18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * TTUSB DVB driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
68c2ecf20Sopenharmony_ci * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/wait.h>
148c2ecf20Sopenharmony_ci#include <linux/fs.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/usb.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/time.h>
198c2ecf20Sopenharmony_ci#include <linux/errno.h>
208c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
218c2ecf20Sopenharmony_ci#include <linux/mutex.h>
228c2ecf20Sopenharmony_ci#include <linux/firmware.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h>
258c2ecf20Sopenharmony_ci#include <media/dmxdev.h>
268c2ecf20Sopenharmony_ci#include <media/dvb_demux.h>
278c2ecf20Sopenharmony_ci#include <media/dvb_net.h>
288c2ecf20Sopenharmony_ci#include "ves1820.h"
298c2ecf20Sopenharmony_ci#include "cx22700.h"
308c2ecf20Sopenharmony_ci#include "tda1004x.h"
318c2ecf20Sopenharmony_ci#include "stv0299.h"
328c2ecf20Sopenharmony_ci#include "tda8083.h"
338c2ecf20Sopenharmony_ci#include "stv0297.h"
348c2ecf20Sopenharmony_ci#include "lnbp21.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h>
378c2ecf20Sopenharmony_ci#include <linux/dvb/dmx.h>
388c2ecf20Sopenharmony_ci#include <linux/pci.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci  TTUSB_HWSECTIONS:
428c2ecf20Sopenharmony_ci    the DSP supports filtering in hardware, however, since the "muxstream"
438c2ecf20Sopenharmony_ci    is a bit braindead (no matching channel masks or no matching filter mask),
448c2ecf20Sopenharmony_ci    we won't support this - yet. it doesn't event support negative filters,
458c2ecf20Sopenharmony_ci    so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just
468c2ecf20Sopenharmony_ci    parse TS data. USB bandwidth will be a problem when having large
478c2ecf20Sopenharmony_ci    datastreams, especially for dvb-net, but hey, that's not my problem.
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci  TTUSB_DISEQC, TTUSB_TONE:
508c2ecf20Sopenharmony_ci    let the STC do the diseqc/tone stuff. this isn't supported at least with
518c2ecf20Sopenharmony_ci    my TTUSB, so let it undef'd unless you want to implement another
528c2ecf20Sopenharmony_ci    frontend. never tested.
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci  debug:
558c2ecf20Sopenharmony_ci    define it to > 3 for really hardcore debugging. you probably don't want
568c2ecf20Sopenharmony_ci    this unless the device doesn't load at all. > 2 for bandwidth statistics.
578c2ecf20Sopenharmony_ci*/
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int debug;
608c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do {					\
668c2ecf20Sopenharmony_ci	if (debug)							\
678c2ecf20Sopenharmony_ci		printk(KERN_DEBUG pr_fmt("%s: " fmt),			\
688c2ecf20Sopenharmony_ci		       __func__, ##arg);				\
698c2ecf20Sopenharmony_ci} while (0)
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#define ISO_BUF_COUNT      4
738c2ecf20Sopenharmony_ci#define FRAMES_PER_ISO_BUF 4
748c2ecf20Sopenharmony_ci#define ISO_FRAME_SIZE     912
758c2ecf20Sopenharmony_ci#define TTUSB_MAXCHANNEL   32
768c2ecf20Sopenharmony_ci#ifdef TTUSB_HWSECTIONS
778c2ecf20Sopenharmony_ci#define TTUSB_MAXFILTER    16	/* ??? */
788c2ecf20Sopenharmony_ci#endif
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#define TTUSB_REV_2_2	0x22
818c2ecf20Sopenharmony_ci#define TTUSB_BUDGET_NAME "ttusb_stc_fw"
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define MAX_SEND	0x28
848c2ecf20Sopenharmony_ci#define MAX_RCV		0x20
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/*
878c2ecf20Sopenharmony_ci *  since we're casting (struct ttusb*) <-> (struct dvb_demux*) around
888c2ecf20Sopenharmony_ci *  the dvb_demux field must be the first in struct!!
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_cistruct ttusb {
918c2ecf20Sopenharmony_ci	struct dvb_demux dvb_demux;
928c2ecf20Sopenharmony_ci	struct dmxdev dmxdev;
938c2ecf20Sopenharmony_ci	struct dvb_net dvbnet;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* and one for USB access. */
968c2ecf20Sopenharmony_ci	struct mutex semi2c;
978c2ecf20Sopenharmony_ci	struct mutex semusb;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	struct dvb_adapter adapter;
1008c2ecf20Sopenharmony_ci	struct usb_device *dev;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	struct i2c_adapter i2c_adap;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	int disconnecting;
1058c2ecf20Sopenharmony_ci	int iso_streaming;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	unsigned int bulk_out_pipe;
1088c2ecf20Sopenharmony_ci	unsigned int bulk_in_pipe;
1098c2ecf20Sopenharmony_ci	unsigned int isoc_in_pipe;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	void *iso_buffer;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	struct urb *iso_urb[ISO_BUF_COUNT];
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	int running_feed_count;
1168c2ecf20Sopenharmony_ci	int last_channel;
1178c2ecf20Sopenharmony_ci	int last_filter;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	u8 c;			/* transaction counter, wraps around...  */
1208c2ecf20Sopenharmony_ci	enum fe_sec_tone_mode tone;
1218c2ecf20Sopenharmony_ci	enum fe_sec_voltage voltage;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	int mux_state;		// 0..2 - MuxSyncWord, 3 - nMuxPacks,    4 - muxpack
1248c2ecf20Sopenharmony_ci	u8 mux_npacks;
1258c2ecf20Sopenharmony_ci	u8 muxpack[256 + 8];
1268c2ecf20Sopenharmony_ci	int muxpack_ptr, muxpack_len;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	int insync;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	int cc;			/* MuxCounter - will increment on EVERY MUX PACKET */
1318c2ecf20Sopenharmony_ci	/* (including stuffing. yes. really.) */
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	u8 send_buf[MAX_SEND];
1348c2ecf20Sopenharmony_ci	u8 last_result[MAX_RCV];
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	int revision;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	struct dvb_frontend* fe;
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic int ttusb_cmd(struct ttusb *ttusb, u8 *data, int len, int len_result)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	int actual_len;
1448c2ecf20Sopenharmony_ci	int err;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&ttusb->semusb) < 0)
1478c2ecf20Sopenharmony_ci		return -EAGAIN;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (debug >= 3)
1508c2ecf20Sopenharmony_ci		dprintk("> %*ph\n", len, data);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	memcpy(data, ttusb->send_buf, len);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
1558c2ecf20Sopenharmony_ci			   ttusb->send_buf, len, &actual_len, 1000);
1568c2ecf20Sopenharmony_ci	if (err != 0) {
1578c2ecf20Sopenharmony_ci		dprintk("usb_bulk_msg(send) failed, err == %i!\n", err);
1588c2ecf20Sopenharmony_ci		goto err;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci	if (actual_len != len) {
1618c2ecf20Sopenharmony_ci		err = -EIO;
1628c2ecf20Sopenharmony_ci		dprintk("only wrote %d of %d bytes\n",
1638c2ecf20Sopenharmony_ci			actual_len, len);
1648c2ecf20Sopenharmony_ci		goto err;
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe,
1688c2ecf20Sopenharmony_ci			   ttusb->last_result, MAX_RCV, &actual_len, 1000);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (err != 0) {
1718c2ecf20Sopenharmony_ci		pr_err("cmd xter failed, receive error %d\n", err);
1728c2ecf20Sopenharmony_ci		goto err;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (debug >= 3) {
1768c2ecf20Sopenharmony_ci		actual_len = ttusb->last_result[3] + 4;
1778c2ecf20Sopenharmony_ci		dprintk("< %*ph\n", actual_len, ttusb->last_result);
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (len_result)
1818c2ecf20Sopenharmony_ci		memcpy(ttusb->send_buf, ttusb->last_result, len_result);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cierr:
1848c2ecf20Sopenharmony_ci	mutex_unlock(&ttusb->semusb);
1858c2ecf20Sopenharmony_ci	return err;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int ttusb_i2c_msg(struct ttusb *ttusb,
1898c2ecf20Sopenharmony_ci		  u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf,
1908c2ecf20Sopenharmony_ci		  u8 rcv_len)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	u8 b[MAX_SEND];
1938c2ecf20Sopenharmony_ci	u8 id = ++ttusb->c;
1948c2ecf20Sopenharmony_ci	int i, err;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (snd_len > MAX_SEND - 7 || rcv_len > MAX_RCV - 7)
1978c2ecf20Sopenharmony_ci		return -EINVAL;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	b[0] = 0xaa;
2008c2ecf20Sopenharmony_ci	b[1] = id;
2018c2ecf20Sopenharmony_ci	b[2] = 0x31;
2028c2ecf20Sopenharmony_ci	b[3] = snd_len + 3;
2038c2ecf20Sopenharmony_ci	b[4] = addr << 1;
2048c2ecf20Sopenharmony_ci	b[5] = snd_len;
2058c2ecf20Sopenharmony_ci	b[6] = rcv_len;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	for (i = 0; i < snd_len; i++)
2088c2ecf20Sopenharmony_ci		b[7 + i] = snd_buf[i];
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	err = ttusb_cmd(ttusb, b, snd_len + 7, MAX_RCV);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (err)
2138c2ecf20Sopenharmony_ci		return -EREMOTEIO;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* check if the i2c transaction was successful */
2168c2ecf20Sopenharmony_ci	if ((snd_len != b[5]) || (rcv_len != b[6])) return -EREMOTEIO;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (rcv_len > 0) {
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci		if (err || b[0] != 0x55 || b[1] != id) {
2218c2ecf20Sopenharmony_ci			dprintk("usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ",
2228c2ecf20Sopenharmony_ci				err, id);
2238c2ecf20Sopenharmony_ci			return -EREMOTEIO;
2248c2ecf20Sopenharmony_ci		}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci		for (i = 0; i < rcv_len; i++)
2278c2ecf20Sopenharmony_ci			rcv_buf[i] = b[7 + i];
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	return rcv_len;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct ttusb *ttusb = i2c_get_adapdata(adapter);
2368c2ecf20Sopenharmony_ci	int i = 0;
2378c2ecf20Sopenharmony_ci	int inc;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&ttusb->semi2c) < 0)
2408c2ecf20Sopenharmony_ci		return -EAGAIN;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	while (i < num) {
2438c2ecf20Sopenharmony_ci		u8 addr, snd_len, rcv_len, *snd_buf, *rcv_buf;
2448c2ecf20Sopenharmony_ci		int err;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		if (num > i + 1 && (msg[i + 1].flags & I2C_M_RD)) {
2478c2ecf20Sopenharmony_ci			addr = msg[i].addr;
2488c2ecf20Sopenharmony_ci			snd_buf = msg[i].buf;
2498c2ecf20Sopenharmony_ci			snd_len = msg[i].len;
2508c2ecf20Sopenharmony_ci			rcv_buf = msg[i + 1].buf;
2518c2ecf20Sopenharmony_ci			rcv_len = msg[i + 1].len;
2528c2ecf20Sopenharmony_ci			inc = 2;
2538c2ecf20Sopenharmony_ci		} else {
2548c2ecf20Sopenharmony_ci			addr = msg[i].addr;
2558c2ecf20Sopenharmony_ci			snd_buf = msg[i].buf;
2568c2ecf20Sopenharmony_ci			snd_len = msg[i].len;
2578c2ecf20Sopenharmony_ci			rcv_buf = NULL;
2588c2ecf20Sopenharmony_ci			rcv_len = 0;
2598c2ecf20Sopenharmony_ci			inc = 1;
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		err = ttusb_i2c_msg(ttusb, addr,
2638c2ecf20Sopenharmony_ci				    snd_buf, snd_len, rcv_buf, rcv_len);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		if (err < rcv_len) {
2668c2ecf20Sopenharmony_ci			dprintk("i == %i\n", i);
2678c2ecf20Sopenharmony_ci			break;
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		i += inc;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	mutex_unlock(&ttusb->semi2c);
2748c2ecf20Sopenharmony_ci	return i;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic int ttusb_boot_dsp(struct ttusb *ttusb)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	const struct firmware *fw;
2808c2ecf20Sopenharmony_ci	int i, err;
2818c2ecf20Sopenharmony_ci	u8 b[40];
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	err = request_firmware(&fw, "ttusb-budget/dspbootcode.bin",
2848c2ecf20Sopenharmony_ci			       &ttusb->dev->dev);
2858c2ecf20Sopenharmony_ci	if (err) {
2868c2ecf20Sopenharmony_ci		pr_err("failed to request firmware\n");
2878c2ecf20Sopenharmony_ci		return err;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* BootBlock */
2918c2ecf20Sopenharmony_ci	b[0] = 0xaa;
2928c2ecf20Sopenharmony_ci	b[2] = 0x13;
2938c2ecf20Sopenharmony_ci	b[3] = 28;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* upload dsp code in 32 byte steps (36 didn't work for me ...) */
2968c2ecf20Sopenharmony_ci	/* 32 is max packet size, no messages should be split. */
2978c2ecf20Sopenharmony_ci	for (i = 0; i < fw->size; i += 28) {
2988c2ecf20Sopenharmony_ci		memcpy(&b[4], &fw->data[i], 28);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		b[1] = ++ttusb->c;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		err = ttusb_cmd(ttusb, b, 32, 0);
3038c2ecf20Sopenharmony_ci		if (err)
3048c2ecf20Sopenharmony_ci			goto done;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	/* last block ... */
3088c2ecf20Sopenharmony_ci	b[1] = ++ttusb->c;
3098c2ecf20Sopenharmony_ci	b[2] = 0x13;
3108c2ecf20Sopenharmony_ci	b[3] = 0;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	err = ttusb_cmd(ttusb, b, 4, 0);
3138c2ecf20Sopenharmony_ci	if (err)
3148c2ecf20Sopenharmony_ci		goto done;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/* BootEnd */
3178c2ecf20Sopenharmony_ci	b[1] = ++ttusb->c;
3188c2ecf20Sopenharmony_ci	b[2] = 0x14;
3198c2ecf20Sopenharmony_ci	b[3] = 0;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	err = ttusb_cmd(ttusb, b, 4, 0);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci      done:
3248c2ecf20Sopenharmony_ci	release_firmware(fw);
3258c2ecf20Sopenharmony_ci	if (err) {
3268c2ecf20Sopenharmony_ci		dprintk("usb_bulk_msg() failed, return value %i!\n", err);
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return err;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int ttusb_set_channel(struct ttusb *ttusb, int chan_id, int filter_type,
3338c2ecf20Sopenharmony_ci		      int pid)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	int err;
3368c2ecf20Sopenharmony_ci	/* SetChannel */
3378c2ecf20Sopenharmony_ci	u8 b[] = { 0xaa, ++ttusb->c, 0x22, 4, chan_id, filter_type,
3388c2ecf20Sopenharmony_ci		(pid >> 8) & 0xff, pid & 0xff
3398c2ecf20Sopenharmony_ci	};
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
3428c2ecf20Sopenharmony_ci	return err;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int ttusb_del_channel(struct ttusb *ttusb, int channel_id)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	int err;
3488c2ecf20Sopenharmony_ci	/* DelChannel */
3498c2ecf20Sopenharmony_ci	u8 b[] = { 0xaa, ++ttusb->c, 0x23, 1, channel_id };
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
3528c2ecf20Sopenharmony_ci	return err;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci#ifdef TTUSB_HWSECTIONS
3568c2ecf20Sopenharmony_cistatic int ttusb_set_filter(struct ttusb *ttusb, int filter_id,
3578c2ecf20Sopenharmony_ci		     int associated_chan, u8 filter[8], u8 mask[8])
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	int err;
3608c2ecf20Sopenharmony_ci	/* SetFilter */
3618c2ecf20Sopenharmony_ci	u8 b[] = { 0xaa, 0, 0x24, 0x1a, filter_id, associated_chan,
3628c2ecf20Sopenharmony_ci		filter[0], filter[1], filter[2], filter[3],
3638c2ecf20Sopenharmony_ci		filter[4], filter[5], filter[6], filter[7],
3648c2ecf20Sopenharmony_ci		filter[8], filter[9], filter[10], filter[11],
3658c2ecf20Sopenharmony_ci		mask[0], mask[1], mask[2], mask[3],
3668c2ecf20Sopenharmony_ci		mask[4], mask[5], mask[6], mask[7],
3678c2ecf20Sopenharmony_ci		mask[8], mask[9], mask[10], mask[11]
3688c2ecf20Sopenharmony_ci	};
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
3718c2ecf20Sopenharmony_ci	return err;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic int ttusb_del_filter(struct ttusb *ttusb, int filter_id)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	int err;
3778c2ecf20Sopenharmony_ci	/* DelFilter */
3788c2ecf20Sopenharmony_ci	u8 b[] = { 0xaa, ++ttusb->c, 0x25, 1, filter_id };
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
3818c2ecf20Sopenharmony_ci	return err;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci#endif
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic int ttusb_init_controller(struct ttusb *ttusb)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	u8 b0[] = { 0xaa, ++ttusb->c, 0x15, 1, 0 };
3888c2ecf20Sopenharmony_ci	u8 b1[] = { 0xaa, ++ttusb->c, 0x15, 1, 1 };
3898c2ecf20Sopenharmony_ci	u8 b2[] = { 0xaa, ++ttusb->c, 0x32, 1, 0 };
3908c2ecf20Sopenharmony_ci	/* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */
3918c2ecf20Sopenharmony_ci	u8 b3[] =
3928c2ecf20Sopenharmony_ci	    { 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e };
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 };
3958c2ecf20Sopenharmony_ci	u8 get_dsp_version[0x20] =
3968c2ecf20Sopenharmony_ci	    { 0xaa, ++ttusb->c, 0x26, 28, 0, 0, 0, 0, 0 };
3978c2ecf20Sopenharmony_ci	int err;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	/* reset board */
4008c2ecf20Sopenharmony_ci	if ((err = ttusb_cmd(ttusb, b0, sizeof(b0), 0)))
4018c2ecf20Sopenharmony_ci		return err;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* reset board (again?) */
4048c2ecf20Sopenharmony_ci	if ((err = ttusb_cmd(ttusb, b1, sizeof(b1), 0)))
4058c2ecf20Sopenharmony_ci		return err;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	ttusb_boot_dsp(ttusb);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* set i2c bit rate */
4108c2ecf20Sopenharmony_ci	if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0)))
4118c2ecf20Sopenharmony_ci		return err;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 0)))
4148c2ecf20Sopenharmony_ci		return err;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if ((err = ttusb_cmd(ttusb, get_version,
4178c2ecf20Sopenharmony_ci			     sizeof(get_version), sizeof(get_version))))
4188c2ecf20Sopenharmony_ci		return err;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	dprintk("stc-version: %c%c%c%c%c\n", get_version[4], get_version[5],
4218c2ecf20Sopenharmony_ci		get_version[6], get_version[7], get_version[8]);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	if (memcmp(get_version + 4, "V 0.0", 5) &&
4248c2ecf20Sopenharmony_ci	    memcmp(get_version + 4, "V 1.1", 5) &&
4258c2ecf20Sopenharmony_ci	    memcmp(get_version + 4, "V 2.1", 5) &&
4268c2ecf20Sopenharmony_ci	    memcmp(get_version + 4, "V 2.2", 5)) {
4278c2ecf20Sopenharmony_ci		pr_err("unknown STC version %c%c%c%c%c, please report!\n",
4288c2ecf20Sopenharmony_ci		       get_version[4], get_version[5],
4298c2ecf20Sopenharmony_ci		       get_version[6], get_version[7], get_version[8]);
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	ttusb->revision = ((get_version[6] - '0') << 4) |
4338c2ecf20Sopenharmony_ci			   (get_version[8] - '0');
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	err =
4368c2ecf20Sopenharmony_ci	    ttusb_cmd(ttusb, get_dsp_version,
4378c2ecf20Sopenharmony_ci		      sizeof(get_dsp_version), sizeof(get_dsp_version));
4388c2ecf20Sopenharmony_ci	if (err)
4398c2ecf20Sopenharmony_ci		return err;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	pr_info("dsp-version: %c%c%c\n",
4428c2ecf20Sopenharmony_ci	       get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]);
4438c2ecf20Sopenharmony_ci	return 0;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci#ifdef TTUSB_DISEQC
4478c2ecf20Sopenharmony_cistatic int ttusb_send_diseqc(struct dvb_frontend* fe,
4488c2ecf20Sopenharmony_ci			     const struct dvb_diseqc_master_cmd *cmd)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
4518c2ecf20Sopenharmony_ci	u8 b[12] = { 0xaa, ++ttusb->c, 0x18 };
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	int err;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	b[3] = 4 + 2 + cmd->msg_len;
4568c2ecf20Sopenharmony_ci	b[4] = 0xFF;		/* send diseqc master, not burst */
4578c2ecf20Sopenharmony_ci	b[5] = cmd->msg_len;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	memcpy(b + 5, cmd->msg, cmd->msg_len);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* Diseqc */
4628c2ecf20Sopenharmony_ci	if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) {
4638c2ecf20Sopenharmony_ci		dprintk("usb_bulk_msg() failed, return value %i!\n", err);
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return err;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci#endif
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic int ttusb_update_lnb(struct ttusb *ttusb)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
4738c2ecf20Sopenharmony_ci		ttusb->voltage == SEC_VOLTAGE_18 ? 0 : 1,
4748c2ecf20Sopenharmony_ci		ttusb->tone == SEC_TONE_ON ? 1 : 0, 1, 1
4758c2ecf20Sopenharmony_ci	};
4768c2ecf20Sopenharmony_ci	int err;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/* SetLNB */
4798c2ecf20Sopenharmony_ci	if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) {
4808c2ecf20Sopenharmony_ci		dprintk("usb_bulk_msg() failed, return value %i!\n", err);
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	return err;
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic int ttusb_set_voltage(struct dvb_frontend *fe,
4878c2ecf20Sopenharmony_ci			     enum fe_sec_voltage voltage)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	ttusb->voltage = voltage;
4928c2ecf20Sopenharmony_ci	return ttusb_update_lnb(ttusb);
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci#ifdef TTUSB_TONE
4968c2ecf20Sopenharmony_cistatic int ttusb_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	ttusb->tone = tone;
5018c2ecf20Sopenharmony_ci	return ttusb_update_lnb(ttusb);
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci#endif
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci#if 0
5078c2ecf20Sopenharmony_cistatic void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	u8 b[] = { 0xaa, ++ttusb->c, 0x19, 1, freq };
5108c2ecf20Sopenharmony_ci	int err, actual_len;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	err = ttusb_cmd(ttusb, b, sizeof(b), 0);
5138c2ecf20Sopenharmony_ci	if (err) {
5148c2ecf20Sopenharmony_ci		dprintk("usb_bulk_msg() failed, return value %i!\n", err);
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci#endif
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/*****************************************************************************/
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci#ifdef TTUSB_HWSECTIONS
5228c2ecf20Sopenharmony_cistatic void ttusb_handle_ts_data(struct ttusb_channel *channel,
5238c2ecf20Sopenharmony_ci				 const u8 * data, int len);
5248c2ecf20Sopenharmony_cistatic void ttusb_handle_sec_data(struct ttusb_channel *channel,
5258c2ecf20Sopenharmony_ci				  const u8 * data, int len);
5268c2ecf20Sopenharmony_ci#endif
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic int numpkt, numts, numstuff, numsec, numinvalid;
5298c2ecf20Sopenharmony_cistatic unsigned long lastj;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
5328c2ecf20Sopenharmony_ci			   int len)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	u16 csum = 0, cc;
5358c2ecf20Sopenharmony_ci	int i;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (len < 4 || len & 0x1) {
5388c2ecf20Sopenharmony_ci		pr_warn("muxpack has invalid len %d\n", len);
5398c2ecf20Sopenharmony_ci		numinvalid++;
5408c2ecf20Sopenharmony_ci		return;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	for (i = 0; i < len; i += 2)
5448c2ecf20Sopenharmony_ci		csum ^= le16_to_cpup((__le16 *) (muxpack + i));
5458c2ecf20Sopenharmony_ci	if (csum) {
5468c2ecf20Sopenharmony_ci		pr_warn("muxpack with incorrect checksum, ignoring\n");
5478c2ecf20Sopenharmony_ci		numinvalid++;
5488c2ecf20Sopenharmony_ci		return;
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	cc = (muxpack[len - 4] << 8) | muxpack[len - 3];
5528c2ecf20Sopenharmony_ci	cc &= 0x7FFF;
5538c2ecf20Sopenharmony_ci	if ((cc != ttusb->cc) && (ttusb->cc != -1))
5548c2ecf20Sopenharmony_ci		pr_warn("cc discontinuity (%d frames missing)\n",
5558c2ecf20Sopenharmony_ci			(cc - ttusb->cc) & 0x7FFF);
5568c2ecf20Sopenharmony_ci	ttusb->cc = (cc + 1) & 0x7FFF;
5578c2ecf20Sopenharmony_ci	if (muxpack[0] & 0x80) {
5588c2ecf20Sopenharmony_ci#ifdef TTUSB_HWSECTIONS
5598c2ecf20Sopenharmony_ci		/* section data */
5608c2ecf20Sopenharmony_ci		int pusi = muxpack[0] & 0x40;
5618c2ecf20Sopenharmony_ci		int channel = muxpack[0] & 0x1F;
5628c2ecf20Sopenharmony_ci		int payload = muxpack[1];
5638c2ecf20Sopenharmony_ci		const u8 *data = muxpack + 2;
5648c2ecf20Sopenharmony_ci		/* check offset flag */
5658c2ecf20Sopenharmony_ci		if (muxpack[0] & 0x20)
5668c2ecf20Sopenharmony_ci			data++;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		ttusb_handle_sec_data(ttusb->channel + channel, data,
5698c2ecf20Sopenharmony_ci				      payload);
5708c2ecf20Sopenharmony_ci		data += payload;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		if ((!!(ttusb->muxpack[0] & 0x20)) ^
5738c2ecf20Sopenharmony_ci		    !!(ttusb->muxpack[1] & 1))
5748c2ecf20Sopenharmony_ci			data++;
5758c2ecf20Sopenharmony_ci#warning TODO: pusi
5768c2ecf20Sopenharmony_ci		dprintk("cc: %04x\n", (data[0] << 8) | data[1]);
5778c2ecf20Sopenharmony_ci#endif
5788c2ecf20Sopenharmony_ci		numsec++;
5798c2ecf20Sopenharmony_ci	} else if (muxpack[0] == 0x47) {
5808c2ecf20Sopenharmony_ci#ifdef TTUSB_HWSECTIONS
5818c2ecf20Sopenharmony_ci		/* we have TS data here! */
5828c2ecf20Sopenharmony_ci		int pid = ((muxpack[1] & 0x0F) << 8) | muxpack[2];
5838c2ecf20Sopenharmony_ci		int channel;
5848c2ecf20Sopenharmony_ci		for (channel = 0; channel < TTUSB_MAXCHANNEL; ++channel)
5858c2ecf20Sopenharmony_ci			if (ttusb->channel[channel].active
5868c2ecf20Sopenharmony_ci			    && (pid == ttusb->channel[channel].pid))
5878c2ecf20Sopenharmony_ci				ttusb_handle_ts_data(ttusb->channel +
5888c2ecf20Sopenharmony_ci						     channel, muxpack,
5898c2ecf20Sopenharmony_ci						     188);
5908c2ecf20Sopenharmony_ci#endif
5918c2ecf20Sopenharmony_ci		numts++;
5928c2ecf20Sopenharmony_ci		dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1);
5938c2ecf20Sopenharmony_ci	} else if (muxpack[0] != 0) {
5948c2ecf20Sopenharmony_ci		numinvalid++;
5958c2ecf20Sopenharmony_ci		pr_err("illegal muxpack type %02x\n", muxpack[0]);
5968c2ecf20Sopenharmony_ci	} else
5978c2ecf20Sopenharmony_ci		numstuff++;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	int maxwork = 1024;
6038c2ecf20Sopenharmony_ci	while (len) {
6048c2ecf20Sopenharmony_ci		if (!(maxwork--)) {
6058c2ecf20Sopenharmony_ci			pr_err("too much work\n");
6068c2ecf20Sopenharmony_ci			break;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		switch (ttusb->mux_state) {
6108c2ecf20Sopenharmony_ci		case 0:
6118c2ecf20Sopenharmony_ci		case 1:
6128c2ecf20Sopenharmony_ci		case 2:
6138c2ecf20Sopenharmony_ci			len--;
6148c2ecf20Sopenharmony_ci			if (*data++ == 0xAA)
6158c2ecf20Sopenharmony_ci				++ttusb->mux_state;
6168c2ecf20Sopenharmony_ci			else {
6178c2ecf20Sopenharmony_ci				ttusb->mux_state = 0;
6188c2ecf20Sopenharmony_ci				if (ttusb->insync) {
6198c2ecf20Sopenharmony_ci					pr_info("lost sync.\n");
6208c2ecf20Sopenharmony_ci					ttusb->insync = 0;
6218c2ecf20Sopenharmony_ci				}
6228c2ecf20Sopenharmony_ci			}
6238c2ecf20Sopenharmony_ci			break;
6248c2ecf20Sopenharmony_ci		case 3:
6258c2ecf20Sopenharmony_ci			ttusb->insync = 1;
6268c2ecf20Sopenharmony_ci			len--;
6278c2ecf20Sopenharmony_ci			ttusb->mux_npacks = *data++;
6288c2ecf20Sopenharmony_ci			++ttusb->mux_state;
6298c2ecf20Sopenharmony_ci			ttusb->muxpack_ptr = 0;
6308c2ecf20Sopenharmony_ci			/* maximum bytes, until we know the length */
6318c2ecf20Sopenharmony_ci			ttusb->muxpack_len = 2;
6328c2ecf20Sopenharmony_ci			break;
6338c2ecf20Sopenharmony_ci		case 4:
6348c2ecf20Sopenharmony_ci			{
6358c2ecf20Sopenharmony_ci				int avail;
6368c2ecf20Sopenharmony_ci				avail = len;
6378c2ecf20Sopenharmony_ci				if (avail >
6388c2ecf20Sopenharmony_ci				    (ttusb->muxpack_len -
6398c2ecf20Sopenharmony_ci				     ttusb->muxpack_ptr))
6408c2ecf20Sopenharmony_ci					avail =
6418c2ecf20Sopenharmony_ci					    ttusb->muxpack_len -
6428c2ecf20Sopenharmony_ci					    ttusb->muxpack_ptr;
6438c2ecf20Sopenharmony_ci				memcpy(ttusb->muxpack + ttusb->muxpack_ptr,
6448c2ecf20Sopenharmony_ci				       data, avail);
6458c2ecf20Sopenharmony_ci				ttusb->muxpack_ptr += avail;
6468c2ecf20Sopenharmony_ci				BUG_ON(ttusb->muxpack_ptr > 264);
6478c2ecf20Sopenharmony_ci				data += avail;
6488c2ecf20Sopenharmony_ci				len -= avail;
6498c2ecf20Sopenharmony_ci				/* determine length */
6508c2ecf20Sopenharmony_ci				if (ttusb->muxpack_ptr == 2) {
6518c2ecf20Sopenharmony_ci					if (ttusb->muxpack[0] & 0x80) {
6528c2ecf20Sopenharmony_ci						ttusb->muxpack_len =
6538c2ecf20Sopenharmony_ci						    ttusb->muxpack[1] + 2;
6548c2ecf20Sopenharmony_ci						if (ttusb->
6558c2ecf20Sopenharmony_ci						    muxpack[0] & 0x20)
6568c2ecf20Sopenharmony_ci							ttusb->
6578c2ecf20Sopenharmony_ci							    muxpack_len++;
6588c2ecf20Sopenharmony_ci						if ((!!
6598c2ecf20Sopenharmony_ci						     (ttusb->
6608c2ecf20Sopenharmony_ci						      muxpack[0] & 0x20)) ^
6618c2ecf20Sopenharmony_ci						    !!(ttusb->
6628c2ecf20Sopenharmony_ci						       muxpack[1] & 1))
6638c2ecf20Sopenharmony_ci							ttusb->
6648c2ecf20Sopenharmony_ci							    muxpack_len++;
6658c2ecf20Sopenharmony_ci						ttusb->muxpack_len += 4;
6668c2ecf20Sopenharmony_ci					} else if (ttusb->muxpack[0] ==
6678c2ecf20Sopenharmony_ci						   0x47)
6688c2ecf20Sopenharmony_ci						ttusb->muxpack_len =
6698c2ecf20Sopenharmony_ci						    188 + 4;
6708c2ecf20Sopenharmony_ci					else if (ttusb->muxpack[0] == 0x00)
6718c2ecf20Sopenharmony_ci						ttusb->muxpack_len =
6728c2ecf20Sopenharmony_ci						    ttusb->muxpack[1] + 2 +
6738c2ecf20Sopenharmony_ci						    4;
6748c2ecf20Sopenharmony_ci					else {
6758c2ecf20Sopenharmony_ci						dprintk("invalid state: first byte is %x\n",
6768c2ecf20Sopenharmony_ci							ttusb->muxpack[0]);
6778c2ecf20Sopenharmony_ci						ttusb->mux_state = 0;
6788c2ecf20Sopenharmony_ci					}
6798c2ecf20Sopenharmony_ci				}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci			/*
6828c2ecf20Sopenharmony_ci			 * if length is valid and we reached the end:
6838c2ecf20Sopenharmony_ci			 * goto next muxpack
6848c2ecf20Sopenharmony_ci			 */
6858c2ecf20Sopenharmony_ci				if ((ttusb->muxpack_ptr >= 2) &&
6868c2ecf20Sopenharmony_ci				    (ttusb->muxpack_ptr ==
6878c2ecf20Sopenharmony_ci				     ttusb->muxpack_len)) {
6888c2ecf20Sopenharmony_ci					ttusb_process_muxpack(ttusb,
6898c2ecf20Sopenharmony_ci							      ttusb->
6908c2ecf20Sopenharmony_ci							      muxpack,
6918c2ecf20Sopenharmony_ci							      ttusb->
6928c2ecf20Sopenharmony_ci							      muxpack_ptr);
6938c2ecf20Sopenharmony_ci					ttusb->muxpack_ptr = 0;
6948c2ecf20Sopenharmony_ci					/* maximum bytes, until we know the length */
6958c2ecf20Sopenharmony_ci					ttusb->muxpack_len = 2;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci				/*
6988c2ecf20Sopenharmony_ci				 * no muxpacks left?
6998c2ecf20Sopenharmony_ci				 * return to search-sync state
7008c2ecf20Sopenharmony_ci				 */
7018c2ecf20Sopenharmony_ci					if (!ttusb->mux_npacks--) {
7028c2ecf20Sopenharmony_ci						ttusb->mux_state = 0;
7038c2ecf20Sopenharmony_ci						break;
7048c2ecf20Sopenharmony_ci					}
7058c2ecf20Sopenharmony_ci				}
7068c2ecf20Sopenharmony_ci				break;
7078c2ecf20Sopenharmony_ci			}
7088c2ecf20Sopenharmony_ci		default:
7098c2ecf20Sopenharmony_ci			BUG();
7108c2ecf20Sopenharmony_ci			break;
7118c2ecf20Sopenharmony_ci		}
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cistatic void ttusb_iso_irq(struct urb *urb)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	struct ttusb *ttusb = urb->context;
7188c2ecf20Sopenharmony_ci	struct usb_iso_packet_descriptor *d;
7198c2ecf20Sopenharmony_ci	u8 *data;
7208c2ecf20Sopenharmony_ci	int len, i;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	if (!ttusb->iso_streaming)
7238c2ecf20Sopenharmony_ci		return;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	if (!urb->status) {
7268c2ecf20Sopenharmony_ci		for (i = 0; i < urb->number_of_packets; ++i) {
7278c2ecf20Sopenharmony_ci			numpkt++;
7288c2ecf20Sopenharmony_ci			if (time_after_eq(jiffies, lastj + HZ)) {
7298c2ecf20Sopenharmony_ci				dprintk("frames/s: %lu (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n",
7308c2ecf20Sopenharmony_ci					numpkt * HZ / (jiffies - lastj),
7318c2ecf20Sopenharmony_ci					numts, numstuff, numsec, numinvalid,
7328c2ecf20Sopenharmony_ci					numts + numstuff + numsec + numinvalid);
7338c2ecf20Sopenharmony_ci				numts = numstuff = numsec = numinvalid = 0;
7348c2ecf20Sopenharmony_ci				lastj = jiffies;
7358c2ecf20Sopenharmony_ci				numpkt = 0;
7368c2ecf20Sopenharmony_ci			}
7378c2ecf20Sopenharmony_ci			d = &urb->iso_frame_desc[i];
7388c2ecf20Sopenharmony_ci			data = urb->transfer_buffer + d->offset;
7398c2ecf20Sopenharmony_ci			len = d->actual_length;
7408c2ecf20Sopenharmony_ci			d->actual_length = 0;
7418c2ecf20Sopenharmony_ci			d->status = 0;
7428c2ecf20Sopenharmony_ci			ttusb_process_frame(ttusb, data, len);
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci	usb_submit_urb(urb, GFP_ATOMIC);
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic void ttusb_free_iso_urbs(struct ttusb *ttusb)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	int i;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	for (i = 0; i < ISO_BUF_COUNT; i++)
7538c2ecf20Sopenharmony_ci		usb_free_urb(ttusb->iso_urb[i]);
7548c2ecf20Sopenharmony_ci	kfree(ttusb->iso_buffer);
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_cistatic int ttusb_alloc_iso_urbs(struct ttusb *ttusb)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	int i;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	ttusb->iso_buffer = kcalloc(FRAMES_PER_ISO_BUF * ISO_BUF_COUNT,
7628c2ecf20Sopenharmony_ci			ISO_FRAME_SIZE, GFP_KERNEL);
7638c2ecf20Sopenharmony_ci	if (!ttusb->iso_buffer)
7648c2ecf20Sopenharmony_ci		return -ENOMEM;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	for (i = 0; i < ISO_BUF_COUNT; i++) {
7678c2ecf20Sopenharmony_ci		struct urb *urb;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci		if (!
7708c2ecf20Sopenharmony_ci		    (urb =
7718c2ecf20Sopenharmony_ci		     usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) {
7728c2ecf20Sopenharmony_ci			ttusb_free_iso_urbs(ttusb);
7738c2ecf20Sopenharmony_ci			return -ENOMEM;
7748c2ecf20Sopenharmony_ci		}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci		ttusb->iso_urb[i] = urb;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	return 0;
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_cistatic void ttusb_stop_iso_xfer(struct ttusb *ttusb)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	int i;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	for (i = 0; i < ISO_BUF_COUNT; i++)
7878c2ecf20Sopenharmony_ci		usb_kill_urb(ttusb->iso_urb[i]);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	ttusb->iso_streaming = 0;
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic int ttusb_start_iso_xfer(struct ttusb *ttusb)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	int i, j, err, buffer_offset = 0;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	if (ttusb->iso_streaming) {
7978c2ecf20Sopenharmony_ci		pr_err("iso xfer already running!\n");
7988c2ecf20Sopenharmony_ci		return 0;
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	ttusb->cc = -1;
8028c2ecf20Sopenharmony_ci	ttusb->insync = 0;
8038c2ecf20Sopenharmony_ci	ttusb->mux_state = 0;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	for (i = 0; i < ISO_BUF_COUNT; i++) {
8068c2ecf20Sopenharmony_ci		int frame_offset = 0;
8078c2ecf20Sopenharmony_ci		struct urb *urb = ttusb->iso_urb[i];
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci		urb->dev = ttusb->dev;
8108c2ecf20Sopenharmony_ci		urb->context = ttusb;
8118c2ecf20Sopenharmony_ci		urb->complete = ttusb_iso_irq;
8128c2ecf20Sopenharmony_ci		urb->pipe = ttusb->isoc_in_pipe;
8138c2ecf20Sopenharmony_ci		urb->transfer_flags = URB_ISO_ASAP;
8148c2ecf20Sopenharmony_ci		urb->interval = 1;
8158c2ecf20Sopenharmony_ci		urb->number_of_packets = FRAMES_PER_ISO_BUF;
8168c2ecf20Sopenharmony_ci		urb->transfer_buffer_length =
8178c2ecf20Sopenharmony_ci		    ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
8188c2ecf20Sopenharmony_ci		urb->transfer_buffer = ttusb->iso_buffer + buffer_offset;
8198c2ecf20Sopenharmony_ci		buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		for (j = 0; j < FRAMES_PER_ISO_BUF; j++) {
8228c2ecf20Sopenharmony_ci			urb->iso_frame_desc[j].offset = frame_offset;
8238c2ecf20Sopenharmony_ci			urb->iso_frame_desc[j].length = ISO_FRAME_SIZE;
8248c2ecf20Sopenharmony_ci			frame_offset += ISO_FRAME_SIZE;
8258c2ecf20Sopenharmony_ci		}
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	for (i = 0; i < ISO_BUF_COUNT; i++) {
8298c2ecf20Sopenharmony_ci		if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_ATOMIC))) {
8308c2ecf20Sopenharmony_ci			ttusb_stop_iso_xfer(ttusb);
8318c2ecf20Sopenharmony_ci			pr_err("failed urb submission (%i: err = %i)!\n",
8328c2ecf20Sopenharmony_ci			       i, err);
8338c2ecf20Sopenharmony_ci			return err;
8348c2ecf20Sopenharmony_ci		}
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	ttusb->iso_streaming = 1;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	return 0;
8408c2ecf20Sopenharmony_ci}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci#ifdef TTUSB_HWSECTIONS
8438c2ecf20Sopenharmony_cistatic void ttusb_handle_ts_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data,
8448c2ecf20Sopenharmony_ci			  int len)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	dvbdmxfeed->cb.ts(data, len, 0, 0, &dvbdmxfeed->feed.ts, 0);
8478c2ecf20Sopenharmony_ci}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic void ttusb_handle_sec_data(struct dvb_demux_feed *dvbdmxfeed, const u8 * data,
8508c2ecf20Sopenharmony_ci			   int len)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci//      struct dvb_demux_feed *dvbdmxfeed = channel->dvbdmxfeed;
8538c2ecf20Sopenharmony_ci#error TODO: handle ugly stuff
8548c2ecf20Sopenharmony_ci//      dvbdmxfeed->cb.sec(data, len, 0, 0, &dvbdmxfeed->feed.sec, 0);
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci#endif
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
8618c2ecf20Sopenharmony_ci	int feed_type = 1;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	dprintk("ttusb_start_feed\n");
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	switch (dvbdmxfeed->type) {
8668c2ecf20Sopenharmony_ci	case DMX_TYPE_TS:
8678c2ecf20Sopenharmony_ci		break;
8688c2ecf20Sopenharmony_ci	case DMX_TYPE_SEC:
8698c2ecf20Sopenharmony_ci		break;
8708c2ecf20Sopenharmony_ci	default:
8718c2ecf20Sopenharmony_ci		return -EINVAL;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	if (dvbdmxfeed->type == DMX_TYPE_TS) {
8758c2ecf20Sopenharmony_ci		switch (dvbdmxfeed->pes_type) {
8768c2ecf20Sopenharmony_ci		case DMX_PES_VIDEO:
8778c2ecf20Sopenharmony_ci		case DMX_PES_AUDIO:
8788c2ecf20Sopenharmony_ci		case DMX_PES_TELETEXT:
8798c2ecf20Sopenharmony_ci		case DMX_PES_PCR:
8808c2ecf20Sopenharmony_ci		case DMX_PES_OTHER:
8818c2ecf20Sopenharmony_ci			break;
8828c2ecf20Sopenharmony_ci		default:
8838c2ecf20Sopenharmony_ci			return -EINVAL;
8848c2ecf20Sopenharmony_ci		}
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci#ifdef TTUSB_HWSECTIONS
8888c2ecf20Sopenharmony_ci#error TODO: allocate filters
8898c2ecf20Sopenharmony_ci	if (dvbdmxfeed->type == DMX_TYPE_TS) {
8908c2ecf20Sopenharmony_ci		feed_type = 1;
8918c2ecf20Sopenharmony_ci	} else if (dvbdmxfeed->type == DMX_TYPE_SEC) {
8928c2ecf20Sopenharmony_ci		feed_type = 2;
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci#endif
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	ttusb_set_channel(ttusb, dvbdmxfeed->index, feed_type, dvbdmxfeed->pid);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (0 == ttusb->running_feed_count++)
8998c2ecf20Sopenharmony_ci		ttusb_start_iso_xfer(ttusb);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	return 0;
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistatic int ttusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	struct ttusb *ttusb = (struct ttusb *) dvbdmxfeed->demux;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	ttusb_del_channel(ttusb, dvbdmxfeed->index);
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	if (--ttusb->running_feed_count == 0)
9118c2ecf20Sopenharmony_ci		ttusb_stop_iso_xfer(ttusb);
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	return 0;
9148c2ecf20Sopenharmony_ci}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_cistatic int ttusb_setup_interfaces(struct ttusb *ttusb)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	usb_set_interface(ttusb->dev, 1, 1);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1);
9218c2ecf20Sopenharmony_ci	ttusb->bulk_in_pipe = usb_rcvbulkpipe(ttusb->dev, 1);
9228c2ecf20Sopenharmony_ci	ttusb->isoc_in_pipe = usb_rcvisocpipe(ttusb->dev, 2);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	return 0;
9258c2ecf20Sopenharmony_ci}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci#if 0
9288c2ecf20Sopenharmony_cistatic u8 stc_firmware[8192];
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cistatic int stc_open(struct inode *inode, struct file *file)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	struct ttusb *ttusb = file->private_data;
9338c2ecf20Sopenharmony_ci	int addr;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	for (addr = 0; addr < 8192; addr += 16) {
9368c2ecf20Sopenharmony_ci		u8 snd_buf[2] = { addr >> 8, addr & 0xFF };
9378c2ecf20Sopenharmony_ci		ttusb_i2c_msg(ttusb, 0x50, snd_buf, 2, stc_firmware + addr,
9388c2ecf20Sopenharmony_ci			      16);
9398c2ecf20Sopenharmony_ci	}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	return 0;
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_cistatic ssize_t stc_read(struct file *file, char *buf, size_t count,
9458c2ecf20Sopenharmony_ci		 loff_t *offset)
9468c2ecf20Sopenharmony_ci{
9478c2ecf20Sopenharmony_ci	return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192);
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_cistatic int stc_release(struct inode *inode, struct file *file)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	return 0;
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic const struct file_operations stc_fops = {
9568c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
9578c2ecf20Sopenharmony_ci	.read = stc_read,
9588c2ecf20Sopenharmony_ci	.open = stc_open,
9598c2ecf20Sopenharmony_ci	.release = stc_release,
9608c2ecf20Sopenharmony_ci};
9618c2ecf20Sopenharmony_ci#endif
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cistatic u32 functionality(struct i2c_adapter *adapter)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C;
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_cistatic int alps_tdmb7_tuner_set_params(struct dvb_frontend *fe)
9718c2ecf20Sopenharmony_ci{
9728c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
9738c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
9748c2ecf20Sopenharmony_ci	u8 data[4];
9758c2ecf20Sopenharmony_ci	struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) };
9768c2ecf20Sopenharmony_ci	u32 div;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	div = (p->frequency + 36166667) / 166667;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	data[0] = (div >> 8) & 0x7f;
9818c2ecf20Sopenharmony_ci	data[1] = div & 0xff;
9828c2ecf20Sopenharmony_ci	data[2] = ((div >> 10) & 0x60) | 0x85;
9838c2ecf20Sopenharmony_ci	data[3] = p->frequency < 592000000 ? 0x40 : 0x80;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
9868c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
9878c2ecf20Sopenharmony_ci	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
9888c2ecf20Sopenharmony_ci	return 0;
9898c2ecf20Sopenharmony_ci}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_cistatic struct cx22700_config alps_tdmb7_config = {
9928c2ecf20Sopenharmony_ci	.demod_address = 0x43,
9938c2ecf20Sopenharmony_ci};
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_cistatic int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
10028c2ecf20Sopenharmony_ci	static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
10038c2ecf20Sopenharmony_ci	static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
10048c2ecf20Sopenharmony_ci	struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	// setup PLL configuration
10078c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
10088c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
10098c2ecf20Sopenharmony_ci	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
10108c2ecf20Sopenharmony_ci	msleep(1);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	// disable the mc44BC374c (do not check for errors)
10138c2ecf20Sopenharmony_ci	tuner_msg.addr = 0x65;
10148c2ecf20Sopenharmony_ci	tuner_msg.buf = disable_mc44BC374c;
10158c2ecf20Sopenharmony_ci	tuner_msg.len = sizeof(disable_mc44BC374c);
10168c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
10178c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
10188c2ecf20Sopenharmony_ci	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
10198c2ecf20Sopenharmony_ci		i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	return 0;
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
10288c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
10298c2ecf20Sopenharmony_ci	u8 tuner_buf[4];
10308c2ecf20Sopenharmony_ci	struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
10318c2ecf20Sopenharmony_ci	int tuner_frequency = 0;
10328c2ecf20Sopenharmony_ci	u8 band, cp, filter;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	// determine charge pump
10358c2ecf20Sopenharmony_ci	tuner_frequency = p->frequency + 36130000;
10368c2ecf20Sopenharmony_ci	if (tuner_frequency < 87000000) return -EINVAL;
10378c2ecf20Sopenharmony_ci	else if (tuner_frequency < 130000000) cp = 3;
10388c2ecf20Sopenharmony_ci	else if (tuner_frequency < 160000000) cp = 5;
10398c2ecf20Sopenharmony_ci	else if (tuner_frequency < 200000000) cp = 6;
10408c2ecf20Sopenharmony_ci	else if (tuner_frequency < 290000000) cp = 3;
10418c2ecf20Sopenharmony_ci	else if (tuner_frequency < 420000000) cp = 5;
10428c2ecf20Sopenharmony_ci	else if (tuner_frequency < 480000000) cp = 6;
10438c2ecf20Sopenharmony_ci	else if (tuner_frequency < 620000000) cp = 3;
10448c2ecf20Sopenharmony_ci	else if (tuner_frequency < 830000000) cp = 5;
10458c2ecf20Sopenharmony_ci	else if (tuner_frequency < 895000000) cp = 7;
10468c2ecf20Sopenharmony_ci	else return -EINVAL;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	// determine band
10498c2ecf20Sopenharmony_ci	if (p->frequency < 49000000)
10508c2ecf20Sopenharmony_ci		return -EINVAL;
10518c2ecf20Sopenharmony_ci	else if (p->frequency < 159000000)
10528c2ecf20Sopenharmony_ci		band = 1;
10538c2ecf20Sopenharmony_ci	else if (p->frequency < 444000000)
10548c2ecf20Sopenharmony_ci		band = 2;
10558c2ecf20Sopenharmony_ci	else if (p->frequency < 861000000)
10568c2ecf20Sopenharmony_ci		band = 4;
10578c2ecf20Sopenharmony_ci	else return -EINVAL;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	// setup PLL filter
10608c2ecf20Sopenharmony_ci	switch (p->bandwidth_hz) {
10618c2ecf20Sopenharmony_ci	case 6000000:
10628c2ecf20Sopenharmony_ci		tda1004x_writereg(fe, 0x0C, 0);
10638c2ecf20Sopenharmony_ci		filter = 0;
10648c2ecf20Sopenharmony_ci		break;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	case 7000000:
10678c2ecf20Sopenharmony_ci		tda1004x_writereg(fe, 0x0C, 0);
10688c2ecf20Sopenharmony_ci		filter = 0;
10698c2ecf20Sopenharmony_ci		break;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	case 8000000:
10728c2ecf20Sopenharmony_ci		tda1004x_writereg(fe, 0x0C, 0xFF);
10738c2ecf20Sopenharmony_ci		filter = 1;
10748c2ecf20Sopenharmony_ci		break;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	default:
10778c2ecf20Sopenharmony_ci		return -EINVAL;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	// calculate divisor
10818c2ecf20Sopenharmony_ci	// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
10828c2ecf20Sopenharmony_ci	tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	// setup tuner buffer
10858c2ecf20Sopenharmony_ci	tuner_buf[0] = tuner_frequency >> 8;
10868c2ecf20Sopenharmony_ci	tuner_buf[1] = tuner_frequency & 0xff;
10878c2ecf20Sopenharmony_ci	tuner_buf[2] = 0xca;
10888c2ecf20Sopenharmony_ci	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
10918c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
10928c2ecf20Sopenharmony_ci	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1)
10938c2ecf20Sopenharmony_ci		return -EIO;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	msleep(1);
10968c2ecf20Sopenharmony_ci	return 0;
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	return request_firmware(fw, name, &ttusb->dev->dev);
11048c2ecf20Sopenharmony_ci}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_cistatic struct tda1004x_config philips_tdm1316l_config = {
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	.demod_address = 0x8,
11098c2ecf20Sopenharmony_ci	.invert = 1,
11108c2ecf20Sopenharmony_ci	.invert_oclk = 0,
11118c2ecf20Sopenharmony_ci	.request_firmware = philips_tdm1316l_request_firmware,
11128c2ecf20Sopenharmony_ci};
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_cistatic u8 alps_bsbe1_inittab[] = {
11158c2ecf20Sopenharmony_ci	0x01, 0x15,
11168c2ecf20Sopenharmony_ci	0x02, 0x30,
11178c2ecf20Sopenharmony_ci	0x03, 0x00,
11188c2ecf20Sopenharmony_ci	0x04, 0x7d,             /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
11198c2ecf20Sopenharmony_ci	0x05, 0x35,             /* I2CT = 0, SCLT = 1, SDAT = 1 */
11208c2ecf20Sopenharmony_ci	0x06, 0x40,             /* DAC not used, set to high impendance mode */
11218c2ecf20Sopenharmony_ci	0x07, 0x00,             /* DAC LSB */
11228c2ecf20Sopenharmony_ci	0x08, 0x40,             /* DiSEqC off, LNB power on OP2/LOCK pin on */
11238c2ecf20Sopenharmony_ci	0x09, 0x00,             /* FIFO */
11248c2ecf20Sopenharmony_ci	0x0c, 0x51,             /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
11258c2ecf20Sopenharmony_ci	0x0d, 0x82,             /* DC offset compensation = ON, beta_agc1 = 2 */
11268c2ecf20Sopenharmony_ci	0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
11278c2ecf20Sopenharmony_ci	0x10, 0x3f,             // AGC2  0x3d
11288c2ecf20Sopenharmony_ci	0x11, 0x84,
11298c2ecf20Sopenharmony_ci	0x12, 0xb9,
11308c2ecf20Sopenharmony_ci	0x15, 0xc9,             // lock detector threshold
11318c2ecf20Sopenharmony_ci	0x16, 0x00,
11328c2ecf20Sopenharmony_ci	0x17, 0x00,
11338c2ecf20Sopenharmony_ci	0x18, 0x00,
11348c2ecf20Sopenharmony_ci	0x19, 0x00,
11358c2ecf20Sopenharmony_ci	0x1a, 0x00,
11368c2ecf20Sopenharmony_ci	0x1f, 0x50,
11378c2ecf20Sopenharmony_ci	0x20, 0x00,
11388c2ecf20Sopenharmony_ci	0x21, 0x00,
11398c2ecf20Sopenharmony_ci	0x22, 0x00,
11408c2ecf20Sopenharmony_ci	0x23, 0x00,
11418c2ecf20Sopenharmony_ci	0x28, 0x00,             // out imp: normal  out type: parallel FEC mode:0
11428c2ecf20Sopenharmony_ci	0x29, 0x1e,             // 1/2 threshold
11438c2ecf20Sopenharmony_ci	0x2a, 0x14,             // 2/3 threshold
11448c2ecf20Sopenharmony_ci	0x2b, 0x0f,             // 3/4 threshold
11458c2ecf20Sopenharmony_ci	0x2c, 0x09,             // 5/6 threshold
11468c2ecf20Sopenharmony_ci	0x2d, 0x05,             // 7/8 threshold
11478c2ecf20Sopenharmony_ci	0x2e, 0x01,
11488c2ecf20Sopenharmony_ci	0x31, 0x1f,             // test all FECs
11498c2ecf20Sopenharmony_ci	0x32, 0x19,             // viterbi and synchro search
11508c2ecf20Sopenharmony_ci	0x33, 0xfc,             // rs control
11518c2ecf20Sopenharmony_ci	0x34, 0x93,             // error control
11528c2ecf20Sopenharmony_ci	0x0f, 0x92,
11538c2ecf20Sopenharmony_ci	0xff, 0xff
11548c2ecf20Sopenharmony_ci};
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cistatic u8 alps_bsru6_inittab[] = {
11578c2ecf20Sopenharmony_ci	0x01, 0x15,
11588c2ecf20Sopenharmony_ci	0x02, 0x30,
11598c2ecf20Sopenharmony_ci	0x03, 0x00,
11608c2ecf20Sopenharmony_ci	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
11618c2ecf20Sopenharmony_ci	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
11628c2ecf20Sopenharmony_ci	0x06, 0x40,		/* DAC not used, set to high impendance mode */
11638c2ecf20Sopenharmony_ci	0x07, 0x00,		/* DAC LSB */
11648c2ecf20Sopenharmony_ci	0x08, 0x40,		/* DiSEqC off, LNB power on OP2/LOCK pin on */
11658c2ecf20Sopenharmony_ci	0x09, 0x00,		/* FIFO */
11668c2ecf20Sopenharmony_ci	0x0c, 0x51,		/* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
11678c2ecf20Sopenharmony_ci	0x0d, 0x82,		/* DC offset compensation = ON, beta_agc1 = 2 */
11688c2ecf20Sopenharmony_ci	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
11698c2ecf20Sopenharmony_ci	0x10, 0x3f,		// AGC2  0x3d
11708c2ecf20Sopenharmony_ci	0x11, 0x84,
11718c2ecf20Sopenharmony_ci	0x12, 0xb9,
11728c2ecf20Sopenharmony_ci	0x15, 0xc9,		// lock detector threshold
11738c2ecf20Sopenharmony_ci	0x16, 0x00,
11748c2ecf20Sopenharmony_ci	0x17, 0x00,
11758c2ecf20Sopenharmony_ci	0x18, 0x00,
11768c2ecf20Sopenharmony_ci	0x19, 0x00,
11778c2ecf20Sopenharmony_ci	0x1a, 0x00,
11788c2ecf20Sopenharmony_ci	0x1f, 0x50,
11798c2ecf20Sopenharmony_ci	0x20, 0x00,
11808c2ecf20Sopenharmony_ci	0x21, 0x00,
11818c2ecf20Sopenharmony_ci	0x22, 0x00,
11828c2ecf20Sopenharmony_ci	0x23, 0x00,
11838c2ecf20Sopenharmony_ci	0x28, 0x00,		// out imp: normal  out type: parallel FEC mode:0
11848c2ecf20Sopenharmony_ci	0x29, 0x1e,		// 1/2 threshold
11858c2ecf20Sopenharmony_ci	0x2a, 0x14,		// 2/3 threshold
11868c2ecf20Sopenharmony_ci	0x2b, 0x0f,		// 3/4 threshold
11878c2ecf20Sopenharmony_ci	0x2c, 0x09,		// 5/6 threshold
11888c2ecf20Sopenharmony_ci	0x2d, 0x05,		// 7/8 threshold
11898c2ecf20Sopenharmony_ci	0x2e, 0x01,
11908c2ecf20Sopenharmony_ci	0x31, 0x1f,		// test all FECs
11918c2ecf20Sopenharmony_ci	0x32, 0x19,		// viterbi and synchro search
11928c2ecf20Sopenharmony_ci	0x33, 0xfc,		// rs control
11938c2ecf20Sopenharmony_ci	0x34, 0x93,		// error control
11948c2ecf20Sopenharmony_ci	0x0f, 0x52,
11958c2ecf20Sopenharmony_ci	0xff, 0xff
11968c2ecf20Sopenharmony_ci};
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_cistatic int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
11998c2ecf20Sopenharmony_ci{
12008c2ecf20Sopenharmony_ci	u8 aclk = 0;
12018c2ecf20Sopenharmony_ci	u8 bclk = 0;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (srate < 1500000) {
12048c2ecf20Sopenharmony_ci		aclk = 0xb7;
12058c2ecf20Sopenharmony_ci		bclk = 0x47;
12068c2ecf20Sopenharmony_ci	} else if (srate < 3000000) {
12078c2ecf20Sopenharmony_ci		aclk = 0xb7;
12088c2ecf20Sopenharmony_ci		bclk = 0x4b;
12098c2ecf20Sopenharmony_ci	} else if (srate < 7000000) {
12108c2ecf20Sopenharmony_ci		aclk = 0xb7;
12118c2ecf20Sopenharmony_ci		bclk = 0x4f;
12128c2ecf20Sopenharmony_ci	} else if (srate < 14000000) {
12138c2ecf20Sopenharmony_ci		aclk = 0xb7;
12148c2ecf20Sopenharmony_ci		bclk = 0x53;
12158c2ecf20Sopenharmony_ci	} else if (srate < 30000000) {
12168c2ecf20Sopenharmony_ci		aclk = 0xb6;
12178c2ecf20Sopenharmony_ci		bclk = 0x53;
12188c2ecf20Sopenharmony_ci	} else if (srate < 45000000) {
12198c2ecf20Sopenharmony_ci		aclk = 0xb4;
12208c2ecf20Sopenharmony_ci		bclk = 0x51;
12218c2ecf20Sopenharmony_ci	}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	stv0299_writereg(fe, 0x13, aclk);
12248c2ecf20Sopenharmony_ci	stv0299_writereg(fe, 0x14, bclk);
12258c2ecf20Sopenharmony_ci	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
12268c2ecf20Sopenharmony_ci	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
12278c2ecf20Sopenharmony_ci	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	return 0;
12308c2ecf20Sopenharmony_ci}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_cistatic int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
12358c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
12368c2ecf20Sopenharmony_ci	u8 buf[4];
12378c2ecf20Sopenharmony_ci	u32 div;
12388c2ecf20Sopenharmony_ci	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	if ((p->frequency < 950000) || (p->frequency > 2150000))
12418c2ecf20Sopenharmony_ci		return -EINVAL;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	div = (p->frequency + (125 - 1)) / 125;	/* round correctly */
12448c2ecf20Sopenharmony_ci	buf[0] = (div >> 8) & 0x7f;
12458c2ecf20Sopenharmony_ci	buf[1] = div & 0xff;
12468c2ecf20Sopenharmony_ci	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
12478c2ecf20Sopenharmony_ci	buf[3] = 0xC4;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	if (p->frequency > 1530000)
12508c2ecf20Sopenharmony_ci		buf[3] = 0xC0;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	/* BSBE1 wants XCE bit set */
12538c2ecf20Sopenharmony_ci	if (ttusb->revision == TTUSB_REV_2_2)
12548c2ecf20Sopenharmony_ci		buf[3] |= 0x20;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
12578c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
12588c2ecf20Sopenharmony_ci	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
12598c2ecf20Sopenharmony_ci		return -EIO;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	return 0;
12628c2ecf20Sopenharmony_ci}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_cistatic struct stv0299_config alps_stv0299_config = {
12658c2ecf20Sopenharmony_ci	.demod_address = 0x68,
12668c2ecf20Sopenharmony_ci	.inittab = alps_bsru6_inittab,
12678c2ecf20Sopenharmony_ci	.mclk = 88000000UL,
12688c2ecf20Sopenharmony_ci	.invert = 1,
12698c2ecf20Sopenharmony_ci	.skip_reinit = 0,
12708c2ecf20Sopenharmony_ci	.lock_output = STV0299_LOCKOUTPUT_1,
12718c2ecf20Sopenharmony_ci	.volt13_op0_op1 = STV0299_VOLT13_OP1,
12728c2ecf20Sopenharmony_ci	.min_delay_ms = 100,
12738c2ecf20Sopenharmony_ci	.set_symbol_rate = alps_stv0299_set_symbol_rate,
12748c2ecf20Sopenharmony_ci};
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cistatic int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
12798c2ecf20Sopenharmony_ci	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
12808c2ecf20Sopenharmony_ci	u8 buf[4];
12818c2ecf20Sopenharmony_ci	u32 div;
12828c2ecf20Sopenharmony_ci	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	div = p->frequency / 125;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	buf[0] = (div >> 8) & 0x7f;
12878c2ecf20Sopenharmony_ci	buf[1] = div & 0xff;
12888c2ecf20Sopenharmony_ci	buf[2] = 0x8e;
12898c2ecf20Sopenharmony_ci	buf[3] = 0x00;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
12928c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
12938c2ecf20Sopenharmony_ci	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
12948c2ecf20Sopenharmony_ci		return -EIO;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	return 0;
12978c2ecf20Sopenharmony_ci}
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_cistatic struct tda8083_config ttusb_novas_grundig_29504_491_config = {
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	.demod_address = 0x68,
13028c2ecf20Sopenharmony_ci};
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cistatic int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
13078c2ecf20Sopenharmony_ci	struct ttusb* ttusb = fe->dvb->priv;
13088c2ecf20Sopenharmony_ci	u32 div;
13098c2ecf20Sopenharmony_ci	u8 data[4];
13108c2ecf20Sopenharmony_ci	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	div = (p->frequency + 35937500 + 31250) / 62500;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	data[0] = (div >> 8) & 0x7f;
13158c2ecf20Sopenharmony_ci	data[1] = div & 0xff;
13168c2ecf20Sopenharmony_ci	data[2] = 0x85 | ((div >> 10) & 0x60);
13178c2ecf20Sopenharmony_ci	data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
13208c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
13218c2ecf20Sopenharmony_ci	if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
13228c2ecf20Sopenharmony_ci		return -EIO;
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	return 0;
13258c2ecf20Sopenharmony_ci}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_cistatic struct ves1820_config alps_tdbe2_config = {
13298c2ecf20Sopenharmony_ci	.demod_address = 0x09,
13308c2ecf20Sopenharmony_ci	.xin = 57840000UL,
13318c2ecf20Sopenharmony_ci	.invert = 1,
13328c2ecf20Sopenharmony_ci	.selagc = VES1820_SELAGC_SIGNAMPERR,
13338c2ecf20Sopenharmony_ci};
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_cistatic u8 read_pwm(struct ttusb* ttusb)
13368c2ecf20Sopenharmony_ci{
13378c2ecf20Sopenharmony_ci	u8 b = 0xff;
13388c2ecf20Sopenharmony_ci	u8 pwm;
13398c2ecf20Sopenharmony_ci	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
13408c2ecf20Sopenharmony_ci				{ .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
13438c2ecf20Sopenharmony_ci		pwm = 0x48;
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	return pwm;
13468c2ecf20Sopenharmony_ci}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_cistatic int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
13508c2ecf20Sopenharmony_ci{
13518c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
13528c2ecf20Sopenharmony_ci	struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
13538c2ecf20Sopenharmony_ci	u8 tuner_buf[5];
13548c2ecf20Sopenharmony_ci	struct i2c_msg tuner_msg = {.addr = 0x60,
13558c2ecf20Sopenharmony_ci				    .flags = 0,
13568c2ecf20Sopenharmony_ci				    .buf = tuner_buf,
13578c2ecf20Sopenharmony_ci				    .len = sizeof(tuner_buf) };
13588c2ecf20Sopenharmony_ci	int tuner_frequency = 0;
13598c2ecf20Sopenharmony_ci	u8 band, cp, filter;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	// determine charge pump
13628c2ecf20Sopenharmony_ci	tuner_frequency = p->frequency;
13638c2ecf20Sopenharmony_ci	if      (tuner_frequency <  87000000) {return -EINVAL;}
13648c2ecf20Sopenharmony_ci	else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
13658c2ecf20Sopenharmony_ci	else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
13668c2ecf20Sopenharmony_ci	else if (tuner_frequency < 200000000) {cp = 6; band = 1;}
13678c2ecf20Sopenharmony_ci	else if (tuner_frequency < 290000000) {cp = 3; band = 2;}
13688c2ecf20Sopenharmony_ci	else if (tuner_frequency < 420000000) {cp = 5; band = 2;}
13698c2ecf20Sopenharmony_ci	else if (tuner_frequency < 480000000) {cp = 6; band = 2;}
13708c2ecf20Sopenharmony_ci	else if (tuner_frequency < 620000000) {cp = 3; band = 4;}
13718c2ecf20Sopenharmony_ci	else if (tuner_frequency < 830000000) {cp = 5; band = 4;}
13728c2ecf20Sopenharmony_ci	else if (tuner_frequency < 895000000) {cp = 7; band = 4;}
13738c2ecf20Sopenharmony_ci	else {return -EINVAL;}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	// assume PLL filter should always be 8MHz for the moment.
13768c2ecf20Sopenharmony_ci	filter = 1;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	// calculate divisor
13798c2ecf20Sopenharmony_ci	// (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
13808c2ecf20Sopenharmony_ci	tuner_frequency = ((p->frequency + 36125000) / 62500);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	// setup tuner buffer
13838c2ecf20Sopenharmony_ci	tuner_buf[0] = tuner_frequency >> 8;
13848c2ecf20Sopenharmony_ci	tuner_buf[1] = tuner_frequency & 0xff;
13858c2ecf20Sopenharmony_ci	tuner_buf[2] = 0xc8;
13868c2ecf20Sopenharmony_ci	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
13878c2ecf20Sopenharmony_ci	tuner_buf[4] = 0x80;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
13908c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
13918c2ecf20Sopenharmony_ci	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
13928c2ecf20Sopenharmony_ci		pr_err("dvbc_philips_tdm1316l_pll_set Error 1\n");
13938c2ecf20Sopenharmony_ci		return -EIO;
13948c2ecf20Sopenharmony_ci	}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	msleep(50);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
13998c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
14008c2ecf20Sopenharmony_ci	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
14018c2ecf20Sopenharmony_ci		pr_err("dvbc_philips_tdm1316l_pll_set Error 2\n");
14028c2ecf20Sopenharmony_ci		return -EIO;
14038c2ecf20Sopenharmony_ci	}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	msleep(1);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	return 0;
14088c2ecf20Sopenharmony_ci}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_cistatic u8 dvbc_philips_tdm1316l_inittab[] = {
14118c2ecf20Sopenharmony_ci	0x80, 0x21,
14128c2ecf20Sopenharmony_ci	0x80, 0x20,
14138c2ecf20Sopenharmony_ci	0x81, 0x01,
14148c2ecf20Sopenharmony_ci	0x81, 0x00,
14158c2ecf20Sopenharmony_ci	0x00, 0x09,
14168c2ecf20Sopenharmony_ci	0x01, 0x69,
14178c2ecf20Sopenharmony_ci	0x03, 0x00,
14188c2ecf20Sopenharmony_ci	0x04, 0x00,
14198c2ecf20Sopenharmony_ci	0x07, 0x00,
14208c2ecf20Sopenharmony_ci	0x08, 0x00,
14218c2ecf20Sopenharmony_ci	0x20, 0x00,
14228c2ecf20Sopenharmony_ci	0x21, 0x40,
14238c2ecf20Sopenharmony_ci	0x22, 0x00,
14248c2ecf20Sopenharmony_ci	0x23, 0x00,
14258c2ecf20Sopenharmony_ci	0x24, 0x40,
14268c2ecf20Sopenharmony_ci	0x25, 0x88,
14278c2ecf20Sopenharmony_ci	0x30, 0xff,
14288c2ecf20Sopenharmony_ci	0x31, 0x00,
14298c2ecf20Sopenharmony_ci	0x32, 0xff,
14308c2ecf20Sopenharmony_ci	0x33, 0x00,
14318c2ecf20Sopenharmony_ci	0x34, 0x50,
14328c2ecf20Sopenharmony_ci	0x35, 0x7f,
14338c2ecf20Sopenharmony_ci	0x36, 0x00,
14348c2ecf20Sopenharmony_ci	0x37, 0x20,
14358c2ecf20Sopenharmony_ci	0x38, 0x00,
14368c2ecf20Sopenharmony_ci	0x40, 0x1c,
14378c2ecf20Sopenharmony_ci	0x41, 0xff,
14388c2ecf20Sopenharmony_ci	0x42, 0x29,
14398c2ecf20Sopenharmony_ci	0x43, 0x20,
14408c2ecf20Sopenharmony_ci	0x44, 0xff,
14418c2ecf20Sopenharmony_ci	0x45, 0x00,
14428c2ecf20Sopenharmony_ci	0x46, 0x00,
14438c2ecf20Sopenharmony_ci	0x49, 0x04,
14448c2ecf20Sopenharmony_ci	0x4a, 0xff,
14458c2ecf20Sopenharmony_ci	0x4b, 0x7f,
14468c2ecf20Sopenharmony_ci	0x52, 0x30,
14478c2ecf20Sopenharmony_ci	0x55, 0xae,
14488c2ecf20Sopenharmony_ci	0x56, 0x47,
14498c2ecf20Sopenharmony_ci	0x57, 0xe1,
14508c2ecf20Sopenharmony_ci	0x58, 0x3a,
14518c2ecf20Sopenharmony_ci	0x5a, 0x1e,
14528c2ecf20Sopenharmony_ci	0x5b, 0x34,
14538c2ecf20Sopenharmony_ci	0x60, 0x00,
14548c2ecf20Sopenharmony_ci	0x63, 0x00,
14558c2ecf20Sopenharmony_ci	0x64, 0x00,
14568c2ecf20Sopenharmony_ci	0x65, 0x00,
14578c2ecf20Sopenharmony_ci	0x66, 0x00,
14588c2ecf20Sopenharmony_ci	0x67, 0x00,
14598c2ecf20Sopenharmony_ci	0x68, 0x00,
14608c2ecf20Sopenharmony_ci	0x69, 0x00,
14618c2ecf20Sopenharmony_ci	0x6a, 0x02,
14628c2ecf20Sopenharmony_ci	0x6b, 0x00,
14638c2ecf20Sopenharmony_ci	0x70, 0xff,
14648c2ecf20Sopenharmony_ci	0x71, 0x00,
14658c2ecf20Sopenharmony_ci	0x72, 0x00,
14668c2ecf20Sopenharmony_ci	0x73, 0x00,
14678c2ecf20Sopenharmony_ci	0x74, 0x0c,
14688c2ecf20Sopenharmony_ci	0x80, 0x00,
14698c2ecf20Sopenharmony_ci	0x81, 0x00,
14708c2ecf20Sopenharmony_ci	0x82, 0x00,
14718c2ecf20Sopenharmony_ci	0x83, 0x00,
14728c2ecf20Sopenharmony_ci	0x84, 0x04,
14738c2ecf20Sopenharmony_ci	0x85, 0x80,
14748c2ecf20Sopenharmony_ci	0x86, 0x24,
14758c2ecf20Sopenharmony_ci	0x87, 0x78,
14768c2ecf20Sopenharmony_ci	0x88, 0x00,
14778c2ecf20Sopenharmony_ci	0x89, 0x00,
14788c2ecf20Sopenharmony_ci	0x90, 0x01,
14798c2ecf20Sopenharmony_ci	0x91, 0x01,
14808c2ecf20Sopenharmony_ci	0xa0, 0x00,
14818c2ecf20Sopenharmony_ci	0xa1, 0x00,
14828c2ecf20Sopenharmony_ci	0xa2, 0x00,
14838c2ecf20Sopenharmony_ci	0xb0, 0x91,
14848c2ecf20Sopenharmony_ci	0xb1, 0x0b,
14858c2ecf20Sopenharmony_ci	0xc0, 0x4b,
14868c2ecf20Sopenharmony_ci	0xc1, 0x00,
14878c2ecf20Sopenharmony_ci	0xc2, 0x00,
14888c2ecf20Sopenharmony_ci	0xd0, 0x00,
14898c2ecf20Sopenharmony_ci	0xd1, 0x00,
14908c2ecf20Sopenharmony_ci	0xd2, 0x00,
14918c2ecf20Sopenharmony_ci	0xd3, 0x00,
14928c2ecf20Sopenharmony_ci	0xd4, 0x00,
14938c2ecf20Sopenharmony_ci	0xd5, 0x00,
14948c2ecf20Sopenharmony_ci	0xde, 0x00,
14958c2ecf20Sopenharmony_ci	0xdf, 0x00,
14968c2ecf20Sopenharmony_ci	0x61, 0x38,
14978c2ecf20Sopenharmony_ci	0x62, 0x0a,
14988c2ecf20Sopenharmony_ci	0x53, 0x13,
14998c2ecf20Sopenharmony_ci	0x59, 0x08,
15008c2ecf20Sopenharmony_ci	0x55, 0x00,
15018c2ecf20Sopenharmony_ci	0x56, 0x40,
15028c2ecf20Sopenharmony_ci	0x57, 0x08,
15038c2ecf20Sopenharmony_ci	0x58, 0x3d,
15048c2ecf20Sopenharmony_ci	0x88, 0x10,
15058c2ecf20Sopenharmony_ci	0xa0, 0x00,
15068c2ecf20Sopenharmony_ci	0xa0, 0x00,
15078c2ecf20Sopenharmony_ci	0xa0, 0x00,
15088c2ecf20Sopenharmony_ci	0xa0, 0x04,
15098c2ecf20Sopenharmony_ci	0xff, 0xff,
15108c2ecf20Sopenharmony_ci};
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_cistatic struct stv0297_config dvbc_philips_tdm1316l_config = {
15138c2ecf20Sopenharmony_ci	.demod_address = 0x1c,
15148c2ecf20Sopenharmony_ci	.inittab = dvbc_philips_tdm1316l_inittab,
15158c2ecf20Sopenharmony_ci	.invert = 0,
15168c2ecf20Sopenharmony_ci};
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_cistatic void frontend_init(struct ttusb* ttusb)
15198c2ecf20Sopenharmony_ci{
15208c2ecf20Sopenharmony_ci	switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
15218c2ecf20Sopenharmony_ci	case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059))
15228c2ecf20Sopenharmony_ci		// try the stv0299 based first
15238c2ecf20Sopenharmony_ci		ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap);
15248c2ecf20Sopenharmony_ci		if (ttusb->fe != NULL) {
15258c2ecf20Sopenharmony_ci			ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci			if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
15288c2ecf20Sopenharmony_ci				alps_stv0299_config.inittab = alps_bsbe1_inittab;
15298c2ecf20Sopenharmony_ci				dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0);
15308c2ecf20Sopenharmony_ci			} else { // ALPS BSRU6
15318c2ecf20Sopenharmony_ci				ttusb->fe->ops.set_voltage = ttusb_set_voltage;
15328c2ecf20Sopenharmony_ci			}
15338c2ecf20Sopenharmony_ci			break;
15348c2ecf20Sopenharmony_ci		}
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci		// Grundig 29504-491
15378c2ecf20Sopenharmony_ci		ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
15388c2ecf20Sopenharmony_ci		if (ttusb->fe != NULL) {
15398c2ecf20Sopenharmony_ci			ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
15408c2ecf20Sopenharmony_ci			ttusb->fe->ops.set_voltage = ttusb_set_voltage;
15418c2ecf20Sopenharmony_ci			break;
15428c2ecf20Sopenharmony_ci		}
15438c2ecf20Sopenharmony_ci		break;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
15468c2ecf20Sopenharmony_ci		ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
15478c2ecf20Sopenharmony_ci		if (ttusb->fe != NULL) {
15488c2ecf20Sopenharmony_ci			ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
15498c2ecf20Sopenharmony_ci			break;
15508c2ecf20Sopenharmony_ci		}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci		ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
15538c2ecf20Sopenharmony_ci		if (ttusb->fe != NULL) {
15548c2ecf20Sopenharmony_ci			ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
15558c2ecf20Sopenharmony_ci			break;
15568c2ecf20Sopenharmony_ci		}
15578c2ecf20Sopenharmony_ci		break;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
15608c2ecf20Sopenharmony_ci		// try the ALPS TDMB7 first
15618c2ecf20Sopenharmony_ci		ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap);
15628c2ecf20Sopenharmony_ci		if (ttusb->fe != NULL) {
15638c2ecf20Sopenharmony_ci			ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
15648c2ecf20Sopenharmony_ci			break;
15658c2ecf20Sopenharmony_ci		}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci		// Philips td1316
15688c2ecf20Sopenharmony_ci		ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap);
15698c2ecf20Sopenharmony_ci		if (ttusb->fe != NULL) {
15708c2ecf20Sopenharmony_ci			ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
15718c2ecf20Sopenharmony_ci			ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
15728c2ecf20Sopenharmony_ci			break;
15738c2ecf20Sopenharmony_ci		}
15748c2ecf20Sopenharmony_ci		break;
15758c2ecf20Sopenharmony_ci	}
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	if (ttusb->fe == NULL) {
15788c2ecf20Sopenharmony_ci		pr_err("no frontend driver found for device [%04x:%04x]\n",
15798c2ecf20Sopenharmony_ci		       le16_to_cpu(ttusb->dev->descriptor.idVendor),
15808c2ecf20Sopenharmony_ci		       le16_to_cpu(ttusb->dev->descriptor.idProduct));
15818c2ecf20Sopenharmony_ci	} else {
15828c2ecf20Sopenharmony_ci		if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
15838c2ecf20Sopenharmony_ci			pr_err("Frontend registration failed!\n");
15848c2ecf20Sopenharmony_ci			dvb_frontend_detach(ttusb->fe);
15858c2ecf20Sopenharmony_ci			ttusb->fe = NULL;
15868c2ecf20Sopenharmony_ci		}
15878c2ecf20Sopenharmony_ci	}
15888c2ecf20Sopenharmony_ci}
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_cistatic const struct i2c_algorithm ttusb_dec_algo = {
15938c2ecf20Sopenharmony_ci	.master_xfer	= master_xfer,
15948c2ecf20Sopenharmony_ci	.functionality	= functionality,
15958c2ecf20Sopenharmony_ci};
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_cistatic int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
15988c2ecf20Sopenharmony_ci{
15998c2ecf20Sopenharmony_ci	struct usb_device *udev;
16008c2ecf20Sopenharmony_ci	struct ttusb *ttusb;
16018c2ecf20Sopenharmony_ci	int result;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	dprintk("TTUSB DVB connected\n");
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	udev = interface_to_usbdev(intf);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	if (!(ttusb = kzalloc(sizeof(struct ttusb), GFP_KERNEL)))
16108c2ecf20Sopenharmony_ci		return -ENOMEM;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	ttusb->dev = udev;
16138c2ecf20Sopenharmony_ci	ttusb->c = 0;
16148c2ecf20Sopenharmony_ci	ttusb->mux_state = 0;
16158c2ecf20Sopenharmony_ci	mutex_init(&ttusb->semi2c);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	mutex_lock(&ttusb->semi2c);
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	mutex_init(&ttusb->semusb);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	ttusb_setup_interfaces(ttusb);
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	result = ttusb_alloc_iso_urbs(ttusb);
16248c2ecf20Sopenharmony_ci	if (result < 0) {
16258c2ecf20Sopenharmony_ci		dprintk("ttusb_alloc_iso_urbs - failed\n");
16268c2ecf20Sopenharmony_ci		mutex_unlock(&ttusb->semi2c);
16278c2ecf20Sopenharmony_ci		kfree(ttusb);
16288c2ecf20Sopenharmony_ci		return result;
16298c2ecf20Sopenharmony_ci	}
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	if (ttusb_init_controller(ttusb))
16328c2ecf20Sopenharmony_ci		pr_err("ttusb_init_controller: error\n");
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	mutex_unlock(&ttusb->semi2c);
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	result = dvb_register_adapter(&ttusb->adapter,
16378c2ecf20Sopenharmony_ci				      "Technotrend/Hauppauge Nova-USB",
16388c2ecf20Sopenharmony_ci				      THIS_MODULE, &udev->dev, adapter_nr);
16398c2ecf20Sopenharmony_ci	if (result < 0) {
16408c2ecf20Sopenharmony_ci		ttusb_free_iso_urbs(ttusb);
16418c2ecf20Sopenharmony_ci		kfree(ttusb);
16428c2ecf20Sopenharmony_ci		return result;
16438c2ecf20Sopenharmony_ci	}
16448c2ecf20Sopenharmony_ci	ttusb->adapter.priv = ttusb;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	/* i2c */
16478c2ecf20Sopenharmony_ci	memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter));
16488c2ecf20Sopenharmony_ci	strscpy(ttusb->i2c_adap.name, "TTUSB DEC", sizeof(ttusb->i2c_adap.name));
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci	i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	ttusb->i2c_adap.algo              = &ttusb_dec_algo;
16538c2ecf20Sopenharmony_ci	ttusb->i2c_adap.algo_data         = NULL;
16548c2ecf20Sopenharmony_ci	ttusb->i2c_adap.dev.parent	  = &udev->dev;
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	result = i2c_add_adapter(&ttusb->i2c_adap);
16578c2ecf20Sopenharmony_ci	if (result)
16588c2ecf20Sopenharmony_ci		goto err_unregister_adapter;
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux));
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	ttusb->dvb_demux.dmx.capabilities =
16638c2ecf20Sopenharmony_ci	    DMX_TS_FILTERING | DMX_SECTION_FILTERING;
16648c2ecf20Sopenharmony_ci	ttusb->dvb_demux.priv = NULL;
16658c2ecf20Sopenharmony_ci#ifdef TTUSB_HWSECTIONS
16668c2ecf20Sopenharmony_ci	ttusb->dvb_demux.filternum = TTUSB_MAXFILTER;
16678c2ecf20Sopenharmony_ci#else
16688c2ecf20Sopenharmony_ci	ttusb->dvb_demux.filternum = 32;
16698c2ecf20Sopenharmony_ci#endif
16708c2ecf20Sopenharmony_ci	ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL;
16718c2ecf20Sopenharmony_ci	ttusb->dvb_demux.start_feed = ttusb_start_feed;
16728c2ecf20Sopenharmony_ci	ttusb->dvb_demux.stop_feed = ttusb_stop_feed;
16738c2ecf20Sopenharmony_ci	ttusb->dvb_demux.write_to_decoder = NULL;
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	result = dvb_dmx_init(&ttusb->dvb_demux);
16768c2ecf20Sopenharmony_ci	if (result < 0) {
16778c2ecf20Sopenharmony_ci		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
16788c2ecf20Sopenharmony_ci		result = -ENODEV;
16798c2ecf20Sopenharmony_ci		goto err_i2c_del_adapter;
16808c2ecf20Sopenharmony_ci	}
16818c2ecf20Sopenharmony_ci//FIXME dmxdev (nur WAS?)
16828c2ecf20Sopenharmony_ci	ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum;
16838c2ecf20Sopenharmony_ci	ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx;
16848c2ecf20Sopenharmony_ci	ttusb->dmxdev.capabilities = 0;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter);
16878c2ecf20Sopenharmony_ci	if (result < 0) {
16888c2ecf20Sopenharmony_ci		pr_err("dvb_dmxdev_init failed (errno = %d)\n",
16898c2ecf20Sopenharmony_ci		       result);
16908c2ecf20Sopenharmony_ci		result = -ENODEV;
16918c2ecf20Sopenharmony_ci		goto err_release_dmx;
16928c2ecf20Sopenharmony_ci	}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
16958c2ecf20Sopenharmony_ci		pr_err("dvb_net_init failed!\n");
16968c2ecf20Sopenharmony_ci		result = -ENODEV;
16978c2ecf20Sopenharmony_ci		goto err_release_dmxdev;
16988c2ecf20Sopenharmony_ci	}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	usb_set_intfdata(intf, (void *) ttusb);
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	frontend_init(ttusb);
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	return 0;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_cierr_release_dmxdev:
17078c2ecf20Sopenharmony_ci	dvb_dmxdev_release(&ttusb->dmxdev);
17088c2ecf20Sopenharmony_cierr_release_dmx:
17098c2ecf20Sopenharmony_ci	dvb_dmx_release(&ttusb->dvb_demux);
17108c2ecf20Sopenharmony_cierr_i2c_del_adapter:
17118c2ecf20Sopenharmony_ci	i2c_del_adapter(&ttusb->i2c_adap);
17128c2ecf20Sopenharmony_cierr_unregister_adapter:
17138c2ecf20Sopenharmony_ci	dvb_unregister_adapter (&ttusb->adapter);
17148c2ecf20Sopenharmony_ci	ttusb_free_iso_urbs(ttusb);
17158c2ecf20Sopenharmony_ci	kfree(ttusb);
17168c2ecf20Sopenharmony_ci	return result;
17178c2ecf20Sopenharmony_ci}
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_cistatic void ttusb_disconnect(struct usb_interface *intf)
17208c2ecf20Sopenharmony_ci{
17218c2ecf20Sopenharmony_ci	struct ttusb *ttusb = usb_get_intfdata(intf);
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	usb_set_intfdata(intf, NULL);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	ttusb->disconnecting = 1;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	ttusb_stop_iso_xfer(ttusb);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	ttusb->dvb_demux.dmx.close(&ttusb->dvb_demux.dmx);
17308c2ecf20Sopenharmony_ci	dvb_net_release(&ttusb->dvbnet);
17318c2ecf20Sopenharmony_ci	dvb_dmxdev_release(&ttusb->dmxdev);
17328c2ecf20Sopenharmony_ci	dvb_dmx_release(&ttusb->dvb_demux);
17338c2ecf20Sopenharmony_ci	if (ttusb->fe != NULL) {
17348c2ecf20Sopenharmony_ci		dvb_unregister_frontend(ttusb->fe);
17358c2ecf20Sopenharmony_ci		dvb_frontend_detach(ttusb->fe);
17368c2ecf20Sopenharmony_ci	}
17378c2ecf20Sopenharmony_ci	i2c_del_adapter(&ttusb->i2c_adap);
17388c2ecf20Sopenharmony_ci	dvb_unregister_adapter(&ttusb->adapter);
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	ttusb_free_iso_urbs(ttusb);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	kfree(ttusb);
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	dprintk("TTUSB DVB disconnected\n");
17458c2ecf20Sopenharmony_ci}
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_cistatic const struct usb_device_id ttusb_table[] = {
17488c2ecf20Sopenharmony_ci	{USB_DEVICE(0xb48, 0x1003)},
17498c2ecf20Sopenharmony_ci	{USB_DEVICE(0xb48, 0x1004)},
17508c2ecf20Sopenharmony_ci	{USB_DEVICE(0xb48, 0x1005)},
17518c2ecf20Sopenharmony_ci	{}
17528c2ecf20Sopenharmony_ci};
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, ttusb_table);
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_cistatic struct usb_driver ttusb_driver = {
17578c2ecf20Sopenharmony_ci      .name		= "ttusb",
17588c2ecf20Sopenharmony_ci      .probe		= ttusb_probe,
17598c2ecf20Sopenharmony_ci      .disconnect	= ttusb_disconnect,
17608c2ecf20Sopenharmony_ci      .id_table		= ttusb_table,
17618c2ecf20Sopenharmony_ci};
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_cimodule_usb_driver(ttusb_driver);
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
17668c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TTUSB DVB Driver");
17678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
17688c2ecf20Sopenharmony_ciMODULE_FIRMWARE("ttusb-budget/dspbootcode.bin");
1769