162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* DVB USB compliant linux driver for Conexant USB reference design.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * The Conexant reference design I saw on their website was only for analogue
562306a36Sopenharmony_ci * capturing (using the cx25842). The box I took to write this driver (reverse
662306a36Sopenharmony_ci * engineered) is the one labeled Medion MD95700. In addition to the cx25842
762306a36Sopenharmony_ci * for analogue capturing it also has a cx22702 DVB-T demodulator on the main
862306a36Sopenharmony_ci * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Maybe it is a little bit premature to call this driver cxusb, but I assume
1162306a36Sopenharmony_ci * the USB protocol is identical or at least inherited from the reference
1262306a36Sopenharmony_ci * design, so it can be reused for the "analogue-only" device (if it will
1362306a36Sopenharmony_ci * appear at all).
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de)
1762306a36Sopenharmony_ci * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
1862306a36Sopenharmony_ci * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au)
1962306a36Sopenharmony_ci * Copyright (C) 2011, 2017 Maciej S. Szmigiero (mail@maciej.szmigiero.name)
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci#include <media/tuner.h>
2462306a36Sopenharmony_ci#include <linux/delay.h>
2562306a36Sopenharmony_ci#include <linux/device.h>
2662306a36Sopenharmony_ci#include <linux/kernel.h>
2762306a36Sopenharmony_ci#include <linux/slab.h>
2862306a36Sopenharmony_ci#include <linux/string.h>
2962306a36Sopenharmony_ci#include <linux/vmalloc.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "cxusb.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include "cx22702.h"
3462306a36Sopenharmony_ci#include "lgdt330x.h"
3562306a36Sopenharmony_ci#include "mt352.h"
3662306a36Sopenharmony_ci#include "mt352_priv.h"
3762306a36Sopenharmony_ci#include "zl10353.h"
3862306a36Sopenharmony_ci#include "xc2028.h"
3962306a36Sopenharmony_ci#include "tuner-simple.h"
4062306a36Sopenharmony_ci#include "mxl5005s.h"
4162306a36Sopenharmony_ci#include "max2165.h"
4262306a36Sopenharmony_ci#include "dib7000p.h"
4362306a36Sopenharmony_ci#include "dib0070.h"
4462306a36Sopenharmony_ci#include "lgs8gxx.h"
4562306a36Sopenharmony_ci#include "atbm8830.h"
4662306a36Sopenharmony_ci#include "si2168.h"
4762306a36Sopenharmony_ci#include "si2157.h"
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* debug */
5062306a36Sopenharmony_ciint dvb_usb_cxusb_debug;
5162306a36Sopenharmony_cimodule_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
5262306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "set debugging level (see cxusb.h)."
5362306a36Sopenharmony_ci		 DVB_USB_DEBUG_STATUS);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cienum cxusb_table_index {
5862306a36Sopenharmony_ci	MEDION_MD95700,
5962306a36Sopenharmony_ci	DVICO_BLUEBIRD_LG064F_COLD,
6062306a36Sopenharmony_ci	DVICO_BLUEBIRD_LG064F_WARM,
6162306a36Sopenharmony_ci	DVICO_BLUEBIRD_DUAL_1_COLD,
6262306a36Sopenharmony_ci	DVICO_BLUEBIRD_DUAL_1_WARM,
6362306a36Sopenharmony_ci	DVICO_BLUEBIRD_LGZ201_COLD,
6462306a36Sopenharmony_ci	DVICO_BLUEBIRD_LGZ201_WARM,
6562306a36Sopenharmony_ci	DVICO_BLUEBIRD_TH7579_COLD,
6662306a36Sopenharmony_ci	DVICO_BLUEBIRD_TH7579_WARM,
6762306a36Sopenharmony_ci	DIGITALNOW_BLUEBIRD_DUAL_1_COLD,
6862306a36Sopenharmony_ci	DIGITALNOW_BLUEBIRD_DUAL_1_WARM,
6962306a36Sopenharmony_ci	DVICO_BLUEBIRD_DUAL_2_COLD,
7062306a36Sopenharmony_ci	DVICO_BLUEBIRD_DUAL_2_WARM,
7162306a36Sopenharmony_ci	DVICO_BLUEBIRD_DUAL_4,
7262306a36Sopenharmony_ci	DVICO_BLUEBIRD_DVB_T_NANO_2,
7362306a36Sopenharmony_ci	DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM,
7462306a36Sopenharmony_ci	AVERMEDIA_VOLAR_A868R,
7562306a36Sopenharmony_ci	DVICO_BLUEBIRD_DUAL_4_REV_2,
7662306a36Sopenharmony_ci	CONEXANT_D680_DMB,
7762306a36Sopenharmony_ci	MYGICA_D689,
7862306a36Sopenharmony_ci	NR__cxusb_table_index
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic struct usb_device_id cxusb_table[];
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciint cxusb_ctrl_msg(struct dvb_usb_device *d,
8462306a36Sopenharmony_ci		   u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct cxusb_state *st = d->priv;
8762306a36Sopenharmony_ci	int ret;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (1 + wlen > MAX_XFER_SIZE) {
9062306a36Sopenharmony_ci		warn("i2c wr: len=%d is too big!\n", wlen);
9162306a36Sopenharmony_ci		return -EOPNOTSUPP;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (rlen > MAX_XFER_SIZE) {
9562306a36Sopenharmony_ci		warn("i2c rd: len=%d is too big!\n", rlen);
9662306a36Sopenharmony_ci		return -EOPNOTSUPP;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	mutex_lock(&d->data_mutex);
10062306a36Sopenharmony_ci	st->data[0] = cmd;
10162306a36Sopenharmony_ci	memcpy(&st->data[1], wbuf, wlen);
10262306a36Sopenharmony_ci	ret = dvb_usb_generic_rw(d, st->data, 1 + wlen, st->data, rlen, 0);
10362306a36Sopenharmony_ci	if (!ret && rbuf && rlen)
10462306a36Sopenharmony_ci		memcpy(rbuf, st->data, rlen);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	mutex_unlock(&d->data_mutex);
10762306a36Sopenharmony_ci	return ret;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/* GPIO */
11162306a36Sopenharmony_cistatic void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct cxusb_state *st = d->priv;
11462306a36Sopenharmony_ci	u8 o[2], i;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (st->gpio_write_state[GPIO_TUNER] == onoff &&
11762306a36Sopenharmony_ci	    !st->gpio_write_refresh[GPIO_TUNER])
11862306a36Sopenharmony_ci		return;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	o[0] = GPIO_TUNER;
12162306a36Sopenharmony_ci	o[1] = onoff;
12262306a36Sopenharmony_ci	cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (i != 0x01)
12562306a36Sopenharmony_ci		dev_info(&d->udev->dev, "gpio_write failed.\n");
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	st->gpio_write_state[GPIO_TUNER] = onoff;
12862306a36Sopenharmony_ci	st->gpio_write_refresh[GPIO_TUNER] = false;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
13262306a36Sopenharmony_ci				  u8 newval)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	u8 o[2], gpio_state;
13562306a36Sopenharmony_ci	int rc;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	o[0] = 0xff & ~changemask;	/* mask of bits to keep */
13862306a36Sopenharmony_ci	o[1] = newval & changemask;	/* new values for bits  */
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1);
14162306a36Sopenharmony_ci	if (rc < 0 || (gpio_state & changemask) != (newval & changemask))
14262306a36Sopenharmony_ci		dev_info(&d->udev->dev, "bluebird_gpio_write failed.\n");
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return rc < 0 ? rc : gpio_state;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin);
15062306a36Sopenharmony_ci	msleep(5);
15162306a36Sopenharmony_ci	cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
16062306a36Sopenharmony_ci				     u8 addr, int onoff)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	u8  o[2] = {addr, onoff};
16362306a36Sopenharmony_ci	u8  i;
16462306a36Sopenharmony_ci	int rc;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (rc < 0)
16962306a36Sopenharmony_ci		return rc;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (i == 0x01)
17262306a36Sopenharmony_ci		return 0;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	dev_info(&d->udev->dev, "gpio_write failed.\n");
17562306a36Sopenharmony_ci	return -EIO;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/* I2C */
17962306a36Sopenharmony_cistatic int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
18062306a36Sopenharmony_ci			  int num)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
18362306a36Sopenharmony_ci	int ret;
18462306a36Sopenharmony_ci	int i;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
18762306a36Sopenharmony_ci		return -EAGAIN;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
19062306a36Sopenharmony_ci		if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION)
19162306a36Sopenharmony_ci			switch (msg[i].addr) {
19262306a36Sopenharmony_ci			case 0x63:
19362306a36Sopenharmony_ci				cxusb_gpio_tuner(d, 0);
19462306a36Sopenharmony_ci				break;
19562306a36Sopenharmony_ci			default:
19662306a36Sopenharmony_ci				cxusb_gpio_tuner(d, 1);
19762306a36Sopenharmony_ci				break;
19862306a36Sopenharmony_ci			}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		if (msg[i].flags & I2C_M_RD) {
20162306a36Sopenharmony_ci			/* read only */
20262306a36Sopenharmony_ci			u8 obuf[3], ibuf[MAX_XFER_SIZE];
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci			if (1 + msg[i].len > sizeof(ibuf)) {
20562306a36Sopenharmony_ci				warn("i2c rd: len=%d is too big!\n",
20662306a36Sopenharmony_ci				     msg[i].len);
20762306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
20862306a36Sopenharmony_ci				goto unlock;
20962306a36Sopenharmony_ci			}
21062306a36Sopenharmony_ci			obuf[0] = 0;
21162306a36Sopenharmony_ci			obuf[1] = msg[i].len;
21262306a36Sopenharmony_ci			obuf[2] = msg[i].addr;
21362306a36Sopenharmony_ci			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
21462306a36Sopenharmony_ci					   obuf, 3,
21562306a36Sopenharmony_ci					   ibuf, 1 + msg[i].len) < 0) {
21662306a36Sopenharmony_ci				warn("i2c read failed");
21762306a36Sopenharmony_ci				break;
21862306a36Sopenharmony_ci			}
21962306a36Sopenharmony_ci			memcpy(msg[i].buf, &ibuf[1], msg[i].len);
22062306a36Sopenharmony_ci		} else if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD) &&
22162306a36Sopenharmony_ci			   msg[i].addr == msg[i + 1].addr) {
22262306a36Sopenharmony_ci			/* write to then read from same address */
22362306a36Sopenharmony_ci			u8 obuf[MAX_XFER_SIZE], ibuf[MAX_XFER_SIZE];
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci			if (3 + msg[i].len > sizeof(obuf)) {
22662306a36Sopenharmony_ci				warn("i2c wr: len=%d is too big!\n",
22762306a36Sopenharmony_ci				     msg[i].len);
22862306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
22962306a36Sopenharmony_ci				goto unlock;
23062306a36Sopenharmony_ci			}
23162306a36Sopenharmony_ci			if (1 + msg[i + 1].len > sizeof(ibuf)) {
23262306a36Sopenharmony_ci				warn("i2c rd: len=%d is too big!\n",
23362306a36Sopenharmony_ci				     msg[i + 1].len);
23462306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
23562306a36Sopenharmony_ci				goto unlock;
23662306a36Sopenharmony_ci			}
23762306a36Sopenharmony_ci			obuf[0] = msg[i].len;
23862306a36Sopenharmony_ci			obuf[1] = msg[i + 1].len;
23962306a36Sopenharmony_ci			obuf[2] = msg[i].addr;
24062306a36Sopenharmony_ci			memcpy(&obuf[3], msg[i].buf, msg[i].len);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
24362306a36Sopenharmony_ci					   obuf, 3 + msg[i].len,
24462306a36Sopenharmony_ci					   ibuf, 1 + msg[i + 1].len) < 0)
24562306a36Sopenharmony_ci				break;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci			if (ibuf[0] != 0x08)
24862306a36Sopenharmony_ci				dev_info(&d->udev->dev, "i2c read may have failed\n");
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci			memcpy(msg[i + 1].buf, &ibuf[1], msg[i + 1].len);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci			i++;
25362306a36Sopenharmony_ci		} else {
25462306a36Sopenharmony_ci			/* write only */
25562306a36Sopenharmony_ci			u8 obuf[MAX_XFER_SIZE], ibuf;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci			if (2 + msg[i].len > sizeof(obuf)) {
25862306a36Sopenharmony_ci				warn("i2c wr: len=%d is too big!\n",
25962306a36Sopenharmony_ci				     msg[i].len);
26062306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
26162306a36Sopenharmony_ci				goto unlock;
26262306a36Sopenharmony_ci			}
26362306a36Sopenharmony_ci			obuf[0] = msg[i].addr;
26462306a36Sopenharmony_ci			obuf[1] = msg[i].len;
26562306a36Sopenharmony_ci			memcpy(&obuf[2], msg[i].buf, msg[i].len);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci			if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf,
26862306a36Sopenharmony_ci					   2 + msg[i].len, &ibuf, 1) < 0)
26962306a36Sopenharmony_ci				break;
27062306a36Sopenharmony_ci			if (ibuf != 0x08)
27162306a36Sopenharmony_ci				dev_info(&d->udev->dev, "i2c write may have failed\n");
27262306a36Sopenharmony_ci		}
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (i == num)
27662306a36Sopenharmony_ci		ret = num;
27762306a36Sopenharmony_ci	else
27862306a36Sopenharmony_ci		ret = -EREMOTEIO;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ciunlock:
28162306a36Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
28262306a36Sopenharmony_ci	return ret;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic u32 cxusb_i2c_func(struct i2c_adapter *adapter)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic struct i2c_algorithm cxusb_i2c_algo = {
29162306a36Sopenharmony_ci	.master_xfer   = cxusb_i2c_xfer,
29262306a36Sopenharmony_ci	.functionality = cxusb_i2c_func,
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int _cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	u8 b = 0;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	dev_info(&d->udev->dev, "setting power %s\n", onoff ? "ON" : "OFF");
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (onoff)
30262306a36Sopenharmony_ci		return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
30362306a36Sopenharmony_ci	else
30462306a36Sopenharmony_ci		return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	bool is_medion = d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700];
31062306a36Sopenharmony_ci	int ret;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (is_medion && !onoff) {
31362306a36Sopenharmony_ci		struct cxusb_medion_dev *cxdev = d->priv;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		mutex_lock(&cxdev->open_lock);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		if (cxdev->open_type == CXUSB_OPEN_ANALOG) {
31862306a36Sopenharmony_ci			dev_info(&d->udev->dev, "preventing DVB core from setting power OFF while we are in analog mode\n");
31962306a36Sopenharmony_ci			ret = -EBUSY;
32062306a36Sopenharmony_ci			goto ret_unlock;
32162306a36Sopenharmony_ci		}
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	ret = _cxusb_power_ctrl(d, onoff);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciret_unlock:
32762306a36Sopenharmony_ci	if (is_medion && !onoff) {
32862306a36Sopenharmony_ci		struct cxusb_medion_dev *cxdev = d->priv;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		mutex_unlock(&cxdev->open_lock);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return ret;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	int ret;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!onoff)
34162306a36Sopenharmony_ci		return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0);
34262306a36Sopenharmony_ci	if (d->state == DVB_USB_STATE_INIT &&
34362306a36Sopenharmony_ci	    usb_set_interface(d->udev, 0, 0) < 0)
34462306a36Sopenharmony_ci		err("set interface failed");
34562306a36Sopenharmony_ci	do {
34662306a36Sopenharmony_ci		/* Nothing */
34762306a36Sopenharmony_ci	} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
34862306a36Sopenharmony_ci		 !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
34962306a36Sopenharmony_ci		 !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (!ret) {
35262306a36Sopenharmony_ci		/*
35362306a36Sopenharmony_ci		 * FIXME: We don't know why, but we need to configure the
35462306a36Sopenharmony_ci		 * lgdt3303 with the register settings below on resume
35562306a36Sopenharmony_ci		 */
35662306a36Sopenharmony_ci		int i;
35762306a36Sopenharmony_ci		u8 buf;
35862306a36Sopenharmony_ci		static const u8 bufs[] = {
35962306a36Sopenharmony_ci			0x0e, 0x2, 0x00, 0x7f,
36062306a36Sopenharmony_ci			0x0e, 0x2, 0x02, 0xfe,
36162306a36Sopenharmony_ci			0x0e, 0x2, 0x02, 0x01,
36262306a36Sopenharmony_ci			0x0e, 0x2, 0x00, 0x03,
36362306a36Sopenharmony_ci			0x0e, 0x2, 0x0d, 0x40,
36462306a36Sopenharmony_ci			0x0e, 0x2, 0x0e, 0x87,
36562306a36Sopenharmony_ci			0x0e, 0x2, 0x0f, 0x8e,
36662306a36Sopenharmony_ci			0x0e, 0x2, 0x10, 0x01,
36762306a36Sopenharmony_ci			0x0e, 0x2, 0x14, 0xd7,
36862306a36Sopenharmony_ci			0x0e, 0x2, 0x47, 0x88,
36962306a36Sopenharmony_ci		};
37062306a36Sopenharmony_ci		msleep(20);
37162306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(bufs); i += 4 / sizeof(u8)) {
37262306a36Sopenharmony_ci			ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE,
37362306a36Sopenharmony_ci					     bufs + i, 4, &buf, 1);
37462306a36Sopenharmony_ci			if (ret)
37562306a36Sopenharmony_ci				break;
37662306a36Sopenharmony_ci			if (buf != 0x8)
37762306a36Sopenharmony_ci				return -EREMOTEIO;
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	return ret;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	u8 b = 0;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (onoff)
38862306a36Sopenharmony_ci		return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0);
38962306a36Sopenharmony_ci	else
39062306a36Sopenharmony_ci		return 0;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	int rc = 0;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	rc = cxusb_power_ctrl(d, onoff);
39862306a36Sopenharmony_ci	if (!onoff)
39962306a36Sopenharmony_ci		cxusb_nano2_led(d, 0);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	return rc;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	int ret;
40762306a36Sopenharmony_ci	u8  b;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	ret = cxusb_power_ctrl(d, onoff);
41062306a36Sopenharmony_ci	if (!onoff)
41162306a36Sopenharmony_ci		return ret;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	msleep(128);
41462306a36Sopenharmony_ci	cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1);
41562306a36Sopenharmony_ci	msleep(100);
41662306a36Sopenharmony_ci	return ret;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct dvb_usb_device *dvbdev = adap->dev;
42262306a36Sopenharmony_ci	bool is_medion = dvbdev->props.devices[0].warm_ids[0] ==
42362306a36Sopenharmony_ci		&cxusb_table[MEDION_MD95700];
42462306a36Sopenharmony_ci	u8 buf[2] = { 0x03, 0x00 };
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (is_medion && onoff) {
42762306a36Sopenharmony_ci		int ret;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		ret = cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL);
43062306a36Sopenharmony_ci		if (ret != 0)
43162306a36Sopenharmony_ci			return ret;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (onoff)
43562306a36Sopenharmony_ci		cxusb_ctrl_msg(dvbdev, CMD_STREAMING_ON, buf, 2, NULL, 0);
43662306a36Sopenharmony_ci	else
43762306a36Sopenharmony_ci		cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (is_medion && !onoff)
44062306a36Sopenharmony_ci		cxusb_medion_put(dvbdev);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	if (onoff)
44862306a36Sopenharmony_ci		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0);
44962306a36Sopenharmony_ci	else
45062306a36Sopenharmony_ci		cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF,
45162306a36Sopenharmony_ci			       NULL, 0, NULL, 0);
45262306a36Sopenharmony_ci	return 0;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	int       ep = d->props.generic_bulk_ctrl_endpoint;
45862306a36Sopenharmony_ci	const int timeout = 100;
45962306a36Sopenharmony_ci	const int junk_len = 32;
46062306a36Sopenharmony_ci	u8        *junk;
46162306a36Sopenharmony_ci	int       rd_count;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* Discard remaining data in video pipe */
46462306a36Sopenharmony_ci	junk = kmalloc(junk_len, GFP_KERNEL);
46562306a36Sopenharmony_ci	if (!junk)
46662306a36Sopenharmony_ci		return;
46762306a36Sopenharmony_ci	while (1) {
46862306a36Sopenharmony_ci		if (usb_bulk_msg(d->udev,
46962306a36Sopenharmony_ci				 usb_rcvbulkpipe(d->udev, ep),
47062306a36Sopenharmony_ci				 junk, junk_len, &rd_count, timeout) < 0)
47162306a36Sopenharmony_ci			break;
47262306a36Sopenharmony_ci		if (!rd_count)
47362306a36Sopenharmony_ci			break;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci	kfree(junk);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct usb_data_stream_properties *p = &d->props.adapter[0].fe[0].stream;
48162306a36Sopenharmony_ci	const int timeout = 100;
48262306a36Sopenharmony_ci	const int junk_len = p->u.bulk.buffersize;
48362306a36Sopenharmony_ci	u8        *junk;
48462306a36Sopenharmony_ci	int       rd_count;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* Discard remaining data in video pipe */
48762306a36Sopenharmony_ci	junk = kmalloc(junk_len, GFP_KERNEL);
48862306a36Sopenharmony_ci	if (!junk)
48962306a36Sopenharmony_ci		return;
49062306a36Sopenharmony_ci	while (1) {
49162306a36Sopenharmony_ci		if (usb_bulk_msg(d->udev,
49262306a36Sopenharmony_ci				 usb_rcvbulkpipe(d->udev, p->endpoint),
49362306a36Sopenharmony_ci				 junk, junk_len, &rd_count, timeout) < 0)
49462306a36Sopenharmony_ci			break;
49562306a36Sopenharmony_ci		if (!rd_count)
49662306a36Sopenharmony_ci			break;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci	kfree(junk);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int cxusb_d680_dmb_streaming_ctrl(struct dvb_usb_adapter *adap,
50262306a36Sopenharmony_ci					 int onoff)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	if (onoff) {
50562306a36Sopenharmony_ci		u8 buf[2] = { 0x03, 0x00 };
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		cxusb_d680_dmb_drain_video(adap->dev);
50862306a36Sopenharmony_ci		return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON,
50962306a36Sopenharmony_ci				      buf, sizeof(buf), NULL, 0);
51062306a36Sopenharmony_ci	} else {
51162306a36Sopenharmony_ci		int ret = cxusb_ctrl_msg(adap->dev,
51262306a36Sopenharmony_ci					 CMD_STREAMING_OFF, NULL, 0, NULL, 0);
51362306a36Sopenharmony_ci		return ret;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic int cxusb_rc_query(struct dvb_usb_device *d)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	u8 ircode[4];
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4) < 0)
52262306a36Sopenharmony_ci		return 0;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (ircode[2] || ircode[3])
52562306a36Sopenharmony_ci		rc_keydown(d->rc_dev, RC_PROTO_NEC,
52662306a36Sopenharmony_ci			   RC_SCANCODE_NEC(~ircode[2] & 0xff, ircode[3]), 0);
52762306a36Sopenharmony_ci	return 0;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int cxusb_bluebird2_rc_query(struct dvb_usb_device *d)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	u8 ircode[4];
53362306a36Sopenharmony_ci	struct i2c_msg msg = {
53462306a36Sopenharmony_ci		.addr = 0x6b,
53562306a36Sopenharmony_ci		.flags = I2C_M_RD,
53662306a36Sopenharmony_ci		.buf = ircode,
53762306a36Sopenharmony_ci		.len = 4
53862306a36Sopenharmony_ci	};
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
54162306a36Sopenharmony_ci		return 0;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (ircode[1] || ircode[2])
54462306a36Sopenharmony_ci		rc_keydown(d->rc_dev, RC_PROTO_NEC,
54562306a36Sopenharmony_ci			   RC_SCANCODE_NEC(~ircode[1] & 0xff, ircode[2]), 0);
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	u8 ircode[2];
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
55462306a36Sopenharmony_ci		return 0;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (ircode[0] || ircode[1])
55762306a36Sopenharmony_ci		rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN,
55862306a36Sopenharmony_ci			   RC_SCANCODE_RC5(ircode[0], ircode[1]), 0);
55962306a36Sopenharmony_ci	return 0;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic int cxusb_dee1601_demod_init(struct dvb_frontend *fe)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x28 };
56562306a36Sopenharmony_ci	static u8 reset[]          = { RESET,      0x80 };
56662306a36Sopenharmony_ci	static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
56762306a36Sopenharmony_ci	static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0x20 };
56862306a36Sopenharmony_ci	static u8 gpp_ctl_cfg[]    = { GPP_CTL,    0x33 };
56962306a36Sopenharmony_ci	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	mt352_write(fe, clock_config,   sizeof(clock_config));
57262306a36Sopenharmony_ci	udelay(200);
57362306a36Sopenharmony_ci	mt352_write(fe, reset,          sizeof(reset));
57462306a36Sopenharmony_ci	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
57762306a36Sopenharmony_ci	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
57862306a36Sopenharmony_ci	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	return 0;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic int cxusb_mt352_demod_init(struct dvb_frontend *fe)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	/* used in both lgz201 and th7579 */
58662306a36Sopenharmony_ci	static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x29 };
58762306a36Sopenharmony_ci	static u8 reset[]          = { RESET,      0x80 };
58862306a36Sopenharmony_ci	static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
58962306a36Sopenharmony_ci	static u8 agc_cfg[]        = { AGC_TARGET, 0x24, 0x20 };
59062306a36Sopenharmony_ci	static u8 gpp_ctl_cfg[]    = { GPP_CTL,    0x33 };
59162306a36Sopenharmony_ci	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	mt352_write(fe, clock_config,   sizeof(clock_config));
59462306a36Sopenharmony_ci	udelay(200);
59562306a36Sopenharmony_ci	mt352_write(fe, reset,          sizeof(reset));
59662306a36Sopenharmony_ci	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
59962306a36Sopenharmony_ci	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
60062306a36Sopenharmony_ci	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
60162306a36Sopenharmony_ci	return 0;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic struct cx22702_config cxusb_cx22702_config = {
60562306a36Sopenharmony_ci	.demod_address = 0x63,
60662306a36Sopenharmony_ci	.output_mode = CX22702_PARALLEL_OUTPUT,
60762306a36Sopenharmony_ci};
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic struct lgdt330x_config cxusb_lgdt3303_config = {
61062306a36Sopenharmony_ci	.demod_chip    = LGDT3303,
61162306a36Sopenharmony_ci};
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic struct lgdt330x_config cxusb_aver_lgdt3303_config = {
61462306a36Sopenharmony_ci	.demod_chip          = LGDT3303,
61562306a36Sopenharmony_ci	.clock_polarity_flip = 2,
61662306a36Sopenharmony_ci};
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_cistatic struct mt352_config cxusb_dee1601_config = {
61962306a36Sopenharmony_ci	.demod_address = 0x0f,
62062306a36Sopenharmony_ci	.demod_init    = cxusb_dee1601_demod_init,
62162306a36Sopenharmony_ci};
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic struct zl10353_config cxusb_zl10353_dee1601_config = {
62462306a36Sopenharmony_ci	.demod_address = 0x0f,
62562306a36Sopenharmony_ci	.parallel_ts = 1,
62662306a36Sopenharmony_ci};
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic struct mt352_config cxusb_mt352_config = {
62962306a36Sopenharmony_ci	/* used in both lgz201 and th7579 */
63062306a36Sopenharmony_ci	.demod_address = 0x0f,
63162306a36Sopenharmony_ci	.demod_init    = cxusb_mt352_demod_init,
63262306a36Sopenharmony_ci};
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic struct zl10353_config cxusb_zl10353_xc3028_config = {
63562306a36Sopenharmony_ci	.demod_address = 0x0f,
63662306a36Sopenharmony_ci	.if2 = 45600,
63762306a36Sopenharmony_ci	.no_tuner = 1,
63862306a36Sopenharmony_ci	.parallel_ts = 1,
63962306a36Sopenharmony_ci};
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic struct zl10353_config cxusb_zl10353_xc3028_config_no_i2c_gate = {
64262306a36Sopenharmony_ci	.demod_address = 0x0f,
64362306a36Sopenharmony_ci	.if2 = 45600,
64462306a36Sopenharmony_ci	.no_tuner = 1,
64562306a36Sopenharmony_ci	.parallel_ts = 1,
64662306a36Sopenharmony_ci	.disable_i2c_gate_ctrl = 1,
64762306a36Sopenharmony_ci};
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic struct mt352_config cxusb_mt352_xc3028_config = {
65062306a36Sopenharmony_ci	.demod_address = 0x0f,
65162306a36Sopenharmony_ci	.if2 = 4560,
65262306a36Sopenharmony_ci	.no_tuner = 1,
65362306a36Sopenharmony_ci	.demod_init = cxusb_mt352_demod_init,
65462306a36Sopenharmony_ci};
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci/* FIXME: needs tweaking */
65762306a36Sopenharmony_cistatic struct mxl5005s_config aver_a868r_tuner = {
65862306a36Sopenharmony_ci	.i2c_address     = 0x63,
65962306a36Sopenharmony_ci	.if_freq         = 6000000UL,
66062306a36Sopenharmony_ci	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
66162306a36Sopenharmony_ci	.agc_mode        = MXL_SINGLE_AGC,
66262306a36Sopenharmony_ci	.tracking_filter = MXL_TF_C,
66362306a36Sopenharmony_ci	.rssi_enable     = MXL_RSSI_ENABLE,
66462306a36Sopenharmony_ci	.cap_select      = MXL_CAP_SEL_ENABLE,
66562306a36Sopenharmony_ci	.div_out         = MXL_DIV_OUT_4,
66662306a36Sopenharmony_ci	.clock_out       = MXL_CLOCK_OUT_DISABLE,
66762306a36Sopenharmony_ci	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
66862306a36Sopenharmony_ci	.top		 = MXL5005S_TOP_25P2,
66962306a36Sopenharmony_ci	.mod_mode        = MXL_DIGITAL_MODE,
67062306a36Sopenharmony_ci	.if_mode         = MXL_ZERO_IF,
67162306a36Sopenharmony_ci	.AgcMasterByte   = 0x00,
67262306a36Sopenharmony_ci};
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/* FIXME: needs tweaking */
67562306a36Sopenharmony_cistatic struct mxl5005s_config d680_dmb_tuner = {
67662306a36Sopenharmony_ci	.i2c_address     = 0x63,
67762306a36Sopenharmony_ci	.if_freq         = 36125000UL,
67862306a36Sopenharmony_ci	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
67962306a36Sopenharmony_ci	.agc_mode        = MXL_SINGLE_AGC,
68062306a36Sopenharmony_ci	.tracking_filter = MXL_TF_C,
68162306a36Sopenharmony_ci	.rssi_enable     = MXL_RSSI_ENABLE,
68262306a36Sopenharmony_ci	.cap_select      = MXL_CAP_SEL_ENABLE,
68362306a36Sopenharmony_ci	.div_out         = MXL_DIV_OUT_4,
68462306a36Sopenharmony_ci	.clock_out       = MXL_CLOCK_OUT_DISABLE,
68562306a36Sopenharmony_ci	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
68662306a36Sopenharmony_ci	.top		 = MXL5005S_TOP_25P2,
68762306a36Sopenharmony_ci	.mod_mode        = MXL_DIGITAL_MODE,
68862306a36Sopenharmony_ci	.if_mode         = MXL_ZERO_IF,
68962306a36Sopenharmony_ci	.AgcMasterByte   = 0x00,
69062306a36Sopenharmony_ci};
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic struct max2165_config mygica_d689_max2165_cfg = {
69362306a36Sopenharmony_ci	.i2c_address = 0x60,
69462306a36Sopenharmony_ci	.osc_clk = 20
69562306a36Sopenharmony_ci};
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci/* Callbacks for DVB USB */
69862306a36Sopenharmony_cistatic int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	struct dvb_usb_device *dvbdev = adap->dev;
70162306a36Sopenharmony_ci	bool is_medion = dvbdev->props.devices[0].warm_ids[0] ==
70262306a36Sopenharmony_ci		&cxusb_table[MEDION_MD95700];
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
70562306a36Sopenharmony_ci		   &dvbdev->i2c_adap, 0x61,
70662306a36Sopenharmony_ci		   TUNER_PHILIPS_FMD1216ME_MK3);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (is_medion && adap->fe_adap[0].fe)
70962306a36Sopenharmony_ci		/*
71062306a36Sopenharmony_ci		 * make sure that DVB core won't put to sleep (reset, really)
71162306a36Sopenharmony_ci		 * tuner when we might be open in analog mode
71262306a36Sopenharmony_ci		 */
71362306a36Sopenharmony_ci		adap->fe_adap[0].fe->ops.tuner_ops.sleep = NULL;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	return 0;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61,
72162306a36Sopenharmony_ci		   NULL, DVB_PLL_THOMSON_DTT7579);
72262306a36Sopenharmony_ci	return 0;
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61,
72862306a36Sopenharmony_ci		   NULL, DVB_PLL_LG_Z201);
72962306a36Sopenharmony_ci	return 0;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
73562306a36Sopenharmony_ci		   NULL, DVB_PLL_THOMSON_DTT7579);
73662306a36Sopenharmony_ci	return 0;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe,
74262306a36Sopenharmony_ci		   &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF);
74362306a36Sopenharmony_ci	return 0;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int dvico_bluebird_xc2028_callback(void *ptr, int component,
74762306a36Sopenharmony_ci					  int command, int arg)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	struct dvb_usb_adapter *adap = ptr;
75062306a36Sopenharmony_ci	struct dvb_usb_device *d = adap->dev;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	switch (command) {
75362306a36Sopenharmony_ci	case XC2028_TUNER_RESET:
75462306a36Sopenharmony_ci		dev_info(&d->udev->dev, "XC2028_TUNER_RESET %d\n", arg);
75562306a36Sopenharmony_ci		cxusb_bluebird_gpio_pulse(d, 0x01, 1);
75662306a36Sopenharmony_ci		break;
75762306a36Sopenharmony_ci	case XC2028_RESET_CLK:
75862306a36Sopenharmony_ci		dev_info(&d->udev->dev, "XC2028_RESET_CLK %d\n", arg);
75962306a36Sopenharmony_ci		break;
76062306a36Sopenharmony_ci	case XC2028_I2C_FLUSH:
76162306a36Sopenharmony_ci		break;
76262306a36Sopenharmony_ci	default:
76362306a36Sopenharmony_ci		dev_info(&d->udev->dev, "unknown command %d, arg %d\n",
76462306a36Sopenharmony_ci			 command, arg);
76562306a36Sopenharmony_ci		return -EINVAL;
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	return 0;
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	struct dvb_frontend	 *fe;
77462306a36Sopenharmony_ci	struct xc2028_config	  cfg = {
77562306a36Sopenharmony_ci		.i2c_adap  = &adap->dev->i2c_adap,
77662306a36Sopenharmony_ci		.i2c_addr  = 0x61,
77762306a36Sopenharmony_ci	};
77862306a36Sopenharmony_ci	static struct xc2028_ctrl ctl = {
77962306a36Sopenharmony_ci		.fname       = XC2028_DEFAULT_FIRMWARE,
78062306a36Sopenharmony_ci		.max_len     = 64,
78162306a36Sopenharmony_ci		.demod       = XC3028_FE_ZARLINK456,
78262306a36Sopenharmony_ci	};
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	/* FIXME: generalize & move to common area */
78562306a36Sopenharmony_ci	adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg);
78862306a36Sopenharmony_ci	if (!fe || !fe->ops.tuner_ops.set_config)
78962306a36Sopenharmony_ci		return -EIO;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	fe->ops.tuner_ops.set_config(fe, &ctl);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	return 0;
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
79962306a36Sopenharmony_ci		   &adap->dev->i2c_adap, &aver_a868r_tuner);
80062306a36Sopenharmony_ci	return 0;
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	struct dvb_frontend *fe;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
80862306a36Sopenharmony_ci			&adap->dev->i2c_adap, &d680_dmb_tuner);
80962306a36Sopenharmony_ci	return (!fe) ? -EIO : 0;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	struct dvb_frontend *fe;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe,
81762306a36Sopenharmony_ci			&adap->dev->i2c_adap, &mygica_d689_max2165_cfg);
81862306a36Sopenharmony_ci	return (!fe) ? -EIO : 0;
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_cistatic int cxusb_medion_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	struct dvb_usb_adapter *adap = fe->dvb->priv;
82462306a36Sopenharmony_ci	struct dvb_usb_device *dvbdev = adap->dev;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (acquire)
82762306a36Sopenharmony_ci		return cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	cxusb_medion_put(dvbdev);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	return 0;
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_cistatic int cxusb_medion_set_mode(struct dvb_usb_device *dvbdev, bool digital)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	struct cxusb_state *st = dvbdev->priv;
83762306a36Sopenharmony_ci	int ret;
83862306a36Sopenharmony_ci	u8 b;
83962306a36Sopenharmony_ci	unsigned int i;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	/*
84262306a36Sopenharmony_ci	 * switching mode while doing an I2C transaction often causes
84362306a36Sopenharmony_ci	 * the device to crash
84462306a36Sopenharmony_ci	 */
84562306a36Sopenharmony_ci	mutex_lock(&dvbdev->i2c_mutex);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	if (digital) {
84862306a36Sopenharmony_ci		ret = usb_set_interface(dvbdev->udev, 0, 6);
84962306a36Sopenharmony_ci		if (ret != 0) {
85062306a36Sopenharmony_ci			dev_err(&dvbdev->udev->dev,
85162306a36Sopenharmony_ci				"digital interface selection failed (%d)\n",
85262306a36Sopenharmony_ci				ret);
85362306a36Sopenharmony_ci			goto ret_unlock;
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci	} else {
85662306a36Sopenharmony_ci		ret = usb_set_interface(dvbdev->udev, 0, 1);
85762306a36Sopenharmony_ci		if (ret != 0) {
85862306a36Sopenharmony_ci			dev_err(&dvbdev->udev->dev,
85962306a36Sopenharmony_ci				"analog interface selection failed (%d)\n",
86062306a36Sopenharmony_ci				ret);
86162306a36Sopenharmony_ci			goto ret_unlock;
86262306a36Sopenharmony_ci		}
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* pipes need to be cleared after setting interface */
86662306a36Sopenharmony_ci	ret = usb_clear_halt(dvbdev->udev, usb_rcvbulkpipe(dvbdev->udev, 1));
86762306a36Sopenharmony_ci	if (ret != 0)
86862306a36Sopenharmony_ci		dev_warn(&dvbdev->udev->dev,
86962306a36Sopenharmony_ci			 "clear halt on IN pipe failed (%d)\n",
87062306a36Sopenharmony_ci			 ret);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	ret = usb_clear_halt(dvbdev->udev, usb_sndbulkpipe(dvbdev->udev, 1));
87362306a36Sopenharmony_ci	if (ret != 0)
87462306a36Sopenharmony_ci		dev_warn(&dvbdev->udev->dev,
87562306a36Sopenharmony_ci			 "clear halt on OUT pipe failed (%d)\n",
87662306a36Sopenharmony_ci			 ret);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	ret = cxusb_ctrl_msg(dvbdev, digital ? CMD_DIGITAL : CMD_ANALOG,
87962306a36Sopenharmony_ci			     NULL, 0, &b, 1);
88062306a36Sopenharmony_ci	if (ret != 0) {
88162306a36Sopenharmony_ci		dev_err(&dvbdev->udev->dev, "mode switch failed (%d)\n",
88262306a36Sopenharmony_ci			ret);
88362306a36Sopenharmony_ci		goto ret_unlock;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* mode switch seems to reset GPIO states */
88762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(st->gpio_write_refresh); i++)
88862306a36Sopenharmony_ci		st->gpio_write_refresh[i] = true;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ciret_unlock:
89162306a36Sopenharmony_ci	mutex_unlock(&dvbdev->i2c_mutex);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	return ret;
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct dvb_usb_device *dvbdev = adap->dev;
89962306a36Sopenharmony_ci	bool is_medion = dvbdev->props.devices[0].warm_ids[0] ==
90062306a36Sopenharmony_ci		&cxusb_table[MEDION_MD95700];
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (is_medion) {
90362306a36Sopenharmony_ci		int ret;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci		ret = cxusb_medion_set_mode(dvbdev, true);
90662306a36Sopenharmony_ci		if (ret)
90762306a36Sopenharmony_ci			return ret;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config,
91162306a36Sopenharmony_ci					 &dvbdev->i2c_adap);
91262306a36Sopenharmony_ci	if (!adap->fe_adap[0].fe)
91362306a36Sopenharmony_ci		return -EIO;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (is_medion)
91662306a36Sopenharmony_ci		adap->fe_adap[0].fe->ops.ts_bus_ctrl =
91762306a36Sopenharmony_ci			cxusb_medion_fe_ts_bus_ctrl;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	return 0;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	if (usb_set_interface(adap->dev->udev, 0, 7) < 0)
92562306a36Sopenharmony_ci		err("set interface failed");
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach,
93062306a36Sopenharmony_ci					 &cxusb_lgdt3303_config,
93162306a36Sopenharmony_ci					 0x0e,
93262306a36Sopenharmony_ci					 &adap->dev->i2c_adap);
93362306a36Sopenharmony_ci	if (adap->fe_adap[0].fe)
93462306a36Sopenharmony_ci		return 0;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	return -EIO;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(lgdt330x_attach,
94262306a36Sopenharmony_ci					 &cxusb_aver_lgdt3303_config,
94362306a36Sopenharmony_ci					 0x0e,
94462306a36Sopenharmony_ci					 &adap->dev->i2c_adap);
94562306a36Sopenharmony_ci	if (adap->fe_adap[0].fe)
94662306a36Sopenharmony_ci		return 0;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return -EIO;
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	/* used in both lgz201 and th7579 */
95462306a36Sopenharmony_ci	if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
95562306a36Sopenharmony_ci		err("set interface failed");
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config,
96062306a36Sopenharmony_ci					 &adap->dev->i2c_adap);
96162306a36Sopenharmony_ci	if (adap->fe_adap[0].fe)
96262306a36Sopenharmony_ci		return 0;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	return -EIO;
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_cistatic int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
97062306a36Sopenharmony_ci		err("set interface failed");
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config,
97562306a36Sopenharmony_ci					 &adap->dev->i2c_adap);
97662306a36Sopenharmony_ci	if (adap->fe_adap[0].fe)
97762306a36Sopenharmony_ci		return 0;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
98062306a36Sopenharmony_ci					 &cxusb_zl10353_dee1601_config,
98162306a36Sopenharmony_ci					 &adap->dev->i2c_adap);
98262306a36Sopenharmony_ci	if (adap->fe_adap[0].fe)
98362306a36Sopenharmony_ci		return 0;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	return -EIO;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cistatic int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	u8 ircode[4];
99162306a36Sopenharmony_ci	int i;
99262306a36Sopenharmony_ci	struct i2c_msg msg = {
99362306a36Sopenharmony_ci		.addr = 0x6b,
99462306a36Sopenharmony_ci		.flags = I2C_M_RD,
99562306a36Sopenharmony_ci		.buf = ircode,
99662306a36Sopenharmony_ci		.len = 4
99762306a36Sopenharmony_ci	};
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
100062306a36Sopenharmony_ci		err("set interface failed");
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	/* reset the tuner and demodulator */
100562306a36Sopenharmony_ci	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
100662306a36Sopenharmony_ci	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
100762306a36Sopenharmony_ci	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	adap->fe_adap[0].fe =
101062306a36Sopenharmony_ci		dvb_attach(zl10353_attach,
101162306a36Sopenharmony_ci			   &cxusb_zl10353_xc3028_config_no_i2c_gate,
101262306a36Sopenharmony_ci			   &adap->dev->i2c_adap);
101362306a36Sopenharmony_ci	if (!adap->fe_adap[0].fe)
101462306a36Sopenharmony_ci		return -EIO;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	/* try to determine if there is no IR decoder on the I2C bus */
101762306a36Sopenharmony_ci	for (i = 0; adap->dev->props.rc.core.rc_codes && i < 5; i++) {
101862306a36Sopenharmony_ci		msleep(20);
101962306a36Sopenharmony_ci		if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
102062306a36Sopenharmony_ci			goto no_IR;
102162306a36Sopenharmony_ci		if (ircode[0] == 0 && ircode[1] == 0)
102262306a36Sopenharmony_ci			continue;
102362306a36Sopenharmony_ci		if (ircode[2] + ircode[3] != 0xff) {
102462306a36Sopenharmony_cino_IR:
102562306a36Sopenharmony_ci			adap->dev->props.rc.core.rc_codes = NULL;
102662306a36Sopenharmony_ci			info("No IR receiver detected on this device.");
102762306a36Sopenharmony_ci			break;
102862306a36Sopenharmony_ci		}
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	return 0;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic struct dibx000_agc_config dib7070_agc_config = {
103562306a36Sopenharmony_ci	.band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	/*
103862306a36Sopenharmony_ci	 * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5,
103962306a36Sopenharmony_ci	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
104062306a36Sopenharmony_ci	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0
104162306a36Sopenharmony_ci	 */
104262306a36Sopenharmony_ci	.setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) |
104362306a36Sopenharmony_ci		 (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
104462306a36Sopenharmony_ci	.inv_gain = 600,
104562306a36Sopenharmony_ci	.time_stabiliz = 10,
104662306a36Sopenharmony_ci	.alpha_level = 0,
104762306a36Sopenharmony_ci	.thlock = 118,
104862306a36Sopenharmony_ci	.wbd_inv = 0,
104962306a36Sopenharmony_ci	.wbd_ref = 3530,
105062306a36Sopenharmony_ci	.wbd_sel = 1,
105162306a36Sopenharmony_ci	.wbd_alpha = 5,
105262306a36Sopenharmony_ci	.agc1_max = 65535,
105362306a36Sopenharmony_ci	.agc1_min = 0,
105462306a36Sopenharmony_ci	.agc2_max = 65535,
105562306a36Sopenharmony_ci	.agc2_min = 0,
105662306a36Sopenharmony_ci	.agc1_pt1 = 0,
105762306a36Sopenharmony_ci	.agc1_pt2 = 40,
105862306a36Sopenharmony_ci	.agc1_pt3 = 183,
105962306a36Sopenharmony_ci	.agc1_slope1 = 206,
106062306a36Sopenharmony_ci	.agc1_slope2 = 255,
106162306a36Sopenharmony_ci	.agc2_pt1 = 72,
106262306a36Sopenharmony_ci	.agc2_pt2 = 152,
106362306a36Sopenharmony_ci	.agc2_slope1 = 88,
106462306a36Sopenharmony_ci	.agc2_slope2 = 90,
106562306a36Sopenharmony_ci	.alpha_mant = 17,
106662306a36Sopenharmony_ci	.alpha_exp = 27,
106762306a36Sopenharmony_ci	.beta_mant = 23,
106862306a36Sopenharmony_ci	.beta_exp = 51,
106962306a36Sopenharmony_ci	.perform_agc_softsplit = 0,
107062306a36Sopenharmony_ci};
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
107362306a36Sopenharmony_ci	.internal = 60000,
107462306a36Sopenharmony_ci	.sampling = 15000,
107562306a36Sopenharmony_ci	.pll_prediv = 1,
107662306a36Sopenharmony_ci	.pll_ratio = 20,
107762306a36Sopenharmony_ci	.pll_range = 3,
107862306a36Sopenharmony_ci	.pll_reset = 1,
107962306a36Sopenharmony_ci	.pll_bypass = 0,
108062306a36Sopenharmony_ci	.enable_refdiv = 0,
108162306a36Sopenharmony_ci	.bypclk_div = 0,
108262306a36Sopenharmony_ci	.IO_CLK_en_core = 1,
108362306a36Sopenharmony_ci	.ADClkSrc = 1,
108462306a36Sopenharmony_ci	.modulo = 2,
108562306a36Sopenharmony_ci	/* refsel, sel, freq_15k */
108662306a36Sopenharmony_ci	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
108762306a36Sopenharmony_ci	.ifreq = (0 << 25) | 0,
108862306a36Sopenharmony_ci	.timf = 20452225,
108962306a36Sopenharmony_ci	.xtal_hz = 12000000,
109062306a36Sopenharmony_ci};
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic struct dib7000p_config cxusb_dualdig4_rev2_config = {
109362306a36Sopenharmony_ci	.output_mode = OUTMODE_MPEG2_PAR_GATED_CLK,
109462306a36Sopenharmony_ci	.output_mpeg2_in_188_bytes = 1,
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	.agc_config_count = 1,
109762306a36Sopenharmony_ci	.agc = &dib7070_agc_config,
109862306a36Sopenharmony_ci	.bw  = &dib7070_bw_config_12_mhz,
109962306a36Sopenharmony_ci	.tuner_is_baseband = 1,
110062306a36Sopenharmony_ci	.spur_protect = 1,
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	.gpio_dir = 0xfcef,
110362306a36Sopenharmony_ci	.gpio_val = 0x0110,
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	.hostbus_diversity = 1,
110862306a36Sopenharmony_ci};
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistruct dib0700_adapter_state {
111162306a36Sopenharmony_ci	int (*set_param_save)(struct dvb_frontend *fe);
111262306a36Sopenharmony_ci	struct dib7000p_ops dib7000p_ops;
111362306a36Sopenharmony_ci};
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_cistatic int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	struct dib0700_adapter_state *state = adap->priv;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
112062306a36Sopenharmony_ci		err("set interface failed");
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
112762306a36Sopenharmony_ci		return -ENODEV;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
113062306a36Sopenharmony_ci						&cxusb_dualdig4_rev2_config) < 0) {
113162306a36Sopenharmony_ci		pr_warn("Unable to enumerate dib7000p\n");
113262306a36Sopenharmony_ci		return -ENODEV;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap,
113662306a36Sopenharmony_ci						       0x80,
113762306a36Sopenharmony_ci						       &cxusb_dualdig4_rev2_config);
113862306a36Sopenharmony_ci	if (!adap->fe_adap[0].fe)
113962306a36Sopenharmony_ci		return -EIO;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	return 0;
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_cistatic int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
114562306a36Sopenharmony_ci{
114662306a36Sopenharmony_ci	struct dvb_usb_adapter *adap = fe->dvb->priv;
114762306a36Sopenharmony_ci	struct dib0700_adapter_state *state = adap->priv;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	return state->dib7000p_ops.set_gpio(fe, 8, 0, !onoff);
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	return 0;
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic struct dib0070_config dib7070p_dib0070_config = {
115862306a36Sopenharmony_ci	.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
115962306a36Sopenharmony_ci	.reset = dib7070_tuner_reset,
116062306a36Sopenharmony_ci	.sleep = dib7070_tuner_sleep,
116162306a36Sopenharmony_ci	.clock_khz = 12000,
116262306a36Sopenharmony_ci};
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic int dib7070_set_param_override(struct dvb_frontend *fe)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
116762306a36Sopenharmony_ci	struct dvb_usb_adapter *adap = fe->dvb->priv;
116862306a36Sopenharmony_ci	struct dib0700_adapter_state *state = adap->priv;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	u16 offset;
117162306a36Sopenharmony_ci	u8 band = BAND_OF_FREQUENCY(p->frequency / 1000);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	switch (band) {
117462306a36Sopenharmony_ci	case BAND_VHF:
117562306a36Sopenharmony_ci		offset = 950;
117662306a36Sopenharmony_ci		break;
117762306a36Sopenharmony_ci	default:
117862306a36Sopenharmony_ci	case BAND_UHF:
117962306a36Sopenharmony_ci		offset = 550;
118062306a36Sopenharmony_ci		break;
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	return state->set_param_save(fe);
118662306a36Sopenharmony_ci}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_cistatic int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
118962306a36Sopenharmony_ci{
119062306a36Sopenharmony_ci	struct dib0700_adapter_state *st = adap->priv;
119162306a36Sopenharmony_ci	struct i2c_adapter *tun_i2c;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	/*
119462306a36Sopenharmony_ci	 * No need to call dvb7000p_attach here, as it was called
119562306a36Sopenharmony_ci	 * already, as frontend_attach method is called first, and
119662306a36Sopenharmony_ci	 * tuner_attach is only called on success.
119762306a36Sopenharmony_ci	 */
119862306a36Sopenharmony_ci	tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
119962306a36Sopenharmony_ci					DIBX000_I2C_INTERFACE_TUNER, 1);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
120262306a36Sopenharmony_ci		       &dib7070p_dib0070_config) == NULL)
120362306a36Sopenharmony_ci		return -ENODEV;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
120662306a36Sopenharmony_ci	adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7070_set_param_override;
120762306a36Sopenharmony_ci	return 0;
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_cistatic int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
121162306a36Sopenharmony_ci{
121262306a36Sopenharmony_ci	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
121362306a36Sopenharmony_ci		err("set interface failed");
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	/* reset the tuner and demodulator */
121862306a36Sopenharmony_ci	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
121962306a36Sopenharmony_ci	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
122062306a36Sopenharmony_ci	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
122362306a36Sopenharmony_ci					 &cxusb_zl10353_xc3028_config,
122462306a36Sopenharmony_ci					 &adap->dev->i2c_adap);
122562306a36Sopenharmony_ci	if (adap->fe_adap[0].fe)
122662306a36Sopenharmony_ci		return 0;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(mt352_attach,
122962306a36Sopenharmony_ci					 &cxusb_mt352_xc3028_config,
123062306a36Sopenharmony_ci					 &adap->dev->i2c_adap);
123162306a36Sopenharmony_ci	if (adap->fe_adap[0].fe)
123262306a36Sopenharmony_ci		return 0;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	return -EIO;
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_cistatic struct lgs8gxx_config d680_lgs8gl5_cfg = {
123862306a36Sopenharmony_ci	.prod = LGS8GXX_PROD_LGS8GL5,
123962306a36Sopenharmony_ci	.demod_address = 0x19,
124062306a36Sopenharmony_ci	.serial_ts = 0,
124162306a36Sopenharmony_ci	.ts_clk_pol = 0,
124262306a36Sopenharmony_ci	.ts_clk_gated = 1,
124362306a36Sopenharmony_ci	.if_clk_freq = 30400, /* 30.4 MHz */
124462306a36Sopenharmony_ci	.if_freq = 5725, /* 5.725 MHz */
124562306a36Sopenharmony_ci	.if_neg_center = 0,
124662306a36Sopenharmony_ci	.ext_adc = 0,
124762306a36Sopenharmony_ci	.adc_signed = 0,
124862306a36Sopenharmony_ci	.if_neg_edge = 0,
124962306a36Sopenharmony_ci};
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct dvb_usb_device *d = adap->dev;
125462306a36Sopenharmony_ci	int n;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	/* Select required USB configuration */
125762306a36Sopenharmony_ci	if (usb_set_interface(d->udev, 0, 0) < 0)
125862306a36Sopenharmony_ci		err("set interface failed");
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	/* Unblock all USB pipes */
126162306a36Sopenharmony_ci	usb_clear_halt(d->udev,
126262306a36Sopenharmony_ci		       usb_sndbulkpipe(d->udev,
126362306a36Sopenharmony_ci				       d->props.generic_bulk_ctrl_endpoint));
126462306a36Sopenharmony_ci	usb_clear_halt(d->udev,
126562306a36Sopenharmony_ci		       usb_rcvbulkpipe(d->udev,
126662306a36Sopenharmony_ci				       d->props.generic_bulk_ctrl_endpoint));
126762306a36Sopenharmony_ci	usb_clear_halt(d->udev,
126862306a36Sopenharmony_ci		       usb_rcvbulkpipe(d->udev,
126962306a36Sopenharmony_ci				       d->props.adapter[0].fe[0].stream.endpoint));
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	/* Drain USB pipes to avoid hang after reboot */
127262306a36Sopenharmony_ci	for (n = 0;  n < 5;  n++) {
127362306a36Sopenharmony_ci		cxusb_d680_dmb_drain_message(d);
127462306a36Sopenharmony_ci		cxusb_d680_dmb_drain_video(d);
127562306a36Sopenharmony_ci		msleep(200);
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	/* Reset the tuner */
127962306a36Sopenharmony_ci	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
128062306a36Sopenharmony_ci		err("clear tuner gpio failed");
128162306a36Sopenharmony_ci		return -EIO;
128262306a36Sopenharmony_ci	}
128362306a36Sopenharmony_ci	msleep(100);
128462306a36Sopenharmony_ci	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
128562306a36Sopenharmony_ci		err("set tuner gpio failed");
128662306a36Sopenharmony_ci		return -EIO;
128762306a36Sopenharmony_ci	}
128862306a36Sopenharmony_ci	msleep(100);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/* Attach frontend */
129162306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach,
129262306a36Sopenharmony_ci					 &d680_lgs8gl5_cfg, &d->i2c_adap);
129362306a36Sopenharmony_ci	if (!adap->fe_adap[0].fe)
129462306a36Sopenharmony_ci		return -EIO;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	return 0;
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cistatic struct atbm8830_config mygica_d689_atbm8830_cfg = {
130062306a36Sopenharmony_ci	.prod = ATBM8830_PROD_8830,
130162306a36Sopenharmony_ci	.demod_address = 0x40,
130262306a36Sopenharmony_ci	.serial_ts = 0,
130362306a36Sopenharmony_ci	.ts_sampling_edge = 1,
130462306a36Sopenharmony_ci	.ts_clk_gated = 0,
130562306a36Sopenharmony_ci	.osc_clk_freq = 30400, /* in kHz */
130662306a36Sopenharmony_ci	.if_freq = 0, /* zero IF */
130762306a36Sopenharmony_ci	.zif_swap_iq = 1,
130862306a36Sopenharmony_ci	.agc_min = 0x2E,
130962306a36Sopenharmony_ci	.agc_max = 0x90,
131062306a36Sopenharmony_ci	.agc_hold_loop = 0,
131162306a36Sopenharmony_ci};
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_cistatic int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	struct dvb_usb_device *d = adap->dev;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	/* Select required USB configuration */
131862306a36Sopenharmony_ci	if (usb_set_interface(d->udev, 0, 0) < 0)
131962306a36Sopenharmony_ci		err("set interface failed");
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/* Unblock all USB pipes */
132262306a36Sopenharmony_ci	usb_clear_halt(d->udev,
132362306a36Sopenharmony_ci		       usb_sndbulkpipe(d->udev,
132462306a36Sopenharmony_ci				       d->props.generic_bulk_ctrl_endpoint));
132562306a36Sopenharmony_ci	usb_clear_halt(d->udev,
132662306a36Sopenharmony_ci		       usb_rcvbulkpipe(d->udev,
132762306a36Sopenharmony_ci				       d->props.generic_bulk_ctrl_endpoint));
132862306a36Sopenharmony_ci	usb_clear_halt(d->udev,
132962306a36Sopenharmony_ci		       usb_rcvbulkpipe(d->udev,
133062306a36Sopenharmony_ci				       d->props.adapter[0].fe[0].stream.endpoint));
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/* Reset the tuner */
133362306a36Sopenharmony_ci	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
133462306a36Sopenharmony_ci		err("clear tuner gpio failed");
133562306a36Sopenharmony_ci		return -EIO;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci	msleep(100);
133862306a36Sopenharmony_ci	if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
133962306a36Sopenharmony_ci		err("set tuner gpio failed");
134062306a36Sopenharmony_ci		return -EIO;
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci	msleep(100);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	/* Attach frontend */
134562306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(atbm8830_attach,
134662306a36Sopenharmony_ci					 &mygica_d689_atbm8830_cfg,
134762306a36Sopenharmony_ci					 &d->i2c_adap);
134862306a36Sopenharmony_ci	if (!adap->fe_adap[0].fe)
134962306a36Sopenharmony_ci		return -EIO;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	return 0;
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci/*
135562306a36Sopenharmony_ci * DViCO has shipped two devices with the same USB ID, but only one of them
135662306a36Sopenharmony_ci * needs a firmware download.  Check the device class details to see if they
135762306a36Sopenharmony_ci * have non-default values to decide whether the device is actually cold or
135862306a36Sopenharmony_ci * not, and forget a match if it turns out we selected the wrong device.
135962306a36Sopenharmony_ci */
136062306a36Sopenharmony_cistatic int bluebird_fx2_identify_state(struct usb_device *udev,
136162306a36Sopenharmony_ci				       const struct dvb_usb_device_properties *props,
136262306a36Sopenharmony_ci				       const struct dvb_usb_device_description **desc,
136362306a36Sopenharmony_ci				       int *cold)
136462306a36Sopenharmony_ci{
136562306a36Sopenharmony_ci	int wascold = *cold;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	*cold = udev->descriptor.bDeviceClass == 0xff &&
136862306a36Sopenharmony_ci		udev->descriptor.bDeviceSubClass == 0xff &&
136962306a36Sopenharmony_ci		udev->descriptor.bDeviceProtocol == 0xff;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	if (*cold && !wascold)
137262306a36Sopenharmony_ci		*desc = NULL;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	return 0;
137562306a36Sopenharmony_ci}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci/*
137862306a36Sopenharmony_ci * DViCO bluebird firmware needs the "warm" product ID to be patched into the
137962306a36Sopenharmony_ci * firmware file before download.
138062306a36Sopenharmony_ci */
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_cistatic const int dvico_firmware_id_offsets[] = { 6638, 3204 };
138362306a36Sopenharmony_cistatic int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
138462306a36Sopenharmony_ci						  const struct firmware *fw)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	int pos;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) {
138962306a36Sopenharmony_ci		int idoff = dvico_firmware_id_offsets[pos];
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci		if (fw->size < idoff + 4)
139262306a36Sopenharmony_ci			continue;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci		if (fw->data[idoff] == (USB_VID_DVICO & 0xff) &&
139562306a36Sopenharmony_ci		    fw->data[idoff + 1] == USB_VID_DVICO >> 8) {
139662306a36Sopenharmony_ci			struct firmware new_fw;
139762306a36Sopenharmony_ci			u8 *new_fw_data = vmalloc(fw->size);
139862306a36Sopenharmony_ci			int ret;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci			if (!new_fw_data)
140162306a36Sopenharmony_ci				return -ENOMEM;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci			memcpy(new_fw_data, fw->data, fw->size);
140462306a36Sopenharmony_ci			new_fw.size = fw->size;
140562306a36Sopenharmony_ci			new_fw.data = new_fw_data;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci			new_fw_data[idoff + 2] =
140862306a36Sopenharmony_ci				le16_to_cpu(udev->descriptor.idProduct) + 1;
140962306a36Sopenharmony_ci			new_fw_data[idoff + 3] =
141062306a36Sopenharmony_ci				le16_to_cpu(udev->descriptor.idProduct) >> 8;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci			ret = usb_cypress_load_firmware(udev, &new_fw,
141362306a36Sopenharmony_ci							CYPRESS_FX2);
141462306a36Sopenharmony_ci			vfree(new_fw_data);
141562306a36Sopenharmony_ci			return ret;
141662306a36Sopenharmony_ci		}
141762306a36Sopenharmony_ci	}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	return -EINVAL;
142062306a36Sopenharmony_ci}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ciint cxusb_medion_get(struct dvb_usb_device *dvbdev,
142362306a36Sopenharmony_ci		     enum cxusb_open_type open_type)
142462306a36Sopenharmony_ci{
142562306a36Sopenharmony_ci	struct cxusb_medion_dev *cxdev = dvbdev->priv;
142662306a36Sopenharmony_ci	int ret = 0;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	mutex_lock(&cxdev->open_lock);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	if (WARN_ON((cxdev->open_type == CXUSB_OPEN_INIT ||
143162306a36Sopenharmony_ci		     cxdev->open_type == CXUSB_OPEN_NONE) &&
143262306a36Sopenharmony_ci		    cxdev->open_ctr != 0)) {
143362306a36Sopenharmony_ci		ret = -EINVAL;
143462306a36Sopenharmony_ci		goto ret_unlock;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	if (cxdev->open_type == CXUSB_OPEN_INIT) {
143862306a36Sopenharmony_ci		ret = -EAGAIN;
143962306a36Sopenharmony_ci		goto ret_unlock;
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (cxdev->open_ctr == 0) {
144362306a36Sopenharmony_ci		if (cxdev->open_type != open_type) {
144462306a36Sopenharmony_ci			dev_info(&dvbdev->udev->dev, "will acquire and switch to %s\n",
144562306a36Sopenharmony_ci				 open_type == CXUSB_OPEN_ANALOG ?
144662306a36Sopenharmony_ci				 "analog" : "digital");
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci			if (open_type == CXUSB_OPEN_ANALOG) {
144962306a36Sopenharmony_ci				ret = _cxusb_power_ctrl(dvbdev, 1);
145062306a36Sopenharmony_ci				if (ret != 0)
145162306a36Sopenharmony_ci					dev_warn(&dvbdev->udev->dev,
145262306a36Sopenharmony_ci						 "powerup for analog switch failed (%d)\n",
145362306a36Sopenharmony_ci						 ret);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci				ret = cxusb_medion_set_mode(dvbdev, false);
145662306a36Sopenharmony_ci				if (ret != 0)
145762306a36Sopenharmony_ci					goto ret_unlock;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci				ret = cxusb_medion_analog_init(dvbdev);
146062306a36Sopenharmony_ci				if (ret != 0)
146162306a36Sopenharmony_ci					goto ret_unlock;
146262306a36Sopenharmony_ci			} else { /* digital */
146362306a36Sopenharmony_ci				ret = _cxusb_power_ctrl(dvbdev, 1);
146462306a36Sopenharmony_ci				if (ret != 0)
146562306a36Sopenharmony_ci					dev_warn(&dvbdev->udev->dev,
146662306a36Sopenharmony_ci						 "powerup for digital switch failed (%d)\n",
146762306a36Sopenharmony_ci						 ret);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci				ret = cxusb_medion_set_mode(dvbdev, true);
147062306a36Sopenharmony_ci				if (ret != 0)
147162306a36Sopenharmony_ci					goto ret_unlock;
147262306a36Sopenharmony_ci			}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci			cxdev->open_type = open_type;
147562306a36Sopenharmony_ci		} else {
147662306a36Sopenharmony_ci			dev_info(&dvbdev->udev->dev, "reacquired idle %s\n",
147762306a36Sopenharmony_ci				 open_type == CXUSB_OPEN_ANALOG ?
147862306a36Sopenharmony_ci				 "analog" : "digital");
147962306a36Sopenharmony_ci		}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci		cxdev->open_ctr = 1;
148262306a36Sopenharmony_ci	} else if (cxdev->open_type == open_type) {
148362306a36Sopenharmony_ci		cxdev->open_ctr++;
148462306a36Sopenharmony_ci		dev_info(&dvbdev->udev->dev, "acquired %s\n",
148562306a36Sopenharmony_ci			 open_type == CXUSB_OPEN_ANALOG ? "analog" : "digital");
148662306a36Sopenharmony_ci	} else {
148762306a36Sopenharmony_ci		ret = -EBUSY;
148862306a36Sopenharmony_ci	}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ciret_unlock:
149162306a36Sopenharmony_ci	mutex_unlock(&cxdev->open_lock);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	return ret;
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_civoid cxusb_medion_put(struct dvb_usb_device *dvbdev)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	struct cxusb_medion_dev *cxdev = dvbdev->priv;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	mutex_lock(&cxdev->open_lock);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	if (cxdev->open_type == CXUSB_OPEN_INIT) {
150362306a36Sopenharmony_ci		WARN_ON(cxdev->open_ctr != 0);
150462306a36Sopenharmony_ci		cxdev->open_type = CXUSB_OPEN_NONE;
150562306a36Sopenharmony_ci		goto unlock;
150662306a36Sopenharmony_ci	}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	if (!WARN_ON(cxdev->open_ctr < 1)) {
150962306a36Sopenharmony_ci		cxdev->open_ctr--;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci		dev_info(&dvbdev->udev->dev, "release %s\n",
151262306a36Sopenharmony_ci			 cxdev->open_type == CXUSB_OPEN_ANALOG ?
151362306a36Sopenharmony_ci			 "analog" : "digital");
151462306a36Sopenharmony_ci	}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ciunlock:
151762306a36Sopenharmony_ci	mutex_unlock(&cxdev->open_lock);
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci/* DVB USB Driver stuff */
152162306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_medion_properties;
152262306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
152362306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
152462306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
152562306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
152662306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
152762306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties;
152862306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
152962306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
153062306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_aver_a868r_properties;
153162306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_d680_dmb_properties;
153262306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_mygica_d689_properties;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic int cxusb_medion_priv_init(struct dvb_usb_device *dvbdev)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	struct cxusb_medion_dev *cxdev = dvbdev->priv;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	cxdev->dvbdev = dvbdev;
153962306a36Sopenharmony_ci	cxdev->open_type = CXUSB_OPEN_INIT;
154062306a36Sopenharmony_ci	mutex_init(&cxdev->open_lock);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	return 0;
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_cistatic void cxusb_medion_priv_destroy(struct dvb_usb_device *dvbdev)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct cxusb_medion_dev *cxdev = dvbdev->priv;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	mutex_destroy(&cxdev->open_lock);
155062306a36Sopenharmony_ci}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_cistatic bool cxusb_medion_check_altsetting(struct usb_host_interface *as)
155362306a36Sopenharmony_ci{
155462306a36Sopenharmony_ci	unsigned int ctr;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	for (ctr = 0; ctr < as->desc.bNumEndpoints; ctr++) {
155762306a36Sopenharmony_ci		if ((as->endpoint[ctr].desc.bEndpointAddress &
155862306a36Sopenharmony_ci		     USB_ENDPOINT_NUMBER_MASK) != 2)
155962306a36Sopenharmony_ci			continue;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		if (as->endpoint[ctr].desc.bEndpointAddress & USB_DIR_IN &&
156262306a36Sopenharmony_ci		    ((as->endpoint[ctr].desc.bmAttributes &
156362306a36Sopenharmony_ci		      USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC))
156462306a36Sopenharmony_ci			return true;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci		break;
156762306a36Sopenharmony_ci	}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	return false;
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic bool cxusb_medion_check_intf(struct usb_interface *intf)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci	unsigned int ctr;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (intf->num_altsetting < 2) {
157762306a36Sopenharmony_ci		dev_err(intf->usb_dev, "no alternate interface");
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci		return false;
158062306a36Sopenharmony_ci	}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	for (ctr = 0; ctr < intf->num_altsetting; ctr++) {
158362306a36Sopenharmony_ci		if (intf->altsetting[ctr].desc.bAlternateSetting != 1)
158462306a36Sopenharmony_ci			continue;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci		if (cxusb_medion_check_altsetting(&intf->altsetting[ctr]))
158762306a36Sopenharmony_ci			return true;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci		break;
159062306a36Sopenharmony_ci	}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	dev_err(intf->usb_dev, "no iso interface");
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	return false;
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_cistatic int cxusb_probe(struct usb_interface *intf,
159862306a36Sopenharmony_ci		       const struct usb_device_id *id)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	struct dvb_usb_device *dvbdev;
160162306a36Sopenharmony_ci	int ret;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	/* Medion 95700 */
160462306a36Sopenharmony_ci	if (!dvb_usb_device_init(intf, &cxusb_medion_properties,
160562306a36Sopenharmony_ci				 THIS_MODULE, &dvbdev, adapter_nr)) {
160662306a36Sopenharmony_ci		if (!cxusb_medion_check_intf(intf)) {
160762306a36Sopenharmony_ci			ret = -ENODEV;
160862306a36Sopenharmony_ci			goto ret_uninit;
160962306a36Sopenharmony_ci		}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci		_cxusb_power_ctrl(dvbdev, 1);
161262306a36Sopenharmony_ci		ret = cxusb_medion_set_mode(dvbdev, false);
161362306a36Sopenharmony_ci		if (ret)
161462306a36Sopenharmony_ci			goto ret_uninit;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci		ret = cxusb_medion_register_analog(dvbdev);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci		cxusb_medion_set_mode(dvbdev, true);
161962306a36Sopenharmony_ci		_cxusb_power_ctrl(dvbdev, 0);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci		if (ret != 0)
162262306a36Sopenharmony_ci			goto ret_uninit;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci		/* release device from INIT mode to normal operation */
162562306a36Sopenharmony_ci		cxusb_medion_put(dvbdev);
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci		return 0;
162862306a36Sopenharmony_ci	} else if (!dvb_usb_device_init(intf,
162962306a36Sopenharmony_ci					&cxusb_bluebird_lgh064f_properties,
163062306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
163162306a36Sopenharmony_ci		   !dvb_usb_device_init(intf,
163262306a36Sopenharmony_ci					&cxusb_bluebird_dee1601_properties,
163362306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
163462306a36Sopenharmony_ci		   !dvb_usb_device_init(intf,
163562306a36Sopenharmony_ci					&cxusb_bluebird_lgz201_properties,
163662306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
163762306a36Sopenharmony_ci		   !dvb_usb_device_init(intf,
163862306a36Sopenharmony_ci					&cxusb_bluebird_dtt7579_properties,
163962306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
164062306a36Sopenharmony_ci		   !dvb_usb_device_init(intf,
164162306a36Sopenharmony_ci					&cxusb_bluebird_dualdig4_properties,
164262306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
164362306a36Sopenharmony_ci		   !dvb_usb_device_init(intf,
164462306a36Sopenharmony_ci					&cxusb_bluebird_nano2_properties,
164562306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
164662306a36Sopenharmony_ci		   !dvb_usb_device_init(intf,
164762306a36Sopenharmony_ci					&cxusb_bluebird_nano2_needsfirmware_properties,
164862306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
164962306a36Sopenharmony_ci		   !dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
165062306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
165162306a36Sopenharmony_ci		   !dvb_usb_device_init(intf,
165262306a36Sopenharmony_ci					&cxusb_bluebird_dualdig4_rev2_properties,
165362306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
165462306a36Sopenharmony_ci		   !dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
165562306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
165662306a36Sopenharmony_ci		   !dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
165762306a36Sopenharmony_ci					THIS_MODULE, NULL, adapter_nr) ||
165862306a36Sopenharmony_ci		   0)
165962306a36Sopenharmony_ci		return 0;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	return -EINVAL;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ciret_uninit:
166462306a36Sopenharmony_ci	dvb_usb_device_exit(intf);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	return ret;
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_cistatic void cxusb_disconnect(struct usb_interface *intf)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	struct dvb_usb_device *d = usb_get_intfdata(intf);
167262306a36Sopenharmony_ci	struct cxusb_state *st = d->priv;
167362306a36Sopenharmony_ci	struct i2c_client *client;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if (d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700])
167662306a36Sopenharmony_ci		cxusb_medion_unregister_analog(d);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	/* remove I2C client for tuner */
167962306a36Sopenharmony_ci	client = st->i2c_client_tuner;
168062306a36Sopenharmony_ci	if (client) {
168162306a36Sopenharmony_ci		module_put(client->dev.driver->owner);
168262306a36Sopenharmony_ci		i2c_unregister_device(client);
168362306a36Sopenharmony_ci	}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	/* remove I2C client for demodulator */
168662306a36Sopenharmony_ci	client = st->i2c_client_demod;
168762306a36Sopenharmony_ci	if (client) {
168862306a36Sopenharmony_ci		module_put(client->dev.driver->owner);
168962306a36Sopenharmony_ci		i2c_unregister_device(client);
169062306a36Sopenharmony_ci	}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	dvb_usb_device_exit(intf);
169362306a36Sopenharmony_ci}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_cistatic struct usb_device_id cxusb_table[] = {
169662306a36Sopenharmony_ci	DVB_USB_DEV(MEDION, MEDION_MD95700),
169762306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LG064F_COLD),
169862306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LG064F_WARM),
169962306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_1_COLD),
170062306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_1_WARM),
170162306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LGZ201_COLD),
170262306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LGZ201_WARM),
170362306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_TH7579_COLD),
170462306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_TH7579_WARM),
170562306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DIGITALNOW_BLUEBIRD_DUAL_1_COLD),
170662306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DIGITALNOW_BLUEBIRD_DUAL_1_WARM),
170762306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_2_COLD),
170862306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_2_WARM),
170962306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_4),
171062306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DVB_T_NANO_2),
171162306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM),
171262306a36Sopenharmony_ci	DVB_USB_DEV(AVERMEDIA, AVERMEDIA_VOLAR_A868R),
171362306a36Sopenharmony_ci	DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_4_REV_2),
171462306a36Sopenharmony_ci	DVB_USB_DEV(CONEXANT, CONEXANT_D680_DMB),
171562306a36Sopenharmony_ci	DVB_USB_DEV(CONEXANT, MYGICA_D689),
171662306a36Sopenharmony_ci	{ }
171762306a36Sopenharmony_ci};
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, cxusb_table);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_medion_properties = {
172262306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	.usb_ctrl = CYPRESS_FX2,
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_medion_dev),
172762306a36Sopenharmony_ci	.priv_init        = cxusb_medion_priv_init,
172862306a36Sopenharmony_ci	.priv_destroy     = cxusb_medion_priv_destroy,
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	.num_adapters = 1,
173162306a36Sopenharmony_ci	.adapter = {
173262306a36Sopenharmony_ci		{
173362306a36Sopenharmony_ci		.num_frontends = 1,
173462306a36Sopenharmony_ci		.fe = {{
173562306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_streaming_ctrl,
173662306a36Sopenharmony_ci			.frontend_attach  = cxusb_cx22702_frontend_attach,
173762306a36Sopenharmony_ci			.tuner_attach     = cxusb_fmd1216me_tuner_attach,
173862306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
173962306a36Sopenharmony_ci					.stream = {
174062306a36Sopenharmony_ci						.type = USB_BULK,
174162306a36Sopenharmony_ci				.count = 5,
174262306a36Sopenharmony_ci				.endpoint = 0x02,
174362306a36Sopenharmony_ci				.u = {
174462306a36Sopenharmony_ci					.bulk = {
174562306a36Sopenharmony_ci						.buffersize = 8192,
174662306a36Sopenharmony_ci					}
174762306a36Sopenharmony_ci				}
174862306a36Sopenharmony_ci			},
174962306a36Sopenharmony_ci		} },
175062306a36Sopenharmony_ci		},
175162306a36Sopenharmony_ci	},
175262306a36Sopenharmony_ci	.power_ctrl       = cxusb_power_ctrl,
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	.num_device_descs = 1,
175962306a36Sopenharmony_ci	.devices = {
176062306a36Sopenharmony_ci		{
176162306a36Sopenharmony_ci			"Medion MD95700 (MDUSBTV-HYBRID)",
176262306a36Sopenharmony_ci			{ NULL },
176362306a36Sopenharmony_ci			{ &cxusb_table[MEDION_MD95700], NULL },
176462306a36Sopenharmony_ci		},
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci};
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
176962306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	.usb_ctrl          = DEVICE_SPECIFIC,
177262306a36Sopenharmony_ci	.firmware          = "dvb-usb-bluebird-01.fw",
177362306a36Sopenharmony_ci	.download_firmware = bluebird_patch_dvico_firmware_download,
177462306a36Sopenharmony_ci	/*
177562306a36Sopenharmony_ci	 * use usb alt setting 0 for EP4 transfer (dvb-t),
177662306a36Sopenharmony_ci	 * use usb alt setting 7 for EP2 transfer (atsc)
177762306a36Sopenharmony_ci	 */
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	.num_adapters = 1,
178262306a36Sopenharmony_ci	.adapter = {
178362306a36Sopenharmony_ci		{
178462306a36Sopenharmony_ci		.num_frontends = 1,
178562306a36Sopenharmony_ci		.fe = {{
178662306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_streaming_ctrl,
178762306a36Sopenharmony_ci			.frontend_attach  = cxusb_lgdt3303_frontend_attach,
178862306a36Sopenharmony_ci			.tuner_attach     = cxusb_lgh064f_tuner_attach,
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
179162306a36Sopenharmony_ci					.stream = {
179262306a36Sopenharmony_ci						.type = USB_BULK,
179362306a36Sopenharmony_ci				.count = 5,
179462306a36Sopenharmony_ci				.endpoint = 0x02,
179562306a36Sopenharmony_ci				.u = {
179662306a36Sopenharmony_ci					.bulk = {
179762306a36Sopenharmony_ci						.buffersize = 8192,
179862306a36Sopenharmony_ci					}
179962306a36Sopenharmony_ci				}
180062306a36Sopenharmony_ci			},
180162306a36Sopenharmony_ci		} },
180262306a36Sopenharmony_ci		},
180362306a36Sopenharmony_ci	},
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	.power_ctrl       = cxusb_bluebird_power_ctrl,
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	.rc.core = {
181062306a36Sopenharmony_ci		.rc_interval	= 100,
181162306a36Sopenharmony_ci		.rc_codes	= RC_MAP_DVICO_PORTABLE,
181262306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
181362306a36Sopenharmony_ci		.rc_query	= cxusb_rc_query,
181462306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_NEC,
181562306a36Sopenharmony_ci	},
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	.num_device_descs = 1,
182062306a36Sopenharmony_ci	.devices = {
182162306a36Sopenharmony_ci		{   "DViCO FusionHDTV5 USB Gold",
182262306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_LG064F_COLD], NULL },
182362306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_LG064F_WARM], NULL },
182462306a36Sopenharmony_ci		},
182562306a36Sopenharmony_ci	}
182662306a36Sopenharmony_ci};
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
182962306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	.usb_ctrl          = DEVICE_SPECIFIC,
183262306a36Sopenharmony_ci	.firmware          = "dvb-usb-bluebird-01.fw",
183362306a36Sopenharmony_ci	.download_firmware = bluebird_patch_dvico_firmware_download,
183462306a36Sopenharmony_ci	/*
183562306a36Sopenharmony_ci	 * use usb alt setting 0 for EP4 transfer (dvb-t),
183662306a36Sopenharmony_ci	 * use usb alt setting 7 for EP2 transfer (atsc)
183762306a36Sopenharmony_ci	 */
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	.num_adapters = 1,
184262306a36Sopenharmony_ci	.adapter = {
184362306a36Sopenharmony_ci		{
184462306a36Sopenharmony_ci		.num_frontends = 1,
184562306a36Sopenharmony_ci		.fe = {{
184662306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_streaming_ctrl,
184762306a36Sopenharmony_ci			.frontend_attach  = cxusb_dee1601_frontend_attach,
184862306a36Sopenharmony_ci			.tuner_attach     = cxusb_dee1601_tuner_attach,
184962306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
185062306a36Sopenharmony_ci			.stream = {
185162306a36Sopenharmony_ci				.type = USB_BULK,
185262306a36Sopenharmony_ci				.count = 5,
185362306a36Sopenharmony_ci				.endpoint = 0x04,
185462306a36Sopenharmony_ci				.u = {
185562306a36Sopenharmony_ci					.bulk = {
185662306a36Sopenharmony_ci						.buffersize = 8192,
185762306a36Sopenharmony_ci					}
185862306a36Sopenharmony_ci				}
185962306a36Sopenharmony_ci			},
186062306a36Sopenharmony_ci		} },
186162306a36Sopenharmony_ci		},
186262306a36Sopenharmony_ci	},
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	.power_ctrl       = cxusb_bluebird_power_ctrl,
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	.rc.core = {
186962306a36Sopenharmony_ci		.rc_interval	= 100,
187062306a36Sopenharmony_ci		.rc_codes	= RC_MAP_DVICO_MCE,
187162306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
187262306a36Sopenharmony_ci		.rc_query	= cxusb_rc_query,
187362306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_NEC,
187462306a36Sopenharmony_ci	},
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	.num_device_descs = 3,
187962306a36Sopenharmony_ci	.devices = {
188062306a36Sopenharmony_ci		{   "DViCO FusionHDTV DVB-T Dual USB",
188162306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DUAL_1_COLD], NULL },
188262306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DUAL_1_WARM], NULL },
188362306a36Sopenharmony_ci		},
188462306a36Sopenharmony_ci		{   "DigitalNow DVB-T Dual USB",
188562306a36Sopenharmony_ci			{ &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL },
188662306a36Sopenharmony_ci			{ &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_WARM], NULL },
188762306a36Sopenharmony_ci		},
188862306a36Sopenharmony_ci		{   "DViCO FusionHDTV DVB-T Dual Digital 2",
188962306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DUAL_2_COLD], NULL },
189062306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DUAL_2_WARM], NULL },
189162306a36Sopenharmony_ci		},
189262306a36Sopenharmony_ci	}
189362306a36Sopenharmony_ci};
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
189662306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	.usb_ctrl          = DEVICE_SPECIFIC,
189962306a36Sopenharmony_ci	.firmware          = "dvb-usb-bluebird-01.fw",
190062306a36Sopenharmony_ci	.download_firmware = bluebird_patch_dvico_firmware_download,
190162306a36Sopenharmony_ci	/*
190262306a36Sopenharmony_ci	 * use usb alt setting 0 for EP4 transfer (dvb-t),
190362306a36Sopenharmony_ci	 * use usb alt setting 7 for EP2 transfer (atsc)
190462306a36Sopenharmony_ci	 */
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	.num_adapters = 1,
190962306a36Sopenharmony_ci	.adapter = {
191062306a36Sopenharmony_ci		{
191162306a36Sopenharmony_ci		.num_frontends = 1,
191262306a36Sopenharmony_ci		.fe = {{
191362306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_streaming_ctrl,
191462306a36Sopenharmony_ci			.frontend_attach  = cxusb_mt352_frontend_attach,
191562306a36Sopenharmony_ci			.tuner_attach     = cxusb_lgz201_tuner_attach,
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
191862306a36Sopenharmony_ci			.stream = {
191962306a36Sopenharmony_ci				.type = USB_BULK,
192062306a36Sopenharmony_ci				.count = 5,
192162306a36Sopenharmony_ci				.endpoint = 0x04,
192262306a36Sopenharmony_ci				.u = {
192362306a36Sopenharmony_ci					.bulk = {
192462306a36Sopenharmony_ci						.buffersize = 8192,
192562306a36Sopenharmony_ci					}
192662306a36Sopenharmony_ci				}
192762306a36Sopenharmony_ci			},
192862306a36Sopenharmony_ci		} },
192962306a36Sopenharmony_ci		},
193062306a36Sopenharmony_ci	},
193162306a36Sopenharmony_ci	.power_ctrl       = cxusb_bluebird_power_ctrl,
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	.rc.core = {
193662306a36Sopenharmony_ci		.rc_interval	= 100,
193762306a36Sopenharmony_ci		.rc_codes	= RC_MAP_DVICO_PORTABLE,
193862306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
193962306a36Sopenharmony_ci		.rc_query	= cxusb_rc_query,
194062306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_NEC,
194162306a36Sopenharmony_ci	},
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
194462306a36Sopenharmony_ci	.num_device_descs = 1,
194562306a36Sopenharmony_ci	.devices = {
194662306a36Sopenharmony_ci		{   "DViCO FusionHDTV DVB-T USB (LGZ201)",
194762306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_LGZ201_COLD], NULL },
194862306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_LGZ201_WARM], NULL },
194962306a36Sopenharmony_ci		},
195062306a36Sopenharmony_ci	}
195162306a36Sopenharmony_ci};
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
195462306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	.usb_ctrl          = DEVICE_SPECIFIC,
195762306a36Sopenharmony_ci	.firmware          = "dvb-usb-bluebird-01.fw",
195862306a36Sopenharmony_ci	.download_firmware = bluebird_patch_dvico_firmware_download,
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	/*
196162306a36Sopenharmony_ci	 * use usb alt setting 0 for EP4 transfer (dvb-t),
196262306a36Sopenharmony_ci	 * use usb alt setting 7 for EP2 transfer (atsc)
196362306a36Sopenharmony_ci	 */
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	.num_adapters = 1,
196862306a36Sopenharmony_ci	.adapter = {
196962306a36Sopenharmony_ci		{
197062306a36Sopenharmony_ci		.num_frontends = 1,
197162306a36Sopenharmony_ci		.fe = {{
197262306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_streaming_ctrl,
197362306a36Sopenharmony_ci			.frontend_attach  = cxusb_mt352_frontend_attach,
197462306a36Sopenharmony_ci			.tuner_attach     = cxusb_dtt7579_tuner_attach,
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
197762306a36Sopenharmony_ci			.stream = {
197862306a36Sopenharmony_ci				.type = USB_BULK,
197962306a36Sopenharmony_ci				.count = 5,
198062306a36Sopenharmony_ci				.endpoint = 0x04,
198162306a36Sopenharmony_ci				.u = {
198262306a36Sopenharmony_ci					.bulk = {
198362306a36Sopenharmony_ci						.buffersize = 8192,
198462306a36Sopenharmony_ci					}
198562306a36Sopenharmony_ci				}
198662306a36Sopenharmony_ci			},
198762306a36Sopenharmony_ci		} },
198862306a36Sopenharmony_ci		},
198962306a36Sopenharmony_ci	},
199062306a36Sopenharmony_ci	.power_ctrl       = cxusb_bluebird_power_ctrl,
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	.rc.core = {
199562306a36Sopenharmony_ci		.rc_interval	= 100,
199662306a36Sopenharmony_ci		.rc_codes	= RC_MAP_DVICO_PORTABLE,
199762306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
199862306a36Sopenharmony_ci		.rc_query	= cxusb_rc_query,
199962306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_NEC,
200062306a36Sopenharmony_ci	},
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	.num_device_descs = 1,
200562306a36Sopenharmony_ci	.devices = {
200662306a36Sopenharmony_ci		{   "DViCO FusionHDTV DVB-T USB (TH7579)",
200762306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_TH7579_COLD], NULL },
200862306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_TH7579_WARM], NULL },
200962306a36Sopenharmony_ci		},
201062306a36Sopenharmony_ci	}
201162306a36Sopenharmony_ci};
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
201462306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	.usb_ctrl         = CYPRESS_FX2,
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	.num_adapters = 1,
202162306a36Sopenharmony_ci	.adapter = {
202262306a36Sopenharmony_ci		{
202362306a36Sopenharmony_ci		.num_frontends = 1,
202462306a36Sopenharmony_ci		.fe = {{
202562306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_streaming_ctrl,
202662306a36Sopenharmony_ci			.frontend_attach  = cxusb_dualdig4_frontend_attach,
202762306a36Sopenharmony_ci			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
202862306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
202962306a36Sopenharmony_ci			.stream = {
203062306a36Sopenharmony_ci				.type = USB_BULK,
203162306a36Sopenharmony_ci				.count = 5,
203262306a36Sopenharmony_ci				.endpoint = 0x02,
203362306a36Sopenharmony_ci				.u = {
203462306a36Sopenharmony_ci					.bulk = {
203562306a36Sopenharmony_ci						.buffersize = 8192,
203662306a36Sopenharmony_ci					}
203762306a36Sopenharmony_ci				}
203862306a36Sopenharmony_ci			},
203962306a36Sopenharmony_ci		} },
204062306a36Sopenharmony_ci		},
204162306a36Sopenharmony_ci	},
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	.power_ctrl       = cxusb_power_ctrl,
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	.rc.core = {
205062306a36Sopenharmony_ci		.rc_interval	= 100,
205162306a36Sopenharmony_ci		.rc_codes	= RC_MAP_DVICO_MCE,
205262306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
205362306a36Sopenharmony_ci		.rc_query	= cxusb_bluebird2_rc_query,
205462306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_NEC,
205562306a36Sopenharmony_ci	},
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	.num_device_descs = 1,
205862306a36Sopenharmony_ci	.devices = {
205962306a36Sopenharmony_ci		{   "DViCO FusionHDTV DVB-T Dual Digital 4",
206062306a36Sopenharmony_ci			{ NULL },
206162306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DUAL_4], NULL },
206262306a36Sopenharmony_ci		},
206362306a36Sopenharmony_ci	}
206462306a36Sopenharmony_ci};
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
206762306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	.usb_ctrl         = CYPRESS_FX2,
207062306a36Sopenharmony_ci	.identify_state   = bluebird_fx2_identify_state,
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	.num_adapters = 1,
207562306a36Sopenharmony_ci	.adapter = {
207662306a36Sopenharmony_ci		{
207762306a36Sopenharmony_ci		.num_frontends = 1,
207862306a36Sopenharmony_ci		.fe = {{
207962306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_streaming_ctrl,
208062306a36Sopenharmony_ci			.frontend_attach  = cxusb_nano2_frontend_attach,
208162306a36Sopenharmony_ci			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
208262306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
208362306a36Sopenharmony_ci			.stream = {
208462306a36Sopenharmony_ci				.type = USB_BULK,
208562306a36Sopenharmony_ci				.count = 5,
208662306a36Sopenharmony_ci				.endpoint = 0x02,
208762306a36Sopenharmony_ci				.u = {
208862306a36Sopenharmony_ci					.bulk = {
208962306a36Sopenharmony_ci						.buffersize = 8192,
209062306a36Sopenharmony_ci					}
209162306a36Sopenharmony_ci				}
209262306a36Sopenharmony_ci			},
209362306a36Sopenharmony_ci		} },
209462306a36Sopenharmony_ci		},
209562306a36Sopenharmony_ci	},
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	.power_ctrl       = cxusb_nano2_power_ctrl,
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	.rc.core = {
210462306a36Sopenharmony_ci		.rc_interval	= 100,
210562306a36Sopenharmony_ci		.rc_codes	= RC_MAP_DVICO_PORTABLE,
210662306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
210762306a36Sopenharmony_ci		.rc_query       = cxusb_bluebird2_rc_query,
210862306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_NEC,
210962306a36Sopenharmony_ci	},
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	.num_device_descs = 1,
211262306a36Sopenharmony_ci	.devices = {
211362306a36Sopenharmony_ci		{   "DViCO FusionHDTV DVB-T NANO2",
211462306a36Sopenharmony_ci			{ NULL },
211562306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL },
211662306a36Sopenharmony_ci		},
211762306a36Sopenharmony_ci	}
211862306a36Sopenharmony_ci};
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_cistatic struct dvb_usb_device_properties
212162306a36Sopenharmony_cicxusb_bluebird_nano2_needsfirmware_properties = {
212262306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	.usb_ctrl          = DEVICE_SPECIFIC,
212562306a36Sopenharmony_ci	.firmware          = "dvb-usb-bluebird-02.fw",
212662306a36Sopenharmony_ci	.download_firmware = bluebird_patch_dvico_firmware_download,
212762306a36Sopenharmony_ci	.identify_state    = bluebird_fx2_identify_state,
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	.size_of_priv      = sizeof(struct cxusb_state),
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	.num_adapters = 1,
213262306a36Sopenharmony_ci	.adapter = {
213362306a36Sopenharmony_ci		{
213462306a36Sopenharmony_ci		.num_frontends = 1,
213562306a36Sopenharmony_ci		.fe = {{
213662306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_streaming_ctrl,
213762306a36Sopenharmony_ci			.frontend_attach  = cxusb_nano2_frontend_attach,
213862306a36Sopenharmony_ci			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
213962306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
214062306a36Sopenharmony_ci			.stream = {
214162306a36Sopenharmony_ci				.type = USB_BULK,
214262306a36Sopenharmony_ci				.count = 5,
214362306a36Sopenharmony_ci				.endpoint = 0x02,
214462306a36Sopenharmony_ci				.u = {
214562306a36Sopenharmony_ci					.bulk = {
214662306a36Sopenharmony_ci						.buffersize = 8192,
214762306a36Sopenharmony_ci					}
214862306a36Sopenharmony_ci				}
214962306a36Sopenharmony_ci			},
215062306a36Sopenharmony_ci		} },
215162306a36Sopenharmony_ci		},
215262306a36Sopenharmony_ci	},
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	.power_ctrl       = cxusb_nano2_power_ctrl,
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	.rc.core = {
216162306a36Sopenharmony_ci		.rc_interval	= 100,
216262306a36Sopenharmony_ci		.rc_codes	= RC_MAP_DVICO_PORTABLE,
216362306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
216462306a36Sopenharmony_ci		.rc_query	= cxusb_rc_query,
216562306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_NEC,
216662306a36Sopenharmony_ci	},
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	.num_device_descs = 1,
216962306a36Sopenharmony_ci	.devices = { {
217062306a36Sopenharmony_ci			"DViCO FusionHDTV DVB-T NANO2 w/o firmware",
217162306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL },
217262306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM],
217362306a36Sopenharmony_ci			  NULL },
217462306a36Sopenharmony_ci		},
217562306a36Sopenharmony_ci	}
217662306a36Sopenharmony_ci};
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
217962306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	.usb_ctrl         = CYPRESS_FX2,
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	.num_adapters = 1,
218662306a36Sopenharmony_ci	.adapter = {
218762306a36Sopenharmony_ci		{
218862306a36Sopenharmony_ci		.num_frontends = 1,
218962306a36Sopenharmony_ci		.fe = {{
219062306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_aver_streaming_ctrl,
219162306a36Sopenharmony_ci			.frontend_attach  = cxusb_aver_lgdt3303_frontend_attach,
219262306a36Sopenharmony_ci			.tuner_attach     = cxusb_mxl5003s_tuner_attach,
219362306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
219462306a36Sopenharmony_ci			.stream = {
219562306a36Sopenharmony_ci				.type = USB_BULK,
219662306a36Sopenharmony_ci				.count = 5,
219762306a36Sopenharmony_ci				.endpoint = 0x04,
219862306a36Sopenharmony_ci				.u = {
219962306a36Sopenharmony_ci					.bulk = {
220062306a36Sopenharmony_ci						.buffersize = 8192,
220162306a36Sopenharmony_ci					}
220262306a36Sopenharmony_ci				}
220362306a36Sopenharmony_ci			},
220462306a36Sopenharmony_ci		} },
220562306a36Sopenharmony_ci		},
220662306a36Sopenharmony_ci	},
220762306a36Sopenharmony_ci	.power_ctrl       = cxusb_aver_power_ctrl,
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	.num_device_descs = 1,
221462306a36Sopenharmony_ci	.devices = {
221562306a36Sopenharmony_ci		{   "AVerMedia AVerTVHD Volar (A868R)",
221662306a36Sopenharmony_ci			{ NULL },
221762306a36Sopenharmony_ci			{ &cxusb_table[AVERMEDIA_VOLAR_A868R], NULL },
221862306a36Sopenharmony_ci		},
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci};
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_cistatic
222362306a36Sopenharmony_cistruct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
222462306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	.usb_ctrl         = CYPRESS_FX2,
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	.num_adapters = 1,
223162306a36Sopenharmony_ci	.adapter = {
223262306a36Sopenharmony_ci		{
223362306a36Sopenharmony_ci		.size_of_priv    = sizeof(struct dib0700_adapter_state),
223462306a36Sopenharmony_ci		.num_frontends = 1,
223562306a36Sopenharmony_ci		.fe = {{
223662306a36Sopenharmony_ci			.streaming_ctrl  = cxusb_streaming_ctrl,
223762306a36Sopenharmony_ci			.frontend_attach = cxusb_dualdig4_rev2_frontend_attach,
223862306a36Sopenharmony_ci			.tuner_attach    = cxusb_dualdig4_rev2_tuner_attach,
223962306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
224062306a36Sopenharmony_ci			.stream = {
224162306a36Sopenharmony_ci				.type = USB_BULK,
224262306a36Sopenharmony_ci				.count = 7,
224362306a36Sopenharmony_ci				.endpoint = 0x02,
224462306a36Sopenharmony_ci				.u = {
224562306a36Sopenharmony_ci					.bulk = {
224662306a36Sopenharmony_ci						.buffersize = 4096,
224762306a36Sopenharmony_ci					}
224862306a36Sopenharmony_ci				}
224962306a36Sopenharmony_ci			},
225062306a36Sopenharmony_ci		} },
225162306a36Sopenharmony_ci		},
225262306a36Sopenharmony_ci	},
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	.power_ctrl       = cxusb_bluebird_power_ctrl,
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	.rc.core = {
226162306a36Sopenharmony_ci		.rc_interval	= 100,
226262306a36Sopenharmony_ci		.rc_codes	= RC_MAP_DVICO_MCE,
226362306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
226462306a36Sopenharmony_ci		.rc_query	= cxusb_rc_query,
226562306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_NEC,
226662306a36Sopenharmony_ci	},
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	.num_device_descs = 1,
226962306a36Sopenharmony_ci	.devices = {
227062306a36Sopenharmony_ci		{   "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)",
227162306a36Sopenharmony_ci			{ NULL },
227262306a36Sopenharmony_ci			{ &cxusb_table[DVICO_BLUEBIRD_DUAL_4_REV_2], NULL },
227362306a36Sopenharmony_ci		},
227462306a36Sopenharmony_ci	}
227562306a36Sopenharmony_ci};
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
227862306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	.usb_ctrl         = CYPRESS_FX2,
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	.num_adapters = 1,
228562306a36Sopenharmony_ci	.adapter = {
228662306a36Sopenharmony_ci		{
228762306a36Sopenharmony_ci		.num_frontends = 1,
228862306a36Sopenharmony_ci		.fe = {{
228962306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
229062306a36Sopenharmony_ci			.frontend_attach  = cxusb_d680_dmb_frontend_attach,
229162306a36Sopenharmony_ci			.tuner_attach     = cxusb_d680_dmb_tuner_attach,
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
229462306a36Sopenharmony_ci			.stream = {
229562306a36Sopenharmony_ci				.type = USB_BULK,
229662306a36Sopenharmony_ci				.count = 5,
229762306a36Sopenharmony_ci				.endpoint = 0x02,
229862306a36Sopenharmony_ci				.u = {
229962306a36Sopenharmony_ci					.bulk = {
230062306a36Sopenharmony_ci						.buffersize = 8192,
230162306a36Sopenharmony_ci					}
230262306a36Sopenharmony_ci				}
230362306a36Sopenharmony_ci			},
230462306a36Sopenharmony_ci		} },
230562306a36Sopenharmony_ci		},
230662306a36Sopenharmony_ci	},
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	.rc.core = {
231562306a36Sopenharmony_ci		.rc_interval	= 100,
231662306a36Sopenharmony_ci		.rc_codes	= RC_MAP_TOTAL_MEDIA_IN_HAND_02,
231762306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
231862306a36Sopenharmony_ci		.rc_query       = cxusb_d680_dmb_rc_query,
231962306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_UNKNOWN,
232062306a36Sopenharmony_ci	},
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	.num_device_descs = 1,
232362306a36Sopenharmony_ci	.devices = {
232462306a36Sopenharmony_ci		{
232562306a36Sopenharmony_ci			"Conexant DMB-TH Stick",
232662306a36Sopenharmony_ci			{ NULL },
232762306a36Sopenharmony_ci			{ &cxusb_table[CONEXANT_D680_DMB], NULL },
232862306a36Sopenharmony_ci		},
232962306a36Sopenharmony_ci	}
233062306a36Sopenharmony_ci};
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_cistatic struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
233362306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	.usb_ctrl         = CYPRESS_FX2,
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct cxusb_state),
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	.num_adapters = 1,
234062306a36Sopenharmony_ci	.adapter = {
234162306a36Sopenharmony_ci		{
234262306a36Sopenharmony_ci		.num_frontends = 1,
234362306a36Sopenharmony_ci		.fe = {{
234462306a36Sopenharmony_ci			.streaming_ctrl   = cxusb_d680_dmb_streaming_ctrl,
234562306a36Sopenharmony_ci			.frontend_attach  = cxusb_mygica_d689_frontend_attach,
234662306a36Sopenharmony_ci			.tuner_attach     = cxusb_mygica_d689_tuner_attach,
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
234962306a36Sopenharmony_ci			.stream = {
235062306a36Sopenharmony_ci				.type = USB_BULK,
235162306a36Sopenharmony_ci				.count = 5,
235262306a36Sopenharmony_ci				.endpoint = 0x02,
235362306a36Sopenharmony_ci				.u = {
235462306a36Sopenharmony_ci					.bulk = {
235562306a36Sopenharmony_ci						.buffersize = 8192,
235662306a36Sopenharmony_ci					}
235762306a36Sopenharmony_ci				}
235862306a36Sopenharmony_ci			},
235962306a36Sopenharmony_ci		} },
236062306a36Sopenharmony_ci		},
236162306a36Sopenharmony_ci	},
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	.power_ctrl       = cxusb_d680_dmb_power_ctrl,
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	.i2c_algo         = &cxusb_i2c_algo,
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	.rc.core = {
237062306a36Sopenharmony_ci		.rc_interval	= 100,
237162306a36Sopenharmony_ci		.rc_codes	= RC_MAP_D680_DMB,
237262306a36Sopenharmony_ci		.module_name	= KBUILD_MODNAME,
237362306a36Sopenharmony_ci		.rc_query       = cxusb_d680_dmb_rc_query,
237462306a36Sopenharmony_ci		.allowed_protos = RC_PROTO_BIT_UNKNOWN,
237562306a36Sopenharmony_ci	},
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	.num_device_descs = 1,
237862306a36Sopenharmony_ci	.devices = {
237962306a36Sopenharmony_ci		{
238062306a36Sopenharmony_ci			"Mygica D689 DMB-TH",
238162306a36Sopenharmony_ci			{ NULL },
238262306a36Sopenharmony_ci			{ &cxusb_table[MYGICA_D689], NULL },
238362306a36Sopenharmony_ci		},
238462306a36Sopenharmony_ci	}
238562306a36Sopenharmony_ci};
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_cistatic struct usb_driver cxusb_driver = {
238862306a36Sopenharmony_ci	.name		= "dvb_usb_cxusb",
238962306a36Sopenharmony_ci	.probe		= cxusb_probe,
239062306a36Sopenharmony_ci	.disconnect     = cxusb_disconnect,
239162306a36Sopenharmony_ci	.id_table	= cxusb_table,
239262306a36Sopenharmony_ci};
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_cimodule_usb_driver(cxusb_driver);
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
239762306a36Sopenharmony_ciMODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
239862306a36Sopenharmony_ciMODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
239962306a36Sopenharmony_ciMODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>");
240062306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
240162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2402