az6007.c 22.2 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
 *
 * Copyright (c) Henry Wang <Henry.wang@AzureWave.com>
 *
 * This driver was made publicly available by Terratec, at:
 *	http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
 * The original driver's license is GPL, as declared with MODULE_LICENSE()
 *
10
 * Copyright (c) 2010-2012 Mauro Carvalho Chehab
11
 *	Driver modified by in order to work with upstream drxk driver, and
12
 *	tons of bugs got fixed, and converted to use dvb-usb-v2.
13 14 15 16 17 18 19 20 21
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation under version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
22 23 24 25 26
 */

#include "drxk.h"
#include "mt2063.h"
#include "dvb_ca_en50221.h"
27 28
#include "dvb_usb.h"
#include "cypress_firmware.h"
29

30
#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw"
31

32 33 34
static int az6007_xfer_debug;
module_param_named(xfer_debug, az6007_xfer_debug, int, 0644);
MODULE_PARM_DESC(xfer_debug, "Enable xfer debug");
35

36 37
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);

38 39 40 41 42 43 44 45 46
/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/

#define FX2_OED			0xb5
#define AZ6007_READ_DATA	0xb7
#define AZ6007_I2C_RD		0xb9
#define AZ6007_POWER		0xbc
#define AZ6007_I2C_WR		0xbd
#define FX2_SCON1		0xc0
#define AZ6007_TS_THROUGH	0xc7
47
#define AZ6007_READ_IR		0xb4
48

49
struct az6007_device_state {
50
	struct mutex		mutex;
51
	struct mutex		ca_mutex;
52 53
	struct dvb_ca_en50221	ca;
	unsigned		warm:1;
54
	int			(*gate_ctrl) (struct dvb_frontend *, int);
55
	unsigned char		data[4096];
56 57
};

58
static struct drxk_config terratec_h7_drxk = {
59
	.adr = 0x29,
60 61 62
	.parallel_ts = true,
	.dynamic_clk = true,
	.single_master = true,
63
	.enable_merr_cfg = true,
64
	.no_i2c_bridge = false,
65
	.chunk_size = 64,
66
	.mpeg_out_clk_strength = 0x02,
67
	.qam_demod_parameter_count = 2,
68
	.microcode_name = "dvb-usb-terratec-h7-drxk.fw",
69 70
};

71 72 73 74 75 76 77 78 79 80 81 82 83
static struct drxk_config cablestar_hdci_drxk = {
	.adr = 0x29,
	.parallel_ts = true,
	.dynamic_clk = true,
	.single_master = true,
	.enable_merr_cfg = true,
	.no_i2c_bridge = false,
	.chunk_size = 64,
	.mpeg_out_clk_strength = 0x02,
	.qam_demod_parameter_count = 2,
	.microcode_name = "dvb-usb-technisat-cablestar-hdci-drxk.fw",
};

84 85
static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
{
86
	struct az6007_device_state *st = fe_to_priv(fe);
87
	struct dvb_usb_adapter *adap = fe->sec_priv;
88
	int status = 0;
89

90
	pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable");
91

92
	if (!adap || !st)
93 94
		return -EINVAL;

95
	if (enable)
96
		status = st->gate_ctrl(fe, 1);
97
	else
98
		status = st->gate_ctrl(fe, 0);
99

100 101 102
	return status;
}

103
static struct mt2063_config az6007_mt2063_config = {
104
	.tuner_address = 0x60,
105 106 107
	.refclock = 36125000,
};

108
static int __az6007_read(struct usb_device *udev, u8 req, u16 value,
109
			    u16 index, u8 *b, int blen)
110
{
111
	int ret;
112

113 114
	ret = usb_control_msg(udev,
			      usb_rcvctrlpipe(udev, 0),
115 116 117
			      req,
			      USB_TYPE_VENDOR | USB_DIR_IN,
			      value, index, b, blen, 5000);
118
	if (ret < 0) {
119
		pr_warn("usb read operation failed. (%d)\n", ret);
120 121
		return -EIO;
	}
122

123 124 125 126 127 128
	if (az6007_xfer_debug) {
		printk(KERN_DEBUG "az6007: IN  req: %02x, value: %04x, index: %04x\n",
		       req, value, index);
		print_hex_dump_bytes("az6007: payload: ",
				     DUMP_PREFIX_NONE, b, blen);
	}
129 130 131 132

	return ret;
}

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value,
			    u16 index, u8 *b, int blen)
{
	struct az6007_device_state *st = d->priv;
	int ret;

	if (mutex_lock_interruptible(&st->mutex) < 0)
		return -EAGAIN;

	ret = __az6007_read(d->udev, req, value, index, b, blen);

	mutex_unlock(&st->mutex);

	return ret;
}

static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
150 151 152 153
			     u16 index, u8 *b, int blen)
{
	int ret;

154 155 156 157 158 159
	if (az6007_xfer_debug) {
		printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n",
		       req, value, index);
		print_hex_dump_bytes("az6007: payload: ",
				     DUMP_PREFIX_NONE, b, blen);
	}
160

161
	if (blen > 64) {
162 163
		pr_err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
		       blen);
164
		return -EOPNOTSUPP;
165
	}
166

167 168
	ret = usb_control_msg(udev,
			      usb_sndctrlpipe(udev, 0),
169 170 171 172
			      req,
			      USB_TYPE_VENDOR | USB_DIR_OUT,
			      value, index, b, blen, 5000);
	if (ret != blen) {
173
		pr_err("usb write operation failed. (%d)\n", ret);
174
		return -EIO;
175
	}
176

177 178 179
	return 0;
}

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,
			    u16 index, u8 *b, int blen)
{
	struct az6007_device_state *st = d->priv;
	int ret;

	if (mutex_lock_interruptible(&st->mutex) < 0)
		return -EAGAIN;

	ret = __az6007_write(d->udev, req, value, index, b, blen);

	mutex_unlock(&st->mutex);

	return ret;
}

196
static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff)
197
{
198
	struct dvb_usb_device *d = fe_to_d(fe);
199

200
	pr_debug("%s: %s\n", __func__, onoff ? "enable" : "disable");
201

202
	return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
203 204
}

205
#if IS_ENABLED(CONFIG_RC_CORE)
206
/* remote control stuff (does not work with my box) */
207
static int az6007_rc_query(struct dvb_usb_device *d)
208
{
209
	struct az6007_device_state *st = d_to_priv(d);
210
	unsigned code = 0;
211

212
	az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
213

214
	if (st->data[1] == 0x44)
215 216
		return 0;

217 218 219 220 221 222 223 224
	if ((st->data[1] ^ st->data[2]) == 0xff)
		code = st->data[1];
	else
		code = st->data[1] << 8 | st->data[2];

	if ((st->data[3] ^ st->data[4]) == 0xff)
		code = code << 8 | st->data[3];
	else
225
		code = code << 16 | st->data[3] << 8 | st->data[4];
226

227
	rc_keydown(d->rc_dev, code, st->data[5]);
228

229 230 231
	return 0;
}

232 233 234 235 236 237 238 239 240 241 242 243 244 245
static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
{
	pr_debug("Getting az6007 Remote Control properties\n");

	rc->allowed_protos = RC_BIT_NEC;
	rc->query          = az6007_rc_query;
	rc->interval       = 400;

	return 0;
}
#else
	#define az6007_get_rc_config NULL
#endif

246 247 248 249 250
static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
					int slot,
					int address)
{
	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
251
	struct az6007_device_state *state = d_to_priv(d);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

	int ret;
	u8 req;
	u16 value;
	u16 index;
	int blen;
	u8 *b;

	if (slot != 0)
		return -EINVAL;

	b = kmalloc(12, GFP_KERNEL);
	if (!b)
		return -ENOMEM;

	mutex_lock(&state->ca_mutex);

	req = 0xC1;
	value = address;
	index = 0;
	blen = 1;

	ret = az6007_read(d, req, value, index, b, blen);
	if (ret < 0) {
276
		pr_warn("usb in operation failed. (%d)\n", ret);
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
		ret = -EINVAL;
	} else {
		ret = b[0];
	}

	mutex_unlock(&state->ca_mutex);
	kfree(b);
	return ret;
}

static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
					 int slot,
					 int address,
					 u8 value)
{
	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
293
	struct az6007_device_state *state = d_to_priv(d);
294 295 296 297 298 299 300

	int ret;
	u8 req;
	u16 value1;
	u16 index;
	int blen;

301
	pr_debug("%s(), slot %d\n", __func__, slot);
302 303 304 305 306 307 308 309 310 311 312
	if (slot != 0)
		return -EINVAL;

	mutex_lock(&state->ca_mutex);
	req = 0xC2;
	value1 = address;
	index = value;
	blen = 0;

	ret = az6007_write(d, req, value1, index, NULL, blen);
	if (ret != 0)
313
		pr_warn("usb out operation failed. (%d)\n", ret);
314 315 316 317 318 319 320 321 322 323

	mutex_unlock(&state->ca_mutex);
	return ret;
}

static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
				      int slot,
				      u8 address)
{
	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
324
	struct az6007_device_state *state = d_to_priv(d);
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348

	int ret;
	u8 req;
	u16 value;
	u16 index;
	int blen;
	u8 *b;

	if (slot != 0)
		return -EINVAL;

	b = kmalloc(12, GFP_KERNEL);
	if (!b)
		return -ENOMEM;

	mutex_lock(&state->ca_mutex);

	req = 0xC3;
	value = address;
	index = 0;
	blen = 2;

	ret = az6007_read(d, req, value, index, b, blen);
	if (ret < 0) {
349
		pr_warn("usb in operation failed. (%d)\n", ret);
350 351 352
		ret = -EINVAL;
	} else {
		if (b[0] == 0)
353
			pr_warn("Read CI IO error\n");
354 355

		ret = b[1];
356
		pr_debug("read cam data = %x from 0x%x\n", b[1], value);
357 358 359 360 361 362 363 364 365 366 367 368 369
	}

	mutex_unlock(&state->ca_mutex);
	kfree(b);
	return ret;
}

static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
				       int slot,
				       u8 address,
				       u8 value)
{
	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
370
	struct az6007_device_state *state = d_to_priv(d);
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

	int ret;
	u8 req;
	u16 value1;
	u16 index;
	int blen;

	if (slot != 0)
		return -EINVAL;

	mutex_lock(&state->ca_mutex);
	req = 0xC4;
	value1 = address;
	index = value;
	blen = 0;

	ret = az6007_write(d, req, value1, index, NULL, blen);
	if (ret != 0) {
389
		pr_warn("usb out operation failed. (%d)\n", ret);
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
		goto failed;
	}

failed:
	mutex_unlock(&state->ca_mutex);
	return ret;
}

static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
{
	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;

	int ret;
	u8 req;
	u16 value;
	u16 index;
	int blen;
	u8 *b;

	b = kmalloc(12, GFP_KERNEL);
	if (!b)
		return -ENOMEM;

	req = 0xC8;
	value = 0;
	index = 0;
	blen = 1;

	ret = az6007_read(d, req, value, index, b, blen);
	if (ret < 0) {
420
		pr_warn("usb in operation failed. (%d)\n", ret);
421 422 423 424 425 426 427 428 429 430 431
		ret = -EIO;
	} else{
		ret = b[0];
	}
	kfree(b);
	return ret;
}

static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
{
	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
432
	struct az6007_device_state *state = d_to_priv(d);
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448

	int ret, i;
	u8 req;
	u16 value;
	u16 index;
	int blen;

	mutex_lock(&state->ca_mutex);

	req = 0xC6;
	value = 1;
	index = 0;
	blen = 0;

	ret = az6007_write(d, req, value, index, NULL, blen);
	if (ret != 0) {
449
		pr_warn("usb out operation failed. (%d)\n", ret);
450 451 452 453 454 455 456 457 458 459 460
		goto failed;
	}

	msleep(500);
	req = 0xC6;
	value = 0;
	index = 0;
	blen = 0;

	ret = az6007_write(d, req, value, index, NULL, blen);
	if (ret != 0) {
461
		pr_warn("usb out operation failed. (%d)\n", ret);
462 463 464 465 466 467 468
		goto failed;
	}

	for (i = 0; i < 15; i++) {
		msleep(100);

		if (CI_CamReady(ca, slot)) {
469
			pr_debug("CAM Ready\n");
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
			break;
		}
	}
	msleep(5000);

failed:
	mutex_unlock(&state->ca_mutex);
	return ret;
}

static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
{
	return 0;
}

static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
{
	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
488
	struct az6007_device_state *state = d_to_priv(d);
489 490 491 492 493 494 495

	int ret;
	u8 req;
	u16 value;
	u16 index;
	int blen;

496
	pr_debug("%s()\n", __func__);
497 498 499 500 501 502 503 504
	mutex_lock(&state->ca_mutex);
	req = 0xC7;
	value = 1;
	index = 0;
	blen = 0;

	ret = az6007_write(d, req, value, index, NULL, blen);
	if (ret != 0) {
505
		pr_warn("usb out operation failed. (%d)\n", ret);
506 507 508 509 510 511 512 513 514 515 516
		goto failed;
	}

failed:
	mutex_unlock(&state->ca_mutex);
	return ret;
}

static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
{
	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
517
	struct az6007_device_state *state = d_to_priv(d);
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
	int ret;
	u8 req;
	u16 value;
	u16 index;
	int blen;
	u8 *b;

	b = kmalloc(12, GFP_KERNEL);
	if (!b)
		return -ENOMEM;
	mutex_lock(&state->ca_mutex);

	req = 0xC5;
	value = 0;
	index = 0;
	blen = 1;

	ret = az6007_read(d, req, value, index, b, blen);
	if (ret < 0) {
537
		pr_warn("usb in operation failed. (%d)\n", ret);
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
		ret = -EIO;
	} else
		ret = 0;

	if (!ret && b[0] == 1) {
		ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
		      DVB_CA_EN50221_POLL_CAM_READY;
	}

	mutex_unlock(&state->ca_mutex);
	kfree(b);
	return ret;
}


static void az6007_ci_uninit(struct dvb_usb_device *d)
{
	struct az6007_device_state *state;

557
	pr_debug("%s()\n", __func__);
558 559 560 561

	if (NULL == d)
		return;

562
	state = d_to_priv(d);
563 564 565 566 567 568 569 570 571 572 573 574
	if (NULL == state)
		return;

	if (NULL == state->ca.data)
		return;

	dvb_ca_en50221_release(&state->ca);

	memset(&state->ca, 0, sizeof(state->ca));
}


575
static int az6007_ci_init(struct dvb_usb_adapter *adap)
576
{
577 578
	struct dvb_usb_device *d = adap_to_d(adap);
	struct az6007_device_state *state = adap_to_priv(adap);
579 580
	int ret;

581
	pr_debug("%s()\n", __func__);
582 583 584 585 586 587 588 589 590 591 592 593 594

	mutex_init(&state->ca_mutex);
	state->ca.owner			= THIS_MODULE;
	state->ca.read_attribute_mem	= az6007_ci_read_attribute_mem;
	state->ca.write_attribute_mem	= az6007_ci_write_attribute_mem;
	state->ca.read_cam_control	= az6007_ci_read_cam_control;
	state->ca.write_cam_control	= az6007_ci_write_cam_control;
	state->ca.slot_reset		= az6007_ci_slot_reset;
	state->ca.slot_shutdown		= az6007_ci_slot_shutdown;
	state->ca.slot_ts_enable	= az6007_ci_slot_ts_enable;
	state->ca.poll_slot_status	= az6007_ci_poll_slot_status;
	state->ca.data			= d;

595
	ret = dvb_ca_en50221_init(&adap->dvb_adap,
596 597 598 599
				  &state->ca,
				  0, /* flags */
				  1);/* n_slots */
	if (ret != 0) {
600
		pr_err("Cannot initialize CI: Error %d.\n", ret);
601 602 603 604
		memset(&state->ca, 0, sizeof(state->ca));
		return ret;
	}

605
	pr_debug("CI initialized.\n");
606 607 608 609

	return 0;
}

610
static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
611
{
612 613
	struct dvb_usb_device *d = adap_to_d(adap);
	struct az6007_device_state *st = adap_to_priv(adap);
614
	int ret;
615 616

	ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);
A
Alan Cox 已提交
617
	memcpy(mac, st->data, 6);
618

619
	if (ret > 0)
620
		pr_debug("%s: mac is %pM\n", __func__, mac);
621 622 623

	return ret;
}
624

625 626
static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
{
627 628
	struct az6007_device_state *st = adap_to_priv(adap);
	struct dvb_usb_device *d = adap_to_d(adap);
629

630
	pr_debug("attaching demod drxk\n");
631

632 633 634
	adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk,
				 &d->i2c_adap);
	if (!adap->fe[0])
635
		return -EINVAL;
636

637 638 639
	adap->fe[0]->sec_priv = adap;
	st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
	adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
640

641 642
	az6007_ci_init(adap);

643 644 645
	return 0;
}

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
static int az6007_cablestar_hdci_frontend_attach(struct dvb_usb_adapter *adap)
{
	struct az6007_device_state *st = adap_to_priv(adap);
	struct dvb_usb_device *d = adap_to_d(adap);

	pr_debug("attaching demod drxk\n");

	adap->fe[0] = dvb_attach(drxk_attach, &cablestar_hdci_drxk,
				 &d->i2c_adap);
	if (!adap->fe[0])
		return -EINVAL;

	adap->fe[0]->sec_priv = adap;
	st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
	adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;

	az6007_ci_init(adap);

	return 0;
}

667 668
static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
{
669 670 671
	struct dvb_usb_device *d = adap_to_d(adap);

	pr_debug("attaching tuner mt2063\n");
672

673
	/* Attach mt2063 to DVB-C frontend */
674 675 676
	if (adap->fe[0]->ops.i2c_gate_ctrl)
		adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1);
	if (!dvb_attach(mt2063_attach, adap->fe[0],
677
			&az6007_mt2063_config,
678
			&d->i2c_adap))
679
		return -EINVAL;
680

681 682
	if (adap->fe[0]->ops.i2c_gate_ctrl)
		adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0);
683

684 685 686
	return 0;
}

687
static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
688
{
689
	struct az6007_device_state *state = d_to_priv(d);
690 691
	int ret;

692
	pr_debug("%s()\n", __func__);
693

694 695
	if (!state->warm) {
		mutex_init(&state->mutex);
696

697
		ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);
698 699 700
		if (ret < 0)
			return ret;
		msleep(60);
701
		ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
702 703 704
		if (ret < 0)
			return ret;
		msleep(100);
705
		ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0);
706 707 708
		if (ret < 0)
			return ret;
		msleep(20);
709
		ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
710 711 712 713
		if (ret < 0)
			return ret;

		msleep(400);
714
		ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0);
715 716
		if (ret < 0)
			return ret;
717
		msleep(150);
718
		ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0);
719 720
		if (ret < 0)
			return ret;
721
		msleep(430);
722
		ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
723 724
		if (ret < 0)
			return ret;
725

726
		state->warm = true;
727

728 729
		return 0;
	}
730

731 732 733
	if (!onoff)
		return 0;

734 735
	az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
	az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0);
736 737 738 739

	return 0;
}

740
/* I2C */
741 742
static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
			   int num)
743 744
{
	struct dvb_usb_device *d = i2c_get_adapdata(adap);
745
	struct az6007_device_state *st = d_to_priv(d);
746 747
	int i, j, len;
	int ret = 0;
748 749 750
	u16 index;
	u16 value;
	int length;
751
	u8 req, addr;
752

753
	if (mutex_lock_interruptible(&st->mutex) < 0)
754 755
		return -EAGAIN;

756 757 758 759
	for (i = 0; i < num; i++) {
		addr = msgs[i].addr << 1;
		if (((i + 1) < num)
		    && (msgs[i].len == 1)
760
		    && ((msgs[i].flags & I2C_M_RD) != I2C_M_RD)
761 762 763 764 765 766 767
		    && (msgs[i + 1].flags & I2C_M_RD)
		    && (msgs[i].addr == msgs[i + 1].addr)) {
			/*
			 * A write + read xfer for the same address, where
			 * the first xfer has just 1 byte length.
			 * Need to join both into one operation
			 */
768 769
			if (az6007_xfer_debug)
				printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n",
770
				       addr, msgs[i].len, msgs[i + 1].len);
771
			req = AZ6007_I2C_RD;
772 773
			index = msgs[i].buf[0];
			value = addr | (1 << 8);
774 775
			length = 6 + msgs[i + 1].len;
			len = msgs[i + 1].len;
776 777
			ret = __az6007_read(d->udev, req, value, index,
					    st->data, length);
778
			if (ret >= len) {
779
				for (j = 0; j < len; j++)
780
					msgs[i + 1].buf[j] = st->data[j + 5];
781 782 783 784 785
			} else
				ret = -EIO;
			i++;
		} else if (!(msgs[i].flags & I2C_M_RD)) {
			/* write bytes */
786 787
			if (az6007_xfer_debug)
				printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n",
788
				       addr, msgs[i].len);
789
			req = AZ6007_I2C_WR;
790 791 792 793
			index = msgs[i].buf[0];
			value = addr | (1 << 8);
			length = msgs[i].len - 1;
			len = msgs[i].len - 1;
794
			for (j = 0; j < len; j++)
795
				st->data[j] = msgs[i].buf[j + 1];
796 797
			ret =  __az6007_write(d->udev, req, value, index,
					      st->data, length);
798 799
		} else {
			/* read bytes */
800 801
			if (az6007_xfer_debug)
				printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n",
802
				       addr, msgs[i].len);
803
			req = AZ6007_I2C_RD;
804 805 806 807
			index = msgs[i].buf[0];
			value = addr;
			length = msgs[i].len + 6;
			len = msgs[i].len;
808 809
			ret = __az6007_read(d->udev, req, value, index,
					    st->data, length);
810
			for (j = 0; j < len; j++)
811
				msgs[i].buf[j] = st->data[j + 5];
812
		}
813 814
		if (ret < 0)
			goto err;
815
	}
816
err:
817
	mutex_unlock(&st->mutex);
818 819

	if (ret < 0) {
820
		pr_info("%s ERROR: %i\n", __func__, ret);
821 822 823
		return ret;
	}
	return num;
824 825 826 827 828 829 830 831
}

static u32 az6007_i2c_func(struct i2c_adapter *adapter)
{
	return I2C_FUNC_I2C;
}

static struct i2c_algorithm az6007_i2c_algo = {
832
	.master_xfer = az6007_i2c_xfer,
833 834 835
	.functionality = az6007_i2c_func,
};

836
static int az6007_identify_state(struct dvb_usb_device *d, const char **name)
837
{
838
	int ret;
839 840
	u8 *mac;

841 842
	pr_debug("Identifying az6007 state\n");

843 844 845
	mac = kmalloc(6, GFP_ATOMIC);
	if (!mac)
		return -ENOMEM;
846

847
	/* Try to read the mac address */
848
	ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6);
849
	if (ret == 6)
850
		ret = WARM;
851
	else
852
		ret = COLD;
853

854 855
	kfree(mac);

856 857 858 859
	if (ret == COLD) {
		__az6007_write(d->udev, 0x09, 1, 0, NULL, 0);
		__az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
		__az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
860 861
	}

862 863 864
	pr_debug("Device is on %s state\n",
		 ret == WARM ? "warm" : "cold");
	return ret;
865 866
}

867 868 869 870
static void az6007_usb_disconnect(struct usb_interface *intf)
{
	struct dvb_usb_device *d = usb_get_intfdata(intf);
	az6007_ci_uninit(d);
871
	dvb_usbv2_disconnect(intf);
872 873
}

874 875 876 877
static int az6007_download_firmware(struct dvb_usb_device *d,
	const struct firmware *fw)
{
	pr_debug("Loading az6007 firmware\n");
878

879
	return cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
880
}
881

882 883 884 885 886 887 888
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties az6007_props = {
	.driver_name         = KBUILD_MODNAME,
	.owner               = THIS_MODULE,
	.firmware            = AZ6007_FIRMWARE,

	.adapter_nr          = adapter_nr,
889
	.size_of_priv        = sizeof(struct az6007_device_state),
890 891 892 893 894 895 896
	.i2c_algo            = &az6007_i2c_algo,
	.tuner_attach        = az6007_tuner_attach,
	.frontend_attach     = az6007_frontend_attach,
	.streaming_ctrl      = az6007_streaming_ctrl,
	.get_rc_config       = az6007_get_rc_config,
	.read_mac_address    = az6007_read_mac_addr,
	.download_firmware   = az6007_download_firmware,
897
	.identify_state	     = az6007_identify_state,
898 899 900 901
	.power_ctrl          = az6007_power_ctrl,
	.num_adapters        = 1,
	.adapter             = {
		{ .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
902 903
	}
};
904

905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
static struct dvb_usb_device_properties az6007_cablestar_hdci_props = {
	.driver_name         = KBUILD_MODNAME,
	.owner               = THIS_MODULE,
	.firmware            = AZ6007_FIRMWARE,

	.adapter_nr          = adapter_nr,
	.size_of_priv        = sizeof(struct az6007_device_state),
	.i2c_algo            = &az6007_i2c_algo,
	.tuner_attach        = az6007_tuner_attach,
	.frontend_attach     = az6007_cablestar_hdci_frontend_attach,
	.streaming_ctrl      = az6007_streaming_ctrl,
/* ditch get_rc_config as it can't work (TS35 remote, I believe it's rc5) */
	.get_rc_config       = NULL,
	.read_mac_address    = az6007_read_mac_addr,
	.download_firmware   = az6007_download_firmware,
	.identify_state	     = az6007_identify_state,
	.power_ctrl          = az6007_power_ctrl,
	.num_adapters        = 1,
	.adapter             = {
		{ .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
	}
};

928 929 930 931 932 933 934
static struct usb_device_id az6007_usb_table[] = {
	{DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
		&az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
	{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7,
		&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
	{DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
		&az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
935 936
	{DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI,
		&az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)},
937 938 939 940 941
	{0},
};

MODULE_DEVICE_TABLE(usb, az6007_usb_table);

942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
static int az6007_suspend(struct usb_interface *intf, pm_message_t msg)
{
	struct dvb_usb_device *d = usb_get_intfdata(intf);

	az6007_ci_uninit(d);
	return dvb_usbv2_suspend(intf, msg);
}

static int az6007_resume(struct usb_interface *intf)
{
	struct dvb_usb_device *d = usb_get_intfdata(intf);
	struct dvb_usb_adapter *adap = &d->adapter[0];

	az6007_ci_init(adap);
	return dvb_usbv2_resume(intf);
}

959 960
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver az6007_usb_driver = {
961
	.name		= KBUILD_MODNAME,
962
	.id_table	= az6007_usb_table,
963 964 965 966
	.probe		= dvb_usbv2_probe,
	.disconnect	= az6007_usb_disconnect,
	.no_dynamic_id	= 1,
	.soft_unbind	= 1,
967 968 969 970 971 972
	/*
	 * FIXME: need to implement reset_resume, likely with
	 * dvb-usb-v2 core support
	 */
	.suspend	= az6007_suspend,
	.resume		= az6007_resume,
973 974
};

975
module_usb_driver(az6007_usb_driver);
976 977

MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
978
MODULE_AUTHOR("Mauro Carvalho Chehab");
979
MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
980
MODULE_VERSION("2.0");
981
MODULE_LICENSE("GPL");
982
MODULE_FIRMWARE(AZ6007_FIRMWARE);