993 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones4 *5 * Copyright (c) Henry Wang <Henry.wang@AzureWave.com>6 *7 * This driver was made publicly available by Terratec, at:8 * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz9 * The original driver's license is GPL, as declared with MODULE_LICENSE()10 *11 * Copyright (c) 2010-2012 Mauro Carvalho Chehab12 * Driver modified by in order to work with upstream drxk driver, and13 * tons of bugs got fixed, and converted to use dvb-usb-v2.14 */15 16#include "drxk.h"17#include "mt2063.h"18#include <media/dvb_ca_en50221.h>19#include "dvb_usb.h"20#include "cypress_firmware.h"21 22#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw"23 24static int az6007_xfer_debug;25module_param_named(xfer_debug, az6007_xfer_debug, int, 0644);26MODULE_PARM_DESC(xfer_debug, "Enable xfer debug");27 28DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);29 30/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/31 32#define FX2_OED 0xb533#define AZ6007_READ_DATA 0xb734#define AZ6007_I2C_RD 0xb935#define AZ6007_POWER 0xbc36#define AZ6007_I2C_WR 0xbd37#define FX2_SCON1 0xc038#define AZ6007_TS_THROUGH 0xc739#define AZ6007_READ_IR 0xb440 41struct az6007_device_state {42 struct mutex mutex;43 struct mutex ca_mutex;44 struct dvb_ca_en50221 ca;45 unsigned warm:1;46 int (*gate_ctrl) (struct dvb_frontend *, int);47 unsigned char data[4096];48};49 50static struct drxk_config terratec_h7_drxk = {51 .adr = 0x29,52 .parallel_ts = true,53 .dynamic_clk = true,54 .single_master = true,55 .enable_merr_cfg = true,56 .no_i2c_bridge = false,57 .chunk_size = 64,58 .mpeg_out_clk_strength = 0x02,59 .qam_demod_parameter_count = 2,60 .microcode_name = "dvb-usb-terratec-h7-drxk.fw",61};62 63static struct drxk_config cablestar_hdci_drxk = {64 .adr = 0x29,65 .parallel_ts = true,66 .dynamic_clk = true,67 .single_master = true,68 .enable_merr_cfg = true,69 .no_i2c_bridge = false,70 .chunk_size = 64,71 .mpeg_out_clk_strength = 0x02,72 .qam_demod_parameter_count = 2,73 .microcode_name = "dvb-usb-technisat-cablestar-hdci-drxk.fw",74};75 76static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)77{78 struct az6007_device_state *st = fe_to_priv(fe);79 struct dvb_usb_adapter *adap = fe->sec_priv;80 int status = 0;81 82 pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable");83 84 if (!adap || !st)85 return -EINVAL;86 87 if (enable)88 status = st->gate_ctrl(fe, 1);89 else90 status = st->gate_ctrl(fe, 0);91 92 return status;93}94 95static struct mt2063_config az6007_mt2063_config = {96 .tuner_address = 0x60,97 .refclock = 36125000,98};99 100static int __az6007_read(struct usb_device *udev, u8 req, u16 value,101 u16 index, u8 *b, int blen)102{103 int ret;104 105 ret = usb_control_msg(udev,106 usb_rcvctrlpipe(udev, 0),107 req,108 USB_TYPE_VENDOR | USB_DIR_IN,109 value, index, b, blen, 5000);110 if (ret < 0) {111 pr_warn("usb read operation failed. (%d)\n", ret);112 return -EIO;113 }114 115 if (az6007_xfer_debug) {116 printk(KERN_DEBUG "az6007: IN req: %02x, value: %04x, index: %04x\n",117 req, value, index);118 print_hex_dump_bytes("az6007: payload: ",119 DUMP_PREFIX_NONE, b, blen);120 }121 122 return ret;123}124 125static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value,126 u16 index, u8 *b, int blen)127{128 struct az6007_device_state *st = d->priv;129 int ret;130 131 if (mutex_lock_interruptible(&st->mutex) < 0)132 return -EAGAIN;133 134 ret = __az6007_read(d->udev, req, value, index, b, blen);135 136 mutex_unlock(&st->mutex);137 138 return ret;139}140 141static int __az6007_write(struct usb_device *udev, u8 req, u16 value,142 u16 index, u8 *b, int blen)143{144 int ret;145 146 if (az6007_xfer_debug) {147 printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n",148 req, value, index);149 print_hex_dump_bytes("az6007: payload: ",150 DUMP_PREFIX_NONE, b, blen);151 }152 153 if (blen > 64) {154 pr_err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",155 blen);156 return -EOPNOTSUPP;157 }158 159 ret = usb_control_msg(udev,160 usb_sndctrlpipe(udev, 0),161 req,162 USB_TYPE_VENDOR | USB_DIR_OUT,163 value, index, b, blen, 5000);164 if (ret != blen) {165 pr_err("usb write operation failed. (%d)\n", ret);166 return -EIO;167 }168 169 return 0;170}171 172static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,173 u16 index, u8 *b, int blen)174{175 struct az6007_device_state *st = d->priv;176 int ret;177 178 if (mutex_lock_interruptible(&st->mutex) < 0)179 return -EAGAIN;180 181 ret = __az6007_write(d->udev, req, value, index, b, blen);182 183 mutex_unlock(&st->mutex);184 185 return ret;186}187 188static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff)189{190 struct dvb_usb_device *d = fe_to_d(fe);191 192 pr_debug("%s: %s\n", __func__, onoff ? "enable" : "disable");193 194 return az6007_write(d, 0xbc, onoff, 0, NULL, 0);195}196 197#if IS_ENABLED(CONFIG_RC_CORE)198/* remote control stuff (does not work with my box) */199static int az6007_rc_query(struct dvb_usb_device *d)200{201 struct az6007_device_state *st = d_to_priv(d);202 unsigned code;203 enum rc_proto proto;204 205 if (az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10) < 0)206 return -EIO;207 208 if (st->data[1] == 0x44)209 return 0;210 211 if ((st->data[3] ^ st->data[4]) == 0xff) {212 if ((st->data[1] ^ st->data[2]) == 0xff) {213 code = RC_SCANCODE_NEC(st->data[1], st->data[3]);214 proto = RC_PROTO_NEC;215 } else {216 code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2],217 st->data[3]);218 proto = RC_PROTO_NECX;219 }220 } else {221 code = RC_SCANCODE_NEC32(st->data[1] << 24 |222 st->data[2] << 16 |223 st->data[3] << 8 |224 st->data[4]);225 proto = RC_PROTO_NEC32;226 }227 228 rc_keydown(d->rc_dev, proto, code, st->data[5]);229 230 return 0;231}232 233static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)234{235 pr_debug("Getting az6007 Remote Control properties\n");236 237 rc->allowed_protos = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX |238 RC_PROTO_BIT_NEC32;239 rc->query = az6007_rc_query;240 rc->interval = 400;241 242 return 0;243}244#else245 #define az6007_get_rc_config NULL246#endif247 248static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,249 int slot,250 int address)251{252 struct dvb_usb_device *d = ca->data;253 struct az6007_device_state *state = d_to_priv(d);254 255 int ret;256 u8 req;257 u16 value;258 u16 index;259 int blen;260 u8 *b;261 262 if (slot != 0)263 return -EINVAL;264 265 b = kmalloc(12, GFP_KERNEL);266 if (!b)267 return -ENOMEM;268 269 mutex_lock(&state->ca_mutex);270 271 req = 0xC1;272 value = address;273 index = 0;274 blen = 1;275 276 ret = az6007_read(d, req, value, index, b, blen);277 if (ret < 0) {278 pr_warn("usb in operation failed. (%d)\n", ret);279 ret = -EINVAL;280 } else {281 ret = b[0];282 }283 284 mutex_unlock(&state->ca_mutex);285 kfree(b);286 return ret;287}288 289static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,290 int slot,291 int address,292 u8 value)293{294 struct dvb_usb_device *d = ca->data;295 struct az6007_device_state *state = d_to_priv(d);296 297 int ret;298 u8 req;299 u16 value1;300 u16 index;301 int blen;302 303 pr_debug("%s(), slot %d\n", __func__, slot);304 if (slot != 0)305 return -EINVAL;306 307 mutex_lock(&state->ca_mutex);308 req = 0xC2;309 value1 = address;310 index = value;311 blen = 0;312 313 ret = az6007_write(d, req, value1, index, NULL, blen);314 if (ret != 0)315 pr_warn("usb out operation failed. (%d)\n", ret);316 317 mutex_unlock(&state->ca_mutex);318 return ret;319}320 321static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,322 int slot,323 u8 address)324{325 struct dvb_usb_device *d = ca->data;326 struct az6007_device_state *state = d_to_priv(d);327 328 int ret;329 u8 req;330 u16 value;331 u16 index;332 int blen;333 u8 *b;334 335 if (slot != 0)336 return -EINVAL;337 338 b = kmalloc(12, GFP_KERNEL);339 if (!b)340 return -ENOMEM;341 342 mutex_lock(&state->ca_mutex);343 344 req = 0xC3;345 value = address;346 index = 0;347 blen = 2;348 349 ret = az6007_read(d, req, value, index, b, blen);350 if (ret < 0) {351 pr_warn("usb in operation failed. (%d)\n", ret);352 ret = -EINVAL;353 } else {354 if (b[0] == 0)355 pr_warn("Read CI IO error\n");356 357 ret = b[1];358 pr_debug("read cam data = %x from 0x%x\n", b[1], value);359 }360 361 mutex_unlock(&state->ca_mutex);362 kfree(b);363 return ret;364}365 366static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,367 int slot,368 u8 address,369 u8 value)370{371 struct dvb_usb_device *d = ca->data;372 struct az6007_device_state *state = d_to_priv(d);373 374 int ret;375 u8 req;376 u16 value1;377 u16 index;378 int blen;379 380 if (slot != 0)381 return -EINVAL;382 383 mutex_lock(&state->ca_mutex);384 req = 0xC4;385 value1 = address;386 index = value;387 blen = 0;388 389 ret = az6007_write(d, req, value1, index, NULL, blen);390 if (ret != 0) {391 pr_warn("usb out operation failed. (%d)\n", ret);392 goto failed;393 }394 395failed:396 mutex_unlock(&state->ca_mutex);397 return ret;398}399 400static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)401{402 struct dvb_usb_device *d = ca->data;403 404 int ret;405 u8 req;406 u16 value;407 u16 index;408 int blen;409 u8 *b;410 411 b = kmalloc(12, GFP_KERNEL);412 if (!b)413 return -ENOMEM;414 415 req = 0xC8;416 value = 0;417 index = 0;418 blen = 1;419 420 ret = az6007_read(d, req, value, index, b, blen);421 if (ret < 0) {422 pr_warn("usb in operation failed. (%d)\n", ret);423 ret = -EIO;424 } else{425 ret = b[0];426 }427 kfree(b);428 return ret;429}430 431static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)432{433 struct dvb_usb_device *d = ca->data;434 struct az6007_device_state *state = d_to_priv(d);435 436 int ret, i;437 u8 req;438 u16 value;439 u16 index;440 int blen;441 442 mutex_lock(&state->ca_mutex);443 444 req = 0xC6;445 value = 1;446 index = 0;447 blen = 0;448 449 ret = az6007_write(d, req, value, index, NULL, blen);450 if (ret != 0) {451 pr_warn("usb out operation failed. (%d)\n", ret);452 goto failed;453 }454 455 msleep(500);456 req = 0xC6;457 value = 0;458 index = 0;459 blen = 0;460 461 ret = az6007_write(d, req, value, index, NULL, blen);462 if (ret != 0) {463 pr_warn("usb out operation failed. (%d)\n", ret);464 goto failed;465 }466 467 for (i = 0; i < 15; i++) {468 msleep(100);469 470 if (CI_CamReady(ca, slot)) {471 pr_debug("CAM Ready\n");472 break;473 }474 }475 msleep(5000);476 477failed:478 mutex_unlock(&state->ca_mutex);479 return ret;480}481 482static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)483{484 return 0;485}486 487static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)488{489 struct dvb_usb_device *d = ca->data;490 struct az6007_device_state *state = d_to_priv(d);491 492 int ret;493 u8 req;494 u16 value;495 u16 index;496 int blen;497 498 pr_debug("%s()\n", __func__);499 mutex_lock(&state->ca_mutex);500 req = 0xC7;501 value = 1;502 index = 0;503 blen = 0;504 505 ret = az6007_write(d, req, value, index, NULL, blen);506 if (ret != 0) {507 pr_warn("usb out operation failed. (%d)\n", ret);508 goto failed;509 }510 511failed:512 mutex_unlock(&state->ca_mutex);513 return ret;514}515 516static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)517{518 struct dvb_usb_device *d = ca->data;519 struct az6007_device_state *state = d_to_priv(d);520 int ret;521 u8 req;522 u16 value;523 u16 index;524 int blen;525 u8 *b;526 527 b = kmalloc(12, GFP_KERNEL);528 if (!b)529 return -ENOMEM;530 mutex_lock(&state->ca_mutex);531 532 req = 0xC5;533 value = 0;534 index = 0;535 blen = 1;536 537 ret = az6007_read(d, req, value, index, b, blen);538 if (ret < 0) {539 pr_warn("usb in operation failed. (%d)\n", ret);540 ret = -EIO;541 } else542 ret = 0;543 544 if (!ret && b[0] == 1) {545 ret = DVB_CA_EN50221_POLL_CAM_PRESENT |546 DVB_CA_EN50221_POLL_CAM_READY;547 }548 549 mutex_unlock(&state->ca_mutex);550 kfree(b);551 return ret;552}553 554 555static void az6007_ci_uninit(struct dvb_usb_device *d)556{557 struct az6007_device_state *state;558 559 pr_debug("%s()\n", __func__);560 561 if (NULL == d)562 return;563 564 state = d_to_priv(d);565 if (NULL == state)566 return;567 568 if (NULL == state->ca.data)569 return;570 571 dvb_ca_en50221_release(&state->ca);572 573 memset(&state->ca, 0, sizeof(state->ca));574}575 576 577static int az6007_ci_init(struct dvb_usb_adapter *adap)578{579 struct dvb_usb_device *d = adap_to_d(adap);580 struct az6007_device_state *state = adap_to_priv(adap);581 int ret;582 583 pr_debug("%s()\n", __func__);584 585 mutex_init(&state->ca_mutex);586 state->ca.owner = THIS_MODULE;587 state->ca.read_attribute_mem = az6007_ci_read_attribute_mem;588 state->ca.write_attribute_mem = az6007_ci_write_attribute_mem;589 state->ca.read_cam_control = az6007_ci_read_cam_control;590 state->ca.write_cam_control = az6007_ci_write_cam_control;591 state->ca.slot_reset = az6007_ci_slot_reset;592 state->ca.slot_shutdown = az6007_ci_slot_shutdown;593 state->ca.slot_ts_enable = az6007_ci_slot_ts_enable;594 state->ca.poll_slot_status = az6007_ci_poll_slot_status;595 state->ca.data = d;596 597 ret = dvb_ca_en50221_init(&adap->dvb_adap,598 &state->ca,599 0, /* flags */600 1);/* n_slots */601 if (ret != 0) {602 pr_err("Cannot initialize CI: Error %d.\n", ret);603 memset(&state->ca, 0, sizeof(state->ca));604 return ret;605 }606 607 pr_debug("CI initialized.\n");608 609 return 0;610}611 612static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])613{614 struct dvb_usb_device *d = adap_to_d(adap);615 struct az6007_device_state *st = adap_to_priv(adap);616 int ret;617 618 ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);619 memcpy(mac, st->data, 6);620 621 if (ret > 0)622 pr_debug("%s: mac is %pM\n", __func__, mac);623 624 return ret;625}626 627static int az6007_frontend_attach(struct dvb_usb_adapter *adap)628{629 struct az6007_device_state *st = adap_to_priv(adap);630 struct dvb_usb_device *d = adap_to_d(adap);631 632 pr_debug("attaching demod drxk\n");633 634 adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk,635 &d->i2c_adap);636 if (!adap->fe[0])637 return -EINVAL;638 639 adap->fe[0]->sec_priv = adap;640 st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;641 adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;642 643 az6007_ci_init(adap);644 645 return 0;646}647 648static int az6007_cablestar_hdci_frontend_attach(struct dvb_usb_adapter *adap)649{650 struct az6007_device_state *st = adap_to_priv(adap);651 struct dvb_usb_device *d = adap_to_d(adap);652 653 pr_debug("attaching demod drxk\n");654 655 adap->fe[0] = dvb_attach(drxk_attach, &cablestar_hdci_drxk,656 &d->i2c_adap);657 if (!adap->fe[0])658 return -EINVAL;659 660 adap->fe[0]->sec_priv = adap;661 st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;662 adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;663 664 az6007_ci_init(adap);665 666 return 0;667}668 669static int az6007_tuner_attach(struct dvb_usb_adapter *adap)670{671 struct dvb_usb_device *d = adap_to_d(adap);672 673 pr_debug("attaching tuner mt2063\n");674 675 /* Attach mt2063 to DVB-C frontend */676 if (adap->fe[0]->ops.i2c_gate_ctrl)677 adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1);678 if (!dvb_attach(mt2063_attach, adap->fe[0],679 &az6007_mt2063_config,680 &d->i2c_adap))681 return -EINVAL;682 683 if (adap->fe[0]->ops.i2c_gate_ctrl)684 adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0);685 686 return 0;687}688 689static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)690{691 struct az6007_device_state *state = d_to_priv(d);692 int ret;693 694 pr_debug("%s()\n", __func__);695 696 if (!state->warm) {697 mutex_init(&state->mutex);698 699 ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);700 if (ret < 0)701 return ret;702 msleep(60);703 ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);704 if (ret < 0)705 return ret;706 msleep(100);707 ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0);708 if (ret < 0)709 return ret;710 msleep(20);711 ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);712 if (ret < 0)713 return ret;714 715 msleep(400);716 ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0);717 if (ret < 0)718 return ret;719 msleep(150);720 ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0);721 if (ret < 0)722 return ret;723 msleep(430);724 ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);725 if (ret < 0)726 return ret;727 728 state->warm = true;729 730 return 0;731 }732 733 if (!onoff)734 return 0;735 736 az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);737 az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0);738 739 return 0;740}741 742/* I2C */743static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],744 int num)745{746 struct dvb_usb_device *d = i2c_get_adapdata(adap);747 struct az6007_device_state *st = d_to_priv(d);748 int i, j, len;749 int ret = 0;750 u16 index;751 u16 value;752 int length;753 u8 req, addr;754 755 if (mutex_lock_interruptible(&st->mutex) < 0)756 return -EAGAIN;757 758 for (i = 0; i < num; i++) {759 addr = msgs[i].addr << 1;760 if (((i + 1) < num)761 && (msgs[i].len == 1)762 && ((msgs[i].flags & I2C_M_RD) != I2C_M_RD)763 && (msgs[i + 1].flags & I2C_M_RD)764 && (msgs[i].addr == msgs[i + 1].addr)) {765 /*766 * A write + read xfer for the same address, where767 * the first xfer has just 1 byte length.768 * Need to join both into one operation769 */770 if (az6007_xfer_debug)771 printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n",772 addr, msgs[i].len, msgs[i + 1].len);773 req = AZ6007_I2C_RD;774 index = msgs[i].buf[0];775 value = addr | (1 << 8);776 length = 6 + msgs[i + 1].len;777 len = msgs[i + 1].len;778 ret = __az6007_read(d->udev, req, value, index,779 st->data, length);780 if (ret >= len) {781 for (j = 0; j < len; j++)782 msgs[i + 1].buf[j] = st->data[j + 5];783 } else784 ret = -EIO;785 i++;786 } else if (!(msgs[i].flags & I2C_M_RD)) {787 /* write bytes */788 if (az6007_xfer_debug)789 printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n",790 addr, msgs[i].len);791 if (msgs[i].len < 1) {792 ret = -EIO;793 goto err;794 }795 req = AZ6007_I2C_WR;796 index = msgs[i].buf[0];797 value = addr | (1 << 8);798 length = msgs[i].len - 1;799 len = msgs[i].len - 1;800 for (j = 0; j < len; j++)801 st->data[j] = msgs[i].buf[j + 1];802 ret = __az6007_write(d->udev, req, value, index,803 st->data, length);804 } else {805 /* read bytes */806 if (az6007_xfer_debug)807 printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n",808 addr, msgs[i].len);809 if (msgs[i].len < 1) {810 ret = -EIO;811 goto err;812 }813 req = AZ6007_I2C_RD;814 index = msgs[i].buf[0];815 value = addr;816 length = msgs[i].len + 6;817 len = msgs[i].len;818 ret = __az6007_read(d->udev, req, value, index,819 st->data, length);820 for (j = 0; j < len; j++)821 msgs[i].buf[j] = st->data[j + 5];822 }823 if (ret < 0)824 goto err;825 }826err:827 mutex_unlock(&st->mutex);828 829 if (ret < 0) {830 pr_info("%s ERROR: %i\n", __func__, ret);831 return ret;832 }833 return num;834}835 836static u32 az6007_i2c_func(struct i2c_adapter *adapter)837{838 return I2C_FUNC_I2C;839}840 841static struct i2c_algorithm az6007_i2c_algo = {842 .master_xfer = az6007_i2c_xfer,843 .functionality = az6007_i2c_func,844};845 846static int az6007_identify_state(struct dvb_usb_device *d, const char **name)847{848 int ret;849 u8 *mac;850 851 pr_debug("Identifying az6007 state\n");852 853 mac = kmalloc(6, GFP_ATOMIC);854 if (!mac)855 return -ENOMEM;856 857 /* Try to read the mac address */858 ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6);859 if (ret == 6)860 ret = WARM;861 else862 ret = COLD;863 864 kfree(mac);865 866 if (ret == COLD) {867 __az6007_write(d->udev, 0x09, 1, 0, NULL, 0);868 __az6007_write(d->udev, 0x00, 0, 0, NULL, 0);869 __az6007_write(d->udev, 0x00, 0, 0, NULL, 0);870 }871 872 pr_debug("Device is on %s state\n",873 ret == WARM ? "warm" : "cold");874 return ret;875}876 877static void az6007_usb_disconnect(struct usb_interface *intf)878{879 struct dvb_usb_device *d = usb_get_intfdata(intf);880 az6007_ci_uninit(d);881 dvb_usbv2_disconnect(intf);882}883 884static int az6007_download_firmware(struct dvb_usb_device *d,885 const struct firmware *fw)886{887 pr_debug("Loading az6007 firmware\n");888 889 return cypress_load_firmware(d->udev, fw, CYPRESS_FX2);890}891 892/* DVB USB Driver stuff */893static struct dvb_usb_device_properties az6007_props = {894 .driver_name = KBUILD_MODNAME,895 .owner = THIS_MODULE,896 .firmware = AZ6007_FIRMWARE,897 898 .adapter_nr = adapter_nr,899 .size_of_priv = sizeof(struct az6007_device_state),900 .i2c_algo = &az6007_i2c_algo,901 .tuner_attach = az6007_tuner_attach,902 .frontend_attach = az6007_frontend_attach,903 .streaming_ctrl = az6007_streaming_ctrl,904 .get_rc_config = az6007_get_rc_config,905 .read_mac_address = az6007_read_mac_addr,906 .download_firmware = az6007_download_firmware,907 .identify_state = az6007_identify_state,908 .power_ctrl = az6007_power_ctrl,909 .num_adapters = 1,910 .adapter = {911 { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }912 }913};914 915static struct dvb_usb_device_properties az6007_cablestar_hdci_props = {916 .driver_name = KBUILD_MODNAME,917 .owner = THIS_MODULE,918 .firmware = AZ6007_FIRMWARE,919 920 .adapter_nr = adapter_nr,921 .size_of_priv = sizeof(struct az6007_device_state),922 .i2c_algo = &az6007_i2c_algo,923 .tuner_attach = az6007_tuner_attach,924 .frontend_attach = az6007_cablestar_hdci_frontend_attach,925 .streaming_ctrl = az6007_streaming_ctrl,926/* ditch get_rc_config as it can't work (TS35 remote, I believe it's rc5) */927 .get_rc_config = NULL,928 .read_mac_address = az6007_read_mac_addr,929 .download_firmware = az6007_download_firmware,930 .identify_state = az6007_identify_state,931 .power_ctrl = az6007_power_ctrl,932 .num_adapters = 1,933 .adapter = {934 { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }935 }936};937 938static const struct usb_device_id az6007_usb_table[] = {939 {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,940 &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},941 {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7,942 &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},943 {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,944 &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},945 {DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI,946 &az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)},947 {0},948};949 950MODULE_DEVICE_TABLE(usb, az6007_usb_table);951 952static int az6007_suspend(struct usb_interface *intf, pm_message_t msg)953{954 struct dvb_usb_device *d = usb_get_intfdata(intf);955 956 az6007_ci_uninit(d);957 return dvb_usbv2_suspend(intf, msg);958}959 960static int az6007_resume(struct usb_interface *intf)961{962 struct dvb_usb_device *d = usb_get_intfdata(intf);963 struct dvb_usb_adapter *adap = &d->adapter[0];964 965 az6007_ci_init(adap);966 return dvb_usbv2_resume(intf);967}968 969/* usb specific object needed to register this driver with the usb subsystem */970static struct usb_driver az6007_usb_driver = {971 .name = KBUILD_MODNAME,972 .id_table = az6007_usb_table,973 .probe = dvb_usbv2_probe,974 .disconnect = az6007_usb_disconnect,975 .no_dynamic_id = 1,976 .soft_unbind = 1,977 /*978 * FIXME: need to implement reset_resume, likely with979 * dvb-usb-v2 core support980 */981 .suspend = az6007_suspend,982 .resume = az6007_resume,983};984 985module_usb_driver(az6007_usb_driver);986 987MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");988MODULE_AUTHOR("Mauro Carvalho Chehab");989MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");990MODULE_VERSION("2.0");991MODULE_LICENSE("GPL");992MODULE_FIRMWARE(AZ6007_FIRMWARE);993