1220 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)3 * receiver.4 *5 * Copyright (C) 2009 Adams.Xu <adams.xu@azwave.com.cn>6 *7 * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information8 */9#include "az6027.h"10 11#include "stb0899_drv.h"12#include "stb0899_reg.h"13#include "stb0899_cfg.h"14 15#include "stb6100.h"16#include "stb6100_cfg.h"17#include <media/dvb_ca_en50221.h>18 19int dvb_usb_az6027_debug;20module_param_named(debug, dvb_usb_az6027_debug, int, 0644);21MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);22 23DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);24 25struct az6027_device_state {26 struct dvb_ca_en50221 ca;27 struct mutex ca_mutex;28 u8 power_state;29};30 31static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = {32 33 /* 0x0000000b, SYSREG */34 { STB0899_DEV_ID , 0x30 },35 { STB0899_DISCNTRL1 , 0x32 },36 { STB0899_DISCNTRL2 , 0x80 },37 { STB0899_DISRX_ST0 , 0x04 },38 { STB0899_DISRX_ST1 , 0x00 },39 { STB0899_DISPARITY , 0x00 },40 { STB0899_DISSTATUS , 0x20 },41 { STB0899_DISF22 , 0x99 },42 { STB0899_DISF22RX , 0xa8 },43 /* SYSREG ? */44 { STB0899_ACRPRESC , 0x11 },45 { STB0899_ACRDIV1 , 0x0a },46 { STB0899_ACRDIV2 , 0x05 },47 { STB0899_DACR1 , 0x00 },48 { STB0899_DACR2 , 0x00 },49 { STB0899_OUTCFG , 0x00 },50 { STB0899_MODECFG , 0x00 },51 { STB0899_IRQSTATUS_3 , 0xfe },52 { STB0899_IRQSTATUS_2 , 0x03 },53 { STB0899_IRQSTATUS_1 , 0x7c },54 { STB0899_IRQSTATUS_0 , 0xf4 },55 { STB0899_IRQMSK_3 , 0xf3 },56 { STB0899_IRQMSK_2 , 0xfc },57 { STB0899_IRQMSK_1 , 0xff },58 { STB0899_IRQMSK_0 , 0xff },59 { STB0899_IRQCFG , 0x00 },60 { STB0899_I2CCFG , 0x88 },61 { STB0899_I2CRPT , 0x58 },62 { STB0899_IOPVALUE5 , 0x00 },63 { STB0899_IOPVALUE4 , 0x33 },64 { STB0899_IOPVALUE3 , 0x6d },65 { STB0899_IOPVALUE2 , 0x90 },66 { STB0899_IOPVALUE1 , 0x60 },67 { STB0899_IOPVALUE0 , 0x00 },68 { STB0899_GPIO00CFG , 0x82 },69 { STB0899_GPIO01CFG , 0x82 },70 { STB0899_GPIO02CFG , 0x82 },71 { STB0899_GPIO03CFG , 0x82 },72 { STB0899_GPIO04CFG , 0x82 },73 { STB0899_GPIO05CFG , 0x82 },74 { STB0899_GPIO06CFG , 0x82 },75 { STB0899_GPIO07CFG , 0x82 },76 { STB0899_GPIO08CFG , 0x82 },77 { STB0899_GPIO09CFG , 0x82 },78 { STB0899_GPIO10CFG , 0x82 },79 { STB0899_GPIO11CFG , 0x82 },80 { STB0899_GPIO12CFG , 0x82 },81 { STB0899_GPIO13CFG , 0x82 },82 { STB0899_GPIO14CFG , 0x82 },83 { STB0899_GPIO15CFG , 0x82 },84 { STB0899_GPIO16CFG , 0x82 },85 { STB0899_GPIO17CFG , 0x82 },86 { STB0899_GPIO18CFG , 0x82 },87 { STB0899_GPIO19CFG , 0x82 },88 { STB0899_GPIO20CFG , 0x82 },89 { STB0899_SDATCFG , 0xb8 },90 { STB0899_SCLTCFG , 0xba },91 { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */92 { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */93 { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */94 { STB0899_DIRCLKCFG , 0x82 },95 { STB0899_CLKOUT27CFG , 0x7e },96 { STB0899_STDBYCFG , 0x82 },97 { STB0899_CS0CFG , 0x82 },98 { STB0899_CS1CFG , 0x82 },99 { STB0899_DISEQCOCFG , 0x20 },100 { STB0899_GPIO32CFG , 0x82 },101 { STB0899_GPIO33CFG , 0x82 },102 { STB0899_GPIO34CFG , 0x82 },103 { STB0899_GPIO35CFG , 0x82 },104 { STB0899_GPIO36CFG , 0x82 },105 { STB0899_GPIO37CFG , 0x82 },106 { STB0899_GPIO38CFG , 0x82 },107 { STB0899_GPIO39CFG , 0x82 },108 { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */109 { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */110 { STB0899_FILTCTRL , 0x00 },111 { STB0899_SYSCTRL , 0x01 },112 { STB0899_STOPCLK1 , 0x20 },113 { STB0899_STOPCLK2 , 0x00 },114 { STB0899_INTBUFSTATUS , 0x00 },115 { STB0899_INTBUFCTRL , 0x0a },116 { 0xffff , 0xff },117};118 119static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = {120 { STB0899_DEMOD , 0x00 },121 { STB0899_RCOMPC , 0xc9 },122 { STB0899_AGC1CN , 0x01 },123 { STB0899_AGC1REF , 0x10 },124 { STB0899_RTC , 0x23 },125 { STB0899_TMGCFG , 0x4e },126 { STB0899_AGC2REF , 0x34 },127 { STB0899_TLSR , 0x84 },128 { STB0899_CFD , 0xf7 },129 { STB0899_ACLC , 0x87 },130 { STB0899_BCLC , 0x94 },131 { STB0899_EQON , 0x41 },132 { STB0899_LDT , 0xf1 },133 { STB0899_LDT2 , 0xe3 },134 { STB0899_EQUALREF , 0xb4 },135 { STB0899_TMGRAMP , 0x10 },136 { STB0899_TMGTHD , 0x30 },137 { STB0899_IDCCOMP , 0xfd },138 { STB0899_QDCCOMP , 0xff },139 { STB0899_POWERI , 0x0c },140 { STB0899_POWERQ , 0x0f },141 { STB0899_RCOMP , 0x6c },142 { STB0899_AGCIQIN , 0x80 },143 { STB0899_AGC2I1 , 0x06 },144 { STB0899_AGC2I2 , 0x00 },145 { STB0899_TLIR , 0x30 },146 { STB0899_RTF , 0x7f },147 { STB0899_DSTATUS , 0x00 },148 { STB0899_LDI , 0xbc },149 { STB0899_CFRM , 0xea },150 { STB0899_CFRL , 0x31 },151 { STB0899_NIRM , 0x2b },152 { STB0899_NIRL , 0x80 },153 { STB0899_ISYMB , 0x1d },154 { STB0899_QSYMB , 0xa6 },155 { STB0899_SFRH , 0x2f },156 { STB0899_SFRM , 0x68 },157 { STB0899_SFRL , 0x40 },158 { STB0899_SFRUPH , 0x2f },159 { STB0899_SFRUPM , 0x68 },160 { STB0899_SFRUPL , 0x40 },161 { STB0899_EQUAI1 , 0x02 },162 { STB0899_EQUAQ1 , 0xff },163 { STB0899_EQUAI2 , 0x04 },164 { STB0899_EQUAQ2 , 0x05 },165 { STB0899_EQUAI3 , 0x02 },166 { STB0899_EQUAQ3 , 0xfd },167 { STB0899_EQUAI4 , 0x03 },168 { STB0899_EQUAQ4 , 0x07 },169 { STB0899_EQUAI5 , 0x08 },170 { STB0899_EQUAQ5 , 0xf5 },171 { STB0899_DSTATUS2 , 0x00 },172 { STB0899_VSTATUS , 0x00 },173 { STB0899_VERROR , 0x86 },174 { STB0899_IQSWAP , 0x2a },175 { STB0899_ECNT1M , 0x00 },176 { STB0899_ECNT1L , 0x00 },177 { STB0899_ECNT2M , 0x00 },178 { STB0899_ECNT2L , 0x00 },179 { STB0899_ECNT3M , 0x0a },180 { STB0899_ECNT3L , 0xad },181 { STB0899_FECAUTO1 , 0x06 },182 { STB0899_FECM , 0x01 },183 { STB0899_VTH12 , 0xb0 },184 { STB0899_VTH23 , 0x7a },185 { STB0899_VTH34 , 0x58 },186 { STB0899_VTH56 , 0x38 },187 { STB0899_VTH67 , 0x34 },188 { STB0899_VTH78 , 0x24 },189 { STB0899_PRVIT , 0xff },190 { STB0899_VITSYNC , 0x19 },191 { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */192 { STB0899_TSULC , 0x42 },193 { STB0899_RSLLC , 0x41 },194 { STB0899_TSLPL , 0x12 },195 { STB0899_TSCFGH , 0x0c },196 { STB0899_TSCFGM , 0x00 },197 { STB0899_TSCFGL , 0x00 },198 { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */199 { STB0899_RSSYNCDEL , 0x00 },200 { STB0899_TSINHDELH , 0x02 },201 { STB0899_TSINHDELM , 0x00 },202 { STB0899_TSINHDELL , 0x00 },203 { STB0899_TSLLSTKM , 0x1b },204 { STB0899_TSLLSTKL , 0xb3 },205 { STB0899_TSULSTKM , 0x00 },206 { STB0899_TSULSTKL , 0x00 },207 { STB0899_PCKLENUL , 0xbc },208 { STB0899_PCKLENLL , 0xcc },209 { STB0899_RSPCKLEN , 0xbd },210 { STB0899_TSSTATUS , 0x90 },211 { STB0899_ERRCTRL1 , 0xb6 },212 { STB0899_ERRCTRL2 , 0x95 },213 { STB0899_ERRCTRL3 , 0x8d },214 { STB0899_DMONMSK1 , 0x27 },215 { STB0899_DMONMSK0 , 0x03 },216 { STB0899_DEMAPVIT , 0x5c },217 { STB0899_PLPARM , 0x19 },218 { STB0899_PDELCTRL , 0x48 },219 { STB0899_PDELCTRL2 , 0x00 },220 { STB0899_BBHCTRL1 , 0x00 },221 { STB0899_BBHCTRL2 , 0x00 },222 { STB0899_HYSTTHRESH , 0x77 },223 { STB0899_MATCSTM , 0x00 },224 { STB0899_MATCSTL , 0x00 },225 { STB0899_UPLCSTM , 0x00 },226 { STB0899_UPLCSTL , 0x00 },227 { STB0899_DFLCSTM , 0x00 },228 { STB0899_DFLCSTL , 0x00 },229 { STB0899_SYNCCST , 0x00 },230 { STB0899_SYNCDCSTM , 0x00 },231 { STB0899_SYNCDCSTL , 0x00 },232 { STB0899_ISI_ENTRY , 0x00 },233 { STB0899_ISI_BIT_EN , 0x00 },234 { STB0899_MATSTRM , 0xf0 },235 { STB0899_MATSTRL , 0x02 },236 { STB0899_UPLSTRM , 0x45 },237 { STB0899_UPLSTRL , 0x60 },238 { STB0899_DFLSTRM , 0xe3 },239 { STB0899_DFLSTRL , 0x00 },240 { STB0899_SYNCSTR , 0x47 },241 { STB0899_SYNCDSTRM , 0x05 },242 { STB0899_SYNCDSTRL , 0x18 },243 { STB0899_CFGPDELSTATUS1 , 0x19 },244 { STB0899_CFGPDELSTATUS2 , 0x2b },245 { STB0899_BBFERRORM , 0x00 },246 { STB0899_BBFERRORL , 0x01 },247 { STB0899_UPKTERRORM , 0x00 },248 { STB0899_UPKTERRORL , 0x00 },249 { 0xffff , 0xff },250};251 252 253 254static struct stb0899_config az6027_stb0899_config = {255 .init_dev = az6027_stb0899_s1_init_1,256 .init_s2_demod = stb0899_s2_init_2,257 .init_s1_demod = az6027_stb0899_s1_init_3,258 .init_s2_fec = stb0899_s2_init_4,259 .init_tst = stb0899_s1_init_5,260 261 .demod_address = 0xd0, /* 0x68, 0xd0 >> 1 */262 263 .xtal_freq = 27000000,264 .inversion = IQ_SWAP_ON,265 266 .lo_clk = 76500000,267 .hi_clk = 99000000,268 269 .esno_ave = STB0899_DVBS2_ESNO_AVE,270 .esno_quant = STB0899_DVBS2_ESNO_QUANT,271 .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,272 .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,273 .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,274 .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,275 .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,276 .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,277 .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,278 279 .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,280 .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,281 .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,282 .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,283 284 .tuner_get_frequency = stb6100_get_frequency,285 .tuner_set_frequency = stb6100_set_frequency,286 .tuner_set_bandwidth = stb6100_set_bandwidth,287 .tuner_get_bandwidth = stb6100_get_bandwidth,288 .tuner_set_rfsiggain = NULL,289};290 291static struct stb6100_config az6027_stb6100_config = {292 .tuner_address = 0xc0,293 .refclock = 27000000,294};295 296 297/* check for mutex FIXME */298static int az6027_usb_in_op(struct dvb_usb_device *d, u8 req,299 u16 value, u16 index, u8 *b, int blen)300{301 int ret = -1;302 if (mutex_lock_interruptible(&d->usb_mutex))303 return -EAGAIN;304 305 ret = usb_control_msg(d->udev,306 usb_rcvctrlpipe(d->udev, 0),307 req,308 USB_TYPE_VENDOR | USB_DIR_IN,309 value,310 index,311 b,312 blen,313 2000);314 315 if (ret < 0) {316 warn("usb in operation failed. (%d)", ret);317 ret = -EIO;318 } else319 ret = 0;320 321 deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);322 debug_dump(b, blen, deb_xfer);323 324 mutex_unlock(&d->usb_mutex);325 return ret;326}327 328static int az6027_usb_out_op(struct dvb_usb_device *d,329 u8 req,330 u16 value,331 u16 index,332 u8 *b,333 int blen)334{335 int ret;336 337 deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);338 debug_dump(b, blen, deb_xfer);339 340 if (mutex_lock_interruptible(&d->usb_mutex))341 return -EAGAIN;342 343 ret = usb_control_msg(d->udev,344 usb_sndctrlpipe(d->udev, 0),345 req,346 USB_TYPE_VENDOR | USB_DIR_OUT,347 value,348 index,349 b,350 blen,351 2000);352 353 if (ret != blen) {354 warn("usb out operation failed. (%d)", ret);355 mutex_unlock(&d->usb_mutex);356 return -EIO;357 } else{358 mutex_unlock(&d->usb_mutex);359 return 0;360 }361}362 363static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)364{365 int ret;366 u8 req;367 u16 value;368 u16 index;369 int blen;370 371 deb_info("%s %d", __func__, onoff);372 373 req = 0xBC;374 value = onoff;375 index = 0;376 blen = 0;377 378 ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);379 if (ret != 0)380 warn("usb out operation failed. (%d)", ret);381 382 return ret;383}384 385/* keys for the enclosed remote control */386static struct rc_map_table rc_map_az6027_table[] = {387 { 0x01, KEY_1 },388 { 0x02, KEY_2 },389};390 391/* remote control stuff (does not work with my box) */392static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state)393{394 *state = REMOTE_NO_KEY_PRESSED;395 return 0;396}397 398/*399int az6027_power_ctrl(struct dvb_usb_device *d, int onoff)400{401 u8 v = onoff;402 return az6027_usb_out_op(d,0xBC,v,3,NULL,1);403}404*/405 406static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,407 int slot,408 int address)409{410 struct dvb_usb_device *d = ca->data;411 struct az6027_device_state *state = d->priv;412 413 int ret;414 u8 req;415 u16 value;416 u16 index;417 int blen;418 u8 *b;419 420 if (slot != 0)421 return -EINVAL;422 423 b = kmalloc(12, GFP_KERNEL);424 if (!b)425 return -ENOMEM;426 427 mutex_lock(&state->ca_mutex);428 429 req = 0xC1;430 value = address;431 index = 0;432 blen = 1;433 434 ret = az6027_usb_in_op(d, req, value, index, b, blen);435 if (ret < 0) {436 warn("usb in operation failed. (%d)", ret);437 ret = -EINVAL;438 } else {439 ret = b[0];440 }441 442 mutex_unlock(&state->ca_mutex);443 kfree(b);444 return ret;445}446 447static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,448 int slot,449 int address,450 u8 value)451{452 struct dvb_usb_device *d = ca->data;453 struct az6027_device_state *state = d->priv;454 455 int ret;456 u8 req;457 u16 value1;458 u16 index;459 int blen;460 461 deb_info("%s %d", __func__, slot);462 if (slot != 0)463 return -EINVAL;464 465 mutex_lock(&state->ca_mutex);466 req = 0xC2;467 value1 = address;468 index = value;469 blen = 0;470 471 ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);472 if (ret != 0)473 warn("usb out operation failed. (%d)", ret);474 475 mutex_unlock(&state->ca_mutex);476 return ret;477}478 479static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca,480 int slot,481 u8 address)482{483 struct dvb_usb_device *d = ca->data;484 struct az6027_device_state *state = d->priv;485 486 int ret;487 u8 req;488 u16 value;489 u16 index;490 int blen;491 u8 *b;492 493 if (slot != 0)494 return -EINVAL;495 496 b = kmalloc(12, GFP_KERNEL);497 if (!b)498 return -ENOMEM;499 500 mutex_lock(&state->ca_mutex);501 502 req = 0xC3;503 value = address;504 index = 0;505 blen = 2;506 507 ret = az6027_usb_in_op(d, req, value, index, b, blen);508 if (ret < 0) {509 warn("usb in operation failed. (%d)", ret);510 ret = -EINVAL;511 } else {512 if (b[0] == 0)513 warn("Read CI IO error");514 515 ret = b[1];516 deb_info("read cam data = %x from 0x%x", b[1], value);517 }518 519 mutex_unlock(&state->ca_mutex);520 kfree(b);521 return ret;522}523 524static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca,525 int slot,526 u8 address,527 u8 value)528{529 struct dvb_usb_device *d = ca->data;530 struct az6027_device_state *state = d->priv;531 532 int ret;533 u8 req;534 u16 value1;535 u16 index;536 int blen;537 538 if (slot != 0)539 return -EINVAL;540 541 mutex_lock(&state->ca_mutex);542 req = 0xC4;543 value1 = address;544 index = value;545 blen = 0;546 547 ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);548 if (ret != 0) {549 warn("usb out operation failed. (%d)", ret);550 goto failed;551 }552 553failed:554 mutex_unlock(&state->ca_mutex);555 return ret;556}557 558static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)559{560 struct dvb_usb_device *d = ca->data;561 562 int ret;563 u8 req;564 u16 value;565 u16 index;566 int blen;567 u8 *b;568 569 b = kmalloc(12, GFP_KERNEL);570 if (!b)571 return -ENOMEM;572 573 req = 0xC8;574 value = 0;575 index = 0;576 blen = 1;577 578 ret = az6027_usb_in_op(d, req, value, index, b, blen);579 if (ret < 0) {580 warn("usb in operation failed. (%d)", ret);581 ret = -EIO;582 } else{583 ret = b[0];584 }585 kfree(b);586 return ret;587}588 589static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)590{591 struct dvb_usb_device *d = ca->data;592 struct az6027_device_state *state = d->priv;593 594 int ret, i;595 u8 req;596 u16 value;597 u16 index;598 int blen;599 600 mutex_lock(&state->ca_mutex);601 602 req = 0xC6;603 value = 1;604 index = 0;605 blen = 0;606 607 ret = az6027_usb_out_op(d, req, value, index, NULL, blen);608 if (ret != 0) {609 warn("usb out operation failed. (%d)", ret);610 goto failed;611 }612 613 msleep(500);614 req = 0xC6;615 value = 0;616 index = 0;617 blen = 0;618 619 ret = az6027_usb_out_op(d, req, value, index, NULL, blen);620 if (ret != 0) {621 warn("usb out operation failed. (%d)", ret);622 goto failed;623 }624 625 for (i = 0; i < 15; i++) {626 msleep(100);627 628 if (CI_CamReady(ca, slot)) {629 deb_info("CAM Ready");630 break;631 }632 }633 msleep(5000);634 635failed:636 mutex_unlock(&state->ca_mutex);637 return ret;638}639 640static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)641{642 return 0;643}644 645static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)646{647 struct dvb_usb_device *d = ca->data;648 struct az6027_device_state *state = d->priv;649 650 int ret;651 u8 req;652 u16 value;653 u16 index;654 int blen;655 656 deb_info("%s", __func__);657 mutex_lock(&state->ca_mutex);658 req = 0xC7;659 value = 1;660 index = 0;661 blen = 0;662 663 ret = az6027_usb_out_op(d, req, value, index, NULL, blen);664 if (ret != 0) {665 warn("usb out operation failed. (%d)", ret);666 goto failed;667 }668 669failed:670 mutex_unlock(&state->ca_mutex);671 return ret;672}673 674static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)675{676 struct dvb_usb_device *d = ca->data;677 struct az6027_device_state *state = d->priv;678 int ret;679 u8 req;680 u16 value;681 u16 index;682 int blen;683 u8 *b;684 685 b = kmalloc(12, GFP_KERNEL);686 if (!b)687 return -ENOMEM;688 mutex_lock(&state->ca_mutex);689 690 req = 0xC5;691 value = 0;692 index = 0;693 blen = 1;694 695 ret = az6027_usb_in_op(d, req, value, index, b, blen);696 if (ret < 0) {697 warn("usb in operation failed. (%d)", ret);698 ret = -EIO;699 } else700 ret = 0;701 702 if (!ret && b[0] == 1) {703 ret = DVB_CA_EN50221_POLL_CAM_PRESENT |704 DVB_CA_EN50221_POLL_CAM_READY;705 }706 707 mutex_unlock(&state->ca_mutex);708 kfree(b);709 return ret;710}711 712 713static void az6027_ci_uninit(struct dvb_usb_device *d)714{715 struct az6027_device_state *state;716 717 deb_info("%s", __func__);718 719 if (NULL == d)720 return;721 722 state = d->priv;723 if (NULL == state)724 return;725 726 if (NULL == state->ca.data)727 return;728 729 dvb_ca_en50221_release(&state->ca);730 731 memset(&state->ca, 0, sizeof(state->ca));732}733 734 735static int az6027_ci_init(struct dvb_usb_adapter *a)736{737 struct dvb_usb_device *d = a->dev;738 struct az6027_device_state *state = d->priv;739 int ret;740 741 deb_info("%s", __func__);742 743 mutex_init(&state->ca_mutex);744 745 state->ca.owner = THIS_MODULE;746 state->ca.read_attribute_mem = az6027_ci_read_attribute_mem;747 state->ca.write_attribute_mem = az6027_ci_write_attribute_mem;748 state->ca.read_cam_control = az6027_ci_read_cam_control;749 state->ca.write_cam_control = az6027_ci_write_cam_control;750 state->ca.slot_reset = az6027_ci_slot_reset;751 state->ca.slot_shutdown = az6027_ci_slot_shutdown;752 state->ca.slot_ts_enable = az6027_ci_slot_ts_enable;753 state->ca.poll_slot_status = az6027_ci_poll_slot_status;754 state->ca.data = d;755 756 ret = dvb_ca_en50221_init(&a->dvb_adap,757 &state->ca,758 0, /* flags */759 1);/* n_slots */760 if (ret != 0) {761 err("Cannot initialize CI: Error %d.", ret);762 memset(&state->ca, 0, sizeof(state->ca));763 return ret;764 }765 766 deb_info("CI initialized.");767 768 return 0;769}770 771/*772static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])773{774 az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);775 return 0;776}777*/778 779static int az6027_set_voltage(struct dvb_frontend *fe,780 enum fe_sec_voltage voltage)781{782 783 u8 buf;784 struct dvb_usb_adapter *adap = fe->dvb->priv;785 786 struct i2c_msg i2c_msg = {787 .addr = 0x99,788 .flags = 0,789 .buf = &buf,790 .len = 1791 };792 793 /*794 * 2 --18v795 * 1 --13v796 * 0 --off797 */798 switch (voltage) {799 case SEC_VOLTAGE_13:800 buf = 1;801 i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);802 break;803 804 case SEC_VOLTAGE_18:805 buf = 2;806 i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);807 break;808 809 case SEC_VOLTAGE_OFF:810 buf = 0;811 i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);812 break;813 814 default:815 return -EINVAL;816 }817 return 0;818}819 820 821static int az6027_frontend_poweron(struct dvb_usb_adapter *adap)822{823 int ret;824 u8 req;825 u16 value;826 u16 index;827 int blen;828 829 req = 0xBC;830 value = 1; /* power on */831 index = 3;832 blen = 0;833 834 ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);835 if (ret != 0)836 return -EIO;837 838 return 0;839}840static int az6027_frontend_reset(struct dvb_usb_adapter *adap)841{842 int ret;843 u8 req;844 u16 value;845 u16 index;846 int blen;847 848 /* reset demodulator */849 req = 0xC0;850 value = 1; /* high */851 index = 3;852 blen = 0;853 854 ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);855 if (ret != 0)856 return -EIO;857 858 req = 0xC0;859 value = 0; /* low */860 index = 3;861 blen = 0;862 msleep_interruptible(200);863 864 ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);865 if (ret != 0)866 return -EIO;867 868 msleep_interruptible(200);869 870 req = 0xC0;871 value = 1; /*high */872 index = 3;873 blen = 0;874 875 ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);876 if (ret != 0)877 return -EIO;878 879 msleep_interruptible(200);880 return 0;881}882 883static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff)884{885 int ret;886 u8 req;887 u16 value;888 u16 index;889 int blen;890 891 /* TS passthrough */892 req = 0xC7;893 value = onoff;894 index = 0;895 blen = 0;896 897 ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);898 if (ret != 0)899 return -EIO;900 901 return 0;902}903 904static int az6027_frontend_attach(struct dvb_usb_adapter *adap)905{906 907 az6027_frontend_poweron(adap);908 az6027_frontend_reset(adap);909 910 deb_info("adap = %p, dev = %p\n", adap, adap->dev);911 adap->fe_adap[0].fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);912 913 if (adap->fe_adap[0].fe) {914 deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address);915 if (stb6100_attach(adap->fe_adap[0].fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {916 deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address);917 adap->fe_adap[0].fe->ops.set_voltage = az6027_set_voltage;918 az6027_ci_init(adap);919 } else {920 adap->fe_adap[0].fe = NULL;921 }922 } else923 warn("no front-end attached\n");924 925 az6027_frontend_tsbypass(adap, 0);926 927 return 0;928}929 930static struct dvb_usb_device_properties az6027_properties;931 932static void az6027_usb_disconnect(struct usb_interface *intf)933{934 struct dvb_usb_device *d = usb_get_intfdata(intf);935 az6027_ci_uninit(d);936 dvb_usb_device_exit(intf);937}938 939 940static int az6027_usb_probe(struct usb_interface *intf,941 const struct usb_device_id *id)942{943 return dvb_usb_device_init(intf,944 &az6027_properties,945 THIS_MODULE,946 NULL,947 adapter_nr);948}949 950/* I2C */951static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)952{953 struct dvb_usb_device *d = i2c_get_adapdata(adap);954 int i = 0, j = 0, len = 0;955 u16 index;956 u16 value;957 int length;958 u8 req;959 u8 *data;960 961 data = kmalloc(256, GFP_KERNEL);962 if (!data)963 return -ENOMEM;964 965 if (mutex_lock_interruptible(&d->i2c_mutex) < 0) {966 kfree(data);967 return -EAGAIN;968 }969 970 if (num > 2)971 warn("more than 2 i2c messages at a time is not handled yet. TODO.");972 973 for (i = 0; i < num; i++) {974 975 if (msg[i].addr == 0x99) {976 req = 0xBE;977 index = 0;978 if (msg[i].len < 1) {979 i = -EOPNOTSUPP;980 break;981 }982 value = msg[i].buf[0] & 0x00ff;983 length = 1;984 az6027_usb_out_op(d, req, value, index, data, length);985 }986 987 if (msg[i].addr == 0xd0) {988 /* write/read request */989 if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {990 req = 0xB9;991 if (msg[i].len < 1) {992 i = -EOPNOTSUPP;993 break;994 }995 index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));996 value = msg[i].addr + (msg[i].len << 8);997 length = msg[i + 1].len + 6;998 az6027_usb_in_op(d, req, value, index, data, length);999 len = msg[i + 1].len;1000 for (j = 0; j < len; j++)1001 msg[i + 1].buf[j] = data[j + 5];1002 1003 i++;1004 } else {1005 1006 /* demod 16bit addr */1007 req = 0xBD;1008 if (msg[i].len < 1) {1009 i = -EOPNOTSUPP;1010 break;1011 }1012 index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));1013 value = msg[i].addr + (2 << 8);1014 length = msg[i].len - 2;1015 len = msg[i].len - 2;1016 for (j = 0; j < len; j++)1017 data[j] = msg[i].buf[j + 2];1018 az6027_usb_out_op(d, req, value, index, data, length);1019 }1020 }1021 1022 if (msg[i].addr == 0xc0) {1023 if (msg[i].flags & I2C_M_RD) {1024 1025 req = 0xB9;1026 index = 0x0;1027 value = msg[i].addr;1028 length = msg[i].len + 6;1029 az6027_usb_in_op(d, req, value, index, data, length);1030 len = msg[i].len;1031 for (j = 0; j < len; j++)1032 msg[i].buf[j] = data[j + 5];1033 1034 } else {1035 1036 req = 0xBD;1037 if (msg[i].len < 1) {1038 i = -EOPNOTSUPP;1039 break;1040 }1041 index = msg[i].buf[0] & 0x00FF;1042 value = msg[i].addr + (1 << 8);1043 length = msg[i].len - 1;1044 len = msg[i].len - 1;1045 1046 for (j = 0; j < len; j++)1047 data[j] = msg[i].buf[j + 1];1048 1049 az6027_usb_out_op(d, req, value, index, data, length);1050 }1051 }1052 }1053 mutex_unlock(&d->i2c_mutex);1054 kfree(data);1055 1056 return i;1057}1058 1059 1060static u32 az6027_i2c_func(struct i2c_adapter *adapter)1061{1062 return I2C_FUNC_I2C;1063}1064 1065static struct i2c_algorithm az6027_i2c_algo = {1066 .master_xfer = az6027_i2c_xfer,1067 .functionality = az6027_i2c_func,1068};1069 1070static int az6027_identify_state(struct usb_device *udev,1071 const struct dvb_usb_device_properties *props,1072 const struct dvb_usb_device_description **desc,1073 int *cold)1074{1075 u8 *b;1076 s16 ret;1077 1078 b = kmalloc(16, GFP_KERNEL);1079 if (!b)1080 return -ENOMEM;1081 1082 ret = usb_control_msg(udev,1083 usb_rcvctrlpipe(udev, 0),1084 0xb7,1085 USB_TYPE_VENDOR | USB_DIR_IN,1086 6,1087 0,1088 b,1089 6,1090 USB_CTRL_GET_TIMEOUT);1091 1092 *cold = ret <= 0;1093 kfree(b);1094 deb_info("cold: %d\n", *cold);1095 return 0;1096}1097 1098 1099enum {1100 AZUREWAVE_AZ6027,1101 TERRATEC_DVBS2CI_V1,1102 TERRATEC_DVBS2CI_V2,1103 TECHNISAT_USB2_HDCI_V1,1104 TECHNISAT_USB2_HDCI_V2,1105 ELGATO_EYETV_SAT,1106 ELGATO_EYETV_SAT_V2,1107 ELGATO_EYETV_SAT_V3,1108};1109 1110static struct usb_device_id az6027_usb_table[] = {1111 DVB_USB_DEV(AZUREWAVE, AZUREWAVE_AZ6027),1112 DVB_USB_DEV(TERRATEC, TERRATEC_DVBS2CI_V1),1113 DVB_USB_DEV(TERRATEC, TERRATEC_DVBS2CI_V2),1114 DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_HDCI_V1),1115 DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_HDCI_V2),1116 DVB_USB_DEV(ELGATO, ELGATO_EYETV_SAT),1117 DVB_USB_DEV(ELGATO, ELGATO_EYETV_SAT_V2),1118 DVB_USB_DEV(ELGATO, ELGATO_EYETV_SAT_V3),1119 { }1120};1121 1122MODULE_DEVICE_TABLE(usb, az6027_usb_table);1123 1124static struct dvb_usb_device_properties az6027_properties = {1125 .caps = DVB_USB_IS_AN_I2C_ADAPTER,1126 .usb_ctrl = CYPRESS_FX2,1127 .firmware = "dvb-usb-az6027-03.fw",1128 .no_reconnect = 1,1129 1130 .size_of_priv = sizeof(struct az6027_device_state),1131 .identify_state = az6027_identify_state,1132 .num_adapters = 1,1133 .adapter = {1134 {1135 .num_frontends = 1,1136 .fe = {{1137 .streaming_ctrl = az6027_streaming_ctrl,1138 .frontend_attach = az6027_frontend_attach,1139 1140 /* parameter for the MPEG2-data transfer */1141 .stream = {1142 .type = USB_BULK,1143 .count = 10,1144 .endpoint = 0x02,1145 .u = {1146 .bulk = {1147 .buffersize = 4096,1148 }1149 }1150 },1151 }},1152 }1153 },1154/*1155 .power_ctrl = az6027_power_ctrl,1156 .read_mac_address = az6027_read_mac_addr,1157 */1158 .rc.legacy = {1159 .rc_map_table = rc_map_az6027_table,1160 .rc_map_size = ARRAY_SIZE(rc_map_az6027_table),1161 .rc_interval = 400,1162 .rc_query = az6027_rc_query,1163 },1164 1165 .i2c_algo = &az6027_i2c_algo,1166 1167 .num_device_descs = 8,1168 .devices = {1169 {1170 .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",1171 .cold_ids = { &az6027_usb_table[AZUREWAVE_AZ6027], NULL },1172 .warm_ids = { NULL },1173 }, {1174 .name = "TERRATEC S7",1175 .cold_ids = { &az6027_usb_table[TERRATEC_DVBS2CI_V1], NULL },1176 .warm_ids = { NULL },1177 }, {1178 .name = "TERRATEC S7 MKII",1179 .cold_ids = { &az6027_usb_table[TERRATEC_DVBS2CI_V2], NULL },1180 .warm_ids = { NULL },1181 }, {1182 .name = "Technisat SkyStar USB 2 HD CI",1183 .cold_ids = { &az6027_usb_table[TECHNISAT_USB2_HDCI_V1], NULL },1184 .warm_ids = { NULL },1185 }, {1186 .name = "Technisat SkyStar USB 2 HD CI",1187 .cold_ids = { &az6027_usb_table[TECHNISAT_USB2_HDCI_V2], NULL },1188 .warm_ids = { NULL },1189 }, {1190 .name = "Elgato EyeTV Sat",1191 .cold_ids = { &az6027_usb_table[ELGATO_EYETV_SAT], NULL },1192 .warm_ids = { NULL },1193 }, {1194 .name = "Elgato EyeTV Sat",1195 .cold_ids = { &az6027_usb_table[ELGATO_EYETV_SAT_V2], NULL },1196 .warm_ids = { NULL },1197 }, {1198 .name = "Elgato EyeTV Sat",1199 .cold_ids = { &az6027_usb_table[ELGATO_EYETV_SAT_V3], NULL },1200 .warm_ids = { NULL },1201 },1202 { NULL },1203 }1204};1205 1206/* usb specific object needed to register this driver with the usb subsystem */1207static struct usb_driver az6027_usb_driver = {1208 .name = "dvb_usb_az6027",1209 .probe = az6027_usb_probe,1210 .disconnect = az6027_usb_disconnect,1211 .id_table = az6027_usb_table,1212};1213 1214module_usb_driver(az6027_usb_driver);1215 1216MODULE_AUTHOR("Adams Xu <Adams.xu@azwave.com.cn>");1217MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)");1218MODULE_VERSION("1.0");1219MODULE_LICENSE("GPL");1220