Path: blob/master/drivers/media/dvb/dvb-usb/az6027.c
15112 views
/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)1* receiver.2*3* Copyright (C) 2009 Adams.Xu <[email protected]>4*5* This program is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License as published by the Free7* Software Foundation, version 2.8*9* see Documentation/dvb/README.dvb-usb for more information10*/11#include "az6027.h"1213#include "stb0899_drv.h"14#include "stb0899_reg.h"15#include "stb0899_cfg.h"1617#include "stb6100.h"18#include "stb6100_cfg.h"19#include "dvb_ca_en50221.h"2021int dvb_usb_az6027_debug;22module_param_named(debug, dvb_usb_az6027_debug, int, 0644);23MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);2425DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);2627struct az6027_device_state {28struct dvb_ca_en50221 ca;29struct mutex ca_mutex;30u8 power_state;31};3233static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = {3435/* 0x0000000b, SYSREG */36{ STB0899_DEV_ID , 0x30 },37{ STB0899_DISCNTRL1 , 0x32 },38{ STB0899_DISCNTRL2 , 0x80 },39{ STB0899_DISRX_ST0 , 0x04 },40{ STB0899_DISRX_ST1 , 0x00 },41{ STB0899_DISPARITY , 0x00 },42{ STB0899_DISFIFO , 0x00 },43{ STB0899_DISSTATUS , 0x20 },44{ STB0899_DISF22 , 0x99 },45{ STB0899_DISF22RX , 0xa8 },46/* SYSREG ? */47{ STB0899_ACRPRESC , 0x11 },48{ STB0899_ACRDIV1 , 0x0a },49{ STB0899_ACRDIV2 , 0x05 },50{ STB0899_DACR1 , 0x00 },51{ STB0899_DACR2 , 0x00 },52{ STB0899_OUTCFG , 0x00 },53{ STB0899_MODECFG , 0x00 },54{ STB0899_IRQSTATUS_3 , 0xfe },55{ STB0899_IRQSTATUS_2 , 0x03 },56{ STB0899_IRQSTATUS_1 , 0x7c },57{ STB0899_IRQSTATUS_0 , 0xf4 },58{ STB0899_IRQMSK_3 , 0xf3 },59{ STB0899_IRQMSK_2 , 0xfc },60{ STB0899_IRQMSK_1 , 0xff },61{ STB0899_IRQMSK_0 , 0xff },62{ STB0899_IRQCFG , 0x00 },63{ STB0899_I2CCFG , 0x88 },64{ STB0899_I2CRPT , 0x58 },65{ STB0899_IOPVALUE5 , 0x00 },66{ STB0899_IOPVALUE4 , 0x33 },67{ STB0899_IOPVALUE3 , 0x6d },68{ STB0899_IOPVALUE2 , 0x90 },69{ STB0899_IOPVALUE1 , 0x60 },70{ STB0899_IOPVALUE0 , 0x00 },71{ STB0899_GPIO00CFG , 0x82 },72{ STB0899_GPIO01CFG , 0x82 },73{ STB0899_GPIO02CFG , 0x82 },74{ STB0899_GPIO03CFG , 0x82 },75{ STB0899_GPIO04CFG , 0x82 },76{ STB0899_GPIO05CFG , 0x82 },77{ STB0899_GPIO06CFG , 0x82 },78{ STB0899_GPIO07CFG , 0x82 },79{ STB0899_GPIO08CFG , 0x82 },80{ STB0899_GPIO09CFG , 0x82 },81{ STB0899_GPIO10CFG , 0x82 },82{ STB0899_GPIO11CFG , 0x82 },83{ STB0899_GPIO12CFG , 0x82 },84{ STB0899_GPIO13CFG , 0x82 },85{ STB0899_GPIO14CFG , 0x82 },86{ STB0899_GPIO15CFG , 0x82 },87{ STB0899_GPIO16CFG , 0x82 },88{ STB0899_GPIO17CFG , 0x82 },89{ STB0899_GPIO18CFG , 0x82 },90{ STB0899_GPIO19CFG , 0x82 },91{ STB0899_GPIO20CFG , 0x82 },92{ STB0899_SDATCFG , 0xb8 },93{ STB0899_SCLTCFG , 0xba },94{ STB0899_AGCRFCFG , 0x1c }, /* 0x11 */95{ STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */96{ STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */97{ STB0899_DIRCLKCFG , 0x82 },98{ STB0899_CLKOUT27CFG , 0x7e },99{ STB0899_STDBYCFG , 0x82 },100{ STB0899_CS0CFG , 0x82 },101{ STB0899_CS1CFG , 0x82 },102{ STB0899_DISEQCOCFG , 0x20 },103{ STB0899_GPIO32CFG , 0x82 },104{ STB0899_GPIO33CFG , 0x82 },105{ STB0899_GPIO34CFG , 0x82 },106{ STB0899_GPIO35CFG , 0x82 },107{ STB0899_GPIO36CFG , 0x82 },108{ STB0899_GPIO37CFG , 0x82 },109{ STB0899_GPIO38CFG , 0x82 },110{ STB0899_GPIO39CFG , 0x82 },111{ STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */112{ STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */113{ STB0899_FILTCTRL , 0x00 },114{ STB0899_SYSCTRL , 0x01 },115{ STB0899_STOPCLK1 , 0x20 },116{ STB0899_STOPCLK2 , 0x00 },117{ STB0899_INTBUFSTATUS , 0x00 },118{ STB0899_INTBUFCTRL , 0x0a },119{ 0xffff , 0xff },120};121122static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = {123{ STB0899_DEMOD , 0x00 },124{ STB0899_RCOMPC , 0xc9 },125{ STB0899_AGC1CN , 0x01 },126{ STB0899_AGC1REF , 0x10 },127{ STB0899_RTC , 0x23 },128{ STB0899_TMGCFG , 0x4e },129{ STB0899_AGC2REF , 0x34 },130{ STB0899_TLSR , 0x84 },131{ STB0899_CFD , 0xf7 },132{ STB0899_ACLC , 0x87 },133{ STB0899_BCLC , 0x94 },134{ STB0899_EQON , 0x41 },135{ STB0899_LDT , 0xf1 },136{ STB0899_LDT2 , 0xe3 },137{ STB0899_EQUALREF , 0xb4 },138{ STB0899_TMGRAMP , 0x10 },139{ STB0899_TMGTHD , 0x30 },140{ STB0899_IDCCOMP , 0xfd },141{ STB0899_QDCCOMP , 0xff },142{ STB0899_POWERI , 0x0c },143{ STB0899_POWERQ , 0x0f },144{ STB0899_RCOMP , 0x6c },145{ STB0899_AGCIQIN , 0x80 },146{ STB0899_AGC2I1 , 0x06 },147{ STB0899_AGC2I2 , 0x00 },148{ STB0899_TLIR , 0x30 },149{ STB0899_RTF , 0x7f },150{ STB0899_DSTATUS , 0x00 },151{ STB0899_LDI , 0xbc },152{ STB0899_CFRM , 0xea },153{ STB0899_CFRL , 0x31 },154{ STB0899_NIRM , 0x2b },155{ STB0899_NIRL , 0x80 },156{ STB0899_ISYMB , 0x1d },157{ STB0899_QSYMB , 0xa6 },158{ STB0899_SFRH , 0x2f },159{ STB0899_SFRM , 0x68 },160{ STB0899_SFRL , 0x40 },161{ STB0899_SFRUPH , 0x2f },162{ STB0899_SFRUPM , 0x68 },163{ STB0899_SFRUPL , 0x40 },164{ STB0899_EQUAI1 , 0x02 },165{ STB0899_EQUAQ1 , 0xff },166{ STB0899_EQUAI2 , 0x04 },167{ STB0899_EQUAQ2 , 0x05 },168{ STB0899_EQUAI3 , 0x02 },169{ STB0899_EQUAQ3 , 0xfd },170{ STB0899_EQUAI4 , 0x03 },171{ STB0899_EQUAQ4 , 0x07 },172{ STB0899_EQUAI5 , 0x08 },173{ STB0899_EQUAQ5 , 0xf5 },174{ STB0899_DSTATUS2 , 0x00 },175{ STB0899_VSTATUS , 0x00 },176{ STB0899_VERROR , 0x86 },177{ STB0899_IQSWAP , 0x2a },178{ STB0899_ECNT1M , 0x00 },179{ STB0899_ECNT1L , 0x00 },180{ STB0899_ECNT2M , 0x00 },181{ STB0899_ECNT2L , 0x00 },182{ STB0899_ECNT3M , 0x0a },183{ STB0899_ECNT3L , 0xad },184{ STB0899_FECAUTO1 , 0x06 },185{ STB0899_FECM , 0x01 },186{ STB0899_VTH12 , 0xb0 },187{ STB0899_VTH23 , 0x7a },188{ STB0899_VTH34 , 0x58 },189{ STB0899_VTH56 , 0x38 },190{ STB0899_VTH67 , 0x34 },191{ STB0899_VTH78 , 0x24 },192{ STB0899_PRVIT , 0xff },193{ STB0899_VITSYNC , 0x19 },194{ STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */195{ STB0899_TSULC , 0x42 },196{ STB0899_RSLLC , 0x41 },197{ STB0899_TSLPL , 0x12 },198{ STB0899_TSCFGH , 0x0c },199{ STB0899_TSCFGM , 0x00 },200{ STB0899_TSCFGL , 0x00 },201{ STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */202{ STB0899_RSSYNCDEL , 0x00 },203{ STB0899_TSINHDELH , 0x02 },204{ STB0899_TSINHDELM , 0x00 },205{ STB0899_TSINHDELL , 0x00 },206{ STB0899_TSLLSTKM , 0x1b },207{ STB0899_TSLLSTKL , 0xb3 },208{ STB0899_TSULSTKM , 0x00 },209{ STB0899_TSULSTKL , 0x00 },210{ STB0899_PCKLENUL , 0xbc },211{ STB0899_PCKLENLL , 0xcc },212{ STB0899_RSPCKLEN , 0xbd },213{ STB0899_TSSTATUS , 0x90 },214{ STB0899_ERRCTRL1 , 0xb6 },215{ STB0899_ERRCTRL2 , 0x95 },216{ STB0899_ERRCTRL3 , 0x8d },217{ STB0899_DMONMSK1 , 0x27 },218{ STB0899_DMONMSK0 , 0x03 },219{ STB0899_DEMAPVIT , 0x5c },220{ STB0899_PLPARM , 0x19 },221{ STB0899_PDELCTRL , 0x48 },222{ STB0899_PDELCTRL2 , 0x00 },223{ STB0899_BBHCTRL1 , 0x00 },224{ STB0899_BBHCTRL2 , 0x00 },225{ STB0899_HYSTTHRESH , 0x77 },226{ STB0899_MATCSTM , 0x00 },227{ STB0899_MATCSTL , 0x00 },228{ STB0899_UPLCSTM , 0x00 },229{ STB0899_UPLCSTL , 0x00 },230{ STB0899_DFLCSTM , 0x00 },231{ STB0899_DFLCSTL , 0x00 },232{ STB0899_SYNCCST , 0x00 },233{ STB0899_SYNCDCSTM , 0x00 },234{ STB0899_SYNCDCSTL , 0x00 },235{ STB0899_ISI_ENTRY , 0x00 },236{ STB0899_ISI_BIT_EN , 0x00 },237{ STB0899_MATSTRM , 0xf0 },238{ STB0899_MATSTRL , 0x02 },239{ STB0899_UPLSTRM , 0x45 },240{ STB0899_UPLSTRL , 0x60 },241{ STB0899_DFLSTRM , 0xe3 },242{ STB0899_DFLSTRL , 0x00 },243{ STB0899_SYNCSTR , 0x47 },244{ STB0899_SYNCDSTRM , 0x05 },245{ STB0899_SYNCDSTRL , 0x18 },246{ STB0899_CFGPDELSTATUS1 , 0x19 },247{ STB0899_CFGPDELSTATUS2 , 0x2b },248{ STB0899_BBFERRORM , 0x00 },249{ STB0899_BBFERRORL , 0x01 },250{ STB0899_UPKTERRORM , 0x00 },251{ STB0899_UPKTERRORL , 0x00 },252{ 0xffff , 0xff },253};254255256257struct stb0899_config az6027_stb0899_config = {258.init_dev = az6027_stb0899_s1_init_1,259.init_s2_demod = stb0899_s2_init_2,260.init_s1_demod = az6027_stb0899_s1_init_3,261.init_s2_fec = stb0899_s2_init_4,262.init_tst = stb0899_s1_init_5,263264.demod_address = 0xd0, /* 0x68, 0xd0 >> 1 */265266.xtal_freq = 27000000,267.inversion = IQ_SWAP_ON, /* 1 */268269.lo_clk = 76500000,270.hi_clk = 99000000,271272.esno_ave = STB0899_DVBS2_ESNO_AVE,273.esno_quant = STB0899_DVBS2_ESNO_QUANT,274.avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,275.avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,276.miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,277.uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,278.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,279.uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,280.sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,281282.btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,283.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,284.crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,285.ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,286287.tuner_get_frequency = stb6100_get_frequency,288.tuner_set_frequency = stb6100_set_frequency,289.tuner_set_bandwidth = stb6100_set_bandwidth,290.tuner_get_bandwidth = stb6100_get_bandwidth,291.tuner_set_rfsiggain = NULL,292};293294struct stb6100_config az6027_stb6100_config = {295.tuner_address = 0xc0,296.refclock = 27000000,297};298299300/* check for mutex FIXME */301int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)302{303int ret = -1;304if (mutex_lock_interruptible(&d->usb_mutex))305return -EAGAIN;306307ret = usb_control_msg(d->udev,308usb_rcvctrlpipe(d->udev, 0),309req,310USB_TYPE_VENDOR | USB_DIR_IN,311value,312index,313b,314blen,3152000);316317if (ret < 0) {318warn("usb in operation failed. (%d)", ret);319ret = -EIO;320} else321ret = 0;322323deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);324debug_dump(b, blen, deb_xfer);325326mutex_unlock(&d->usb_mutex);327return ret;328}329330static int az6027_usb_out_op(struct dvb_usb_device *d,331u8 req,332u16 value,333u16 index,334u8 *b,335int blen)336{337int ret;338339deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);340debug_dump(b, blen, deb_xfer);341342if (mutex_lock_interruptible(&d->usb_mutex))343return -EAGAIN;344345ret = usb_control_msg(d->udev,346usb_sndctrlpipe(d->udev, 0),347req,348USB_TYPE_VENDOR | USB_DIR_OUT,349value,350index,351b,352blen,3532000);354355if (ret != blen) {356warn("usb out operation failed. (%d)", ret);357mutex_unlock(&d->usb_mutex);358return -EIO;359} else{360mutex_unlock(&d->usb_mutex);361return 0;362}363}364365static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)366{367int ret;368u8 req;369u16 value;370u16 index;371int blen;372373deb_info("%s %d", __func__, onoff);374375req = 0xBC;376value = onoff;377index = 0;378blen = 0;379380ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);381if (ret != 0)382warn("usb out operation failed. (%d)", ret);383384return ret;385}386387/* keys for the enclosed remote control */388static struct rc_map_table rc_map_az6027_table[] = {389{ 0x01, KEY_1 },390{ 0x02, KEY_2 },391};392393/* remote control stuff (does not work with my box) */394static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state)395{396return 0;397}398399/*400int az6027_power_ctrl(struct dvb_usb_device *d, int onoff)401{402u8 v = onoff;403return az6027_usb_out_op(d,0xBC,v,3,NULL,1);404}405*/406407static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,408int slot,409int address)410{411struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;412struct az6027_device_state *state = (struct az6027_device_state *)d->priv;413414int ret;415u8 req;416u16 value;417u16 index;418int blen;419u8 *b;420421if (slot != 0)422return -EINVAL;423424b = kmalloc(12, GFP_KERNEL);425if (!b)426return -ENOMEM;427428mutex_lock(&state->ca_mutex);429430req = 0xC1;431value = address;432index = 0;433blen = 1;434435ret = az6027_usb_in_op(d, req, value, index, b, blen);436if (ret < 0) {437warn("usb in operation failed. (%d)", ret);438ret = -EINVAL;439} else {440ret = b[0];441}442443mutex_unlock(&state->ca_mutex);444kfree(b);445return ret;446}447448static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,449int slot,450int address,451u8 value)452{453struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;454struct az6027_device_state *state = (struct az6027_device_state *)d->priv;455456int ret;457u8 req;458u16 value1;459u16 index;460int blen;461462deb_info("%s %d", __func__, slot);463if (slot != 0)464return -EINVAL;465466mutex_lock(&state->ca_mutex);467req = 0xC2;468value1 = address;469index = value;470blen = 0;471472ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);473if (ret != 0)474warn("usb out operation failed. (%d)", ret);475476mutex_unlock(&state->ca_mutex);477return ret;478}479480static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca,481int slot,482u8 address)483{484struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;485struct az6027_device_state *state = (struct az6027_device_state *)d->priv;486487int ret;488u8 req;489u16 value;490u16 index;491int blen;492u8 *b;493494if (slot != 0)495return -EINVAL;496497b = kmalloc(12, GFP_KERNEL);498if (!b)499return -ENOMEM;500501mutex_lock(&state->ca_mutex);502503req = 0xC3;504value = address;505index = 0;506blen = 2;507508ret = az6027_usb_in_op(d, req, value, index, b, blen);509if (ret < 0) {510warn("usb in operation failed. (%d)", ret);511ret = -EINVAL;512} else {513if (b[0] == 0)514warn("Read CI IO error");515516ret = b[1];517deb_info("read cam data = %x from 0x%x", b[1], value);518}519520mutex_unlock(&state->ca_mutex);521kfree(b);522return ret;523}524525static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca,526int slot,527u8 address,528u8 value)529{530struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;531struct az6027_device_state *state = (struct az6027_device_state *)d->priv;532533int ret;534u8 req;535u16 value1;536u16 index;537int blen;538539if (slot != 0)540return -EINVAL;541542mutex_lock(&state->ca_mutex);543req = 0xC4;544value1 = address;545index = value;546blen = 0;547548ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);549if (ret != 0) {550warn("usb out operation failed. (%d)", ret);551goto failed;552}553554failed:555mutex_unlock(&state->ca_mutex);556return ret;557}558559static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)560{561struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;562563int ret;564u8 req;565u16 value;566u16 index;567int blen;568u8 *b;569570b = kmalloc(12, GFP_KERNEL);571if (!b)572return -ENOMEM;573574req = 0xC8;575value = 0;576index = 0;577blen = 1;578579ret = az6027_usb_in_op(d, req, value, index, b, blen);580if (ret < 0) {581warn("usb in operation failed. (%d)", ret);582ret = -EIO;583} else{584ret = b[0];585}586kfree(b);587return ret;588}589590static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)591{592struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;593struct az6027_device_state *state = (struct az6027_device_state *)d->priv;594595int ret, i;596u8 req;597u16 value;598u16 index;599int blen;600601mutex_lock(&state->ca_mutex);602603req = 0xC6;604value = 1;605index = 0;606blen = 0;607608ret = az6027_usb_out_op(d, req, value, index, NULL, blen);609if (ret != 0) {610warn("usb out operation failed. (%d)", ret);611goto failed;612}613614msleep(500);615req = 0xC6;616value = 0;617index = 0;618blen = 0;619620ret = az6027_usb_out_op(d, req, value, index, NULL, blen);621if (ret != 0) {622warn("usb out operation failed. (%d)", ret);623goto failed;624}625626for (i = 0; i < 15; i++) {627msleep(100);628629if (CI_CamReady(ca, slot)) {630deb_info("CAM Ready");631break;632}633}634msleep(5000);635636failed:637mutex_unlock(&state->ca_mutex);638return ret;639}640641static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)642{643return 0;644}645646static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)647{648struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;649struct az6027_device_state *state = (struct az6027_device_state *)d->priv;650651int ret;652u8 req;653u16 value;654u16 index;655int blen;656657deb_info("%s", __func__);658mutex_lock(&state->ca_mutex);659req = 0xC7;660value = 1;661index = 0;662blen = 0;663664ret = az6027_usb_out_op(d, req, value, index, NULL, blen);665if (ret != 0) {666warn("usb out operation failed. (%d)", ret);667goto failed;668}669670failed:671mutex_unlock(&state->ca_mutex);672return ret;673}674675static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)676{677struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;678struct az6027_device_state *state = (struct az6027_device_state *)d->priv;679int ret;680u8 req;681u16 value;682u16 index;683int blen;684u8 *b;685686b = kmalloc(12, GFP_KERNEL);687if (!b)688return -ENOMEM;689mutex_lock(&state->ca_mutex);690691req = 0xC5;692value = 0;693index = 0;694blen = 1;695696ret = az6027_usb_in_op(d, req, value, index, b, blen);697if (ret < 0) {698warn("usb in operation failed. (%d)", ret);699ret = -EIO;700} else701ret = 0;702703if (!ret && b[0] == 1) {704ret = DVB_CA_EN50221_POLL_CAM_PRESENT |705DVB_CA_EN50221_POLL_CAM_READY;706}707708mutex_unlock(&state->ca_mutex);709kfree(b);710return ret;711}712713714static void az6027_ci_uninit(struct dvb_usb_device *d)715{716struct az6027_device_state *state;717718deb_info("%s", __func__);719720if (NULL == d)721return;722723state = (struct az6027_device_state *)d->priv;724if (NULL == state)725return;726727if (NULL == state->ca.data)728return;729730dvb_ca_en50221_release(&state->ca);731732memset(&state->ca, 0, sizeof(state->ca));733}734735736static int az6027_ci_init(struct dvb_usb_adapter *a)737{738struct dvb_usb_device *d = a->dev;739struct az6027_device_state *state = (struct az6027_device_state *)d->priv;740int ret;741742deb_info("%s", __func__);743744mutex_init(&state->ca_mutex);745746state->ca.owner = THIS_MODULE;747state->ca.read_attribute_mem = az6027_ci_read_attribute_mem;748state->ca.write_attribute_mem = az6027_ci_write_attribute_mem;749state->ca.read_cam_control = az6027_ci_read_cam_control;750state->ca.write_cam_control = az6027_ci_write_cam_control;751state->ca.slot_reset = az6027_ci_slot_reset;752state->ca.slot_shutdown = az6027_ci_slot_shutdown;753state->ca.slot_ts_enable = az6027_ci_slot_ts_enable;754state->ca.poll_slot_status = az6027_ci_poll_slot_status;755state->ca.data = d;756757ret = dvb_ca_en50221_init(&a->dvb_adap,758&state->ca,7590, /* flags */7601);/* n_slots */761if (ret != 0) {762err("Cannot initialize CI: Error %d.", ret);763memset(&state->ca, 0, sizeof(state->ca));764return ret;765}766767deb_info("CI initialized.");768769return 0;770}771772/*773static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])774{775az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);776return 0;777}778*/779780static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)781{782783u8 buf;784int ret;785struct dvb_usb_adapter *adap = fe->dvb->priv;786787struct i2c_msg i2c_msg = {788.addr = 0x99,789.flags = 0,790.buf = &buf,791.len = 1792};793794/*795* 2 --18v796* 1 --13v797* 0 --off798*/799switch (voltage) {800case SEC_VOLTAGE_13:801buf = 1;802ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);803break;804805case SEC_VOLTAGE_18:806buf = 2;807ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);808break;809810case SEC_VOLTAGE_OFF:811buf = 0;812ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);813break;814815default:816return -EINVAL;817}818return 0;819}820821822static int az6027_frontend_poweron(struct dvb_usb_adapter *adap)823{824int ret;825u8 req;826u16 value;827u16 index;828int blen;829830req = 0xBC;831value = 1; /* power on */832index = 3;833blen = 0;834835ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);836if (ret != 0)837return -EIO;838839return 0;840}841static int az6027_frontend_reset(struct dvb_usb_adapter *adap)842{843int ret;844u8 req;845u16 value;846u16 index;847int blen;848849/* reset demodulator */850req = 0xC0;851value = 1; /* high */852index = 3;853blen = 0;854855ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);856if (ret != 0)857return -EIO;858859req = 0xC0;860value = 0; /* low */861index = 3;862blen = 0;863msleep_interruptible(200);864865ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);866if (ret != 0)867return -EIO;868869msleep_interruptible(200);870871req = 0xC0;872value = 1; /*high */873index = 3;874blen = 0;875876ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);877if (ret != 0)878return -EIO;879880msleep_interruptible(200);881return 0;882}883884static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff)885{886int ret;887u8 req;888u16 value;889u16 index;890int blen;891892/* TS passthrough */893req = 0xC7;894value = onoff;895index = 0;896blen = 0;897898ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);899if (ret != 0)900return -EIO;901902return 0;903}904905static int az6027_frontend_attach(struct dvb_usb_adapter *adap)906{907908az6027_frontend_poweron(adap);909az6027_frontend_reset(adap);910911deb_info("adap = %p, dev = %p\n", adap, adap->dev);912adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);913914if (adap->fe) {915deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address);916if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {917deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address);918adap->fe->ops.set_voltage = az6027_set_voltage;919az6027_ci_init(adap);920} else {921adap->fe = NULL;922}923} else924warn("no front-end attached\n");925926az6027_frontend_tsbypass(adap, 0);927928return 0;929}930931static struct dvb_usb_device_properties az6027_properties;932933static void az6027_usb_disconnect(struct usb_interface *intf)934{935struct dvb_usb_device *d = usb_get_intfdata(intf);936az6027_ci_uninit(d);937dvb_usb_device_exit(intf);938}939940941static int az6027_usb_probe(struct usb_interface *intf,942const struct usb_device_id *id)943{944return dvb_usb_device_init(intf,945&az6027_properties,946THIS_MODULE,947NULL,948adapter_nr);949}950951/* I2C */952static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)953{954struct dvb_usb_device *d = i2c_get_adapdata(adap);955int i = 0, j = 0, len = 0;956int ret;957u16 index;958u16 value;959int length;960u8 req;961u8 *data;962963data = kmalloc(256, GFP_KERNEL);964if (!data)965return -ENOMEM;966967if (mutex_lock_interruptible(&d->i2c_mutex) < 0) {968kfree(data);969return -EAGAIN;970}971972if (num > 2)973warn("more than 2 i2c messages at a time is not handled yet. TODO.");974975for (i = 0; i < num; i++) {976977if (msg[i].addr == 0x99) {978req = 0xBE;979index = 0;980value = msg[i].buf[0] & 0x00ff;981length = 1;982az6027_usb_out_op(d, req, value, index, data, length);983}984985if (msg[i].addr == 0xd0) {986/* write/read request */987if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {988req = 0xB9;989index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));990value = msg[i].addr + (msg[i].len << 8);991length = msg[i + 1].len + 6;992ret = az6027_usb_in_op(d, req, value, index, data, length);993len = msg[i + 1].len;994for (j = 0; j < len; j++)995msg[i + 1].buf[j] = data[j + 5];996997i++;998} else {9991000/* demod 16bit addr */1001req = 0xBD;1002index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));1003value = msg[i].addr + (2 << 8);1004length = msg[i].len - 2;1005len = msg[i].len - 2;1006for (j = 0; j < len; j++)1007data[j] = msg[i].buf[j + 2];1008az6027_usb_out_op(d, req, value, index, data, length);1009}1010}10111012if (msg[i].addr == 0xc0) {1013if (msg[i].flags & I2C_M_RD) {10141015req = 0xB9;1016index = 0x0;1017value = msg[i].addr;1018length = msg[i].len + 6;1019ret = az6027_usb_in_op(d, req, value, index, data, length);1020len = msg[i].len;1021for (j = 0; j < len; j++)1022msg[i].buf[j] = data[j + 5];10231024} else {10251026req = 0xBD;1027index = msg[i].buf[0] & 0x00FF;1028value = msg[i].addr + (1 << 8);1029length = msg[i].len - 1;1030len = msg[i].len - 1;10311032for (j = 0; j < len; j++)1033data[j] = msg[i].buf[j + 1];10341035az6027_usb_out_op(d, req, value, index, data, length);1036}1037}1038}1039mutex_unlock(&d->i2c_mutex);1040kfree(data);10411042return i;1043}104410451046static u32 az6027_i2c_func(struct i2c_adapter *adapter)1047{1048return I2C_FUNC_I2C;1049}10501051static struct i2c_algorithm az6027_i2c_algo = {1052.master_xfer = az6027_i2c_xfer,1053.functionality = az6027_i2c_func,1054};10551056int az6027_identify_state(struct usb_device *udev,1057struct dvb_usb_device_properties *props,1058struct dvb_usb_device_description **desc,1059int *cold)1060{1061u8 *b;1062s16 ret;10631064b = kmalloc(16, GFP_KERNEL);1065if (!b)1066return -ENOMEM;10671068ret = usb_control_msg(udev,1069usb_rcvctrlpipe(udev, 0),10700xb7,1071USB_TYPE_VENDOR | USB_DIR_IN,10726,10730,1074b,10756,1076USB_CTRL_GET_TIMEOUT);10771078*cold = ret <= 0;1079kfree(b);1080deb_info("cold: %d\n", *cold);1081return 0;1082}108310841085static struct usb_device_id az6027_usb_table[] = {1086{ USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) },1087{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V1) },1088{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V2) },1089{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) },1090{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },1091{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) },1092{ },1093};10941095MODULE_DEVICE_TABLE(usb, az6027_usb_table);10961097static struct dvb_usb_device_properties az6027_properties = {1098.caps = DVB_USB_IS_AN_I2C_ADAPTER,1099.usb_ctrl = CYPRESS_FX2,1100.firmware = "dvb-usb-az6027-03.fw",1101.no_reconnect = 1,11021103.size_of_priv = sizeof(struct az6027_device_state),1104.identify_state = az6027_identify_state,1105.num_adapters = 1,1106.adapter = {1107{1108.streaming_ctrl = az6027_streaming_ctrl,1109.frontend_attach = az6027_frontend_attach,11101111/* parameter for the MPEG2-data transfer */1112.stream = {1113.type = USB_BULK,1114.count = 10,1115.endpoint = 0x02,1116.u = {1117.bulk = {1118.buffersize = 4096,1119}1120}1121},1122}1123},1124/*1125.power_ctrl = az6027_power_ctrl,1126.read_mac_address = az6027_read_mac_addr,1127*/1128.rc.legacy = {1129.rc_map_table = rc_map_az6027_table,1130.rc_map_size = ARRAY_SIZE(rc_map_az6027_table),1131.rc_interval = 400,1132.rc_query = az6027_rc_query,1133},11341135.i2c_algo = &az6027_i2c_algo,11361137.num_device_descs = 6,1138.devices = {1139{1140.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",1141.cold_ids = { &az6027_usb_table[0], NULL },1142.warm_ids = { NULL },1143}, {1144.name = "TERRATEC S7",1145.cold_ids = { &az6027_usb_table[1], NULL },1146.warm_ids = { NULL },1147}, {1148.name = "TERRATEC S7 MKII",1149.cold_ids = { &az6027_usb_table[2], NULL },1150.warm_ids = { NULL },1151}, {1152.name = "Technisat SkyStar USB 2 HD CI",1153.cold_ids = { &az6027_usb_table[3], NULL },1154.warm_ids = { NULL },1155}, {1156.name = "Technisat SkyStar USB 2 HD CI",1157.cold_ids = { &az6027_usb_table[4], NULL },1158.warm_ids = { NULL },1159}, {1160.name = "Elgato EyeTV Sat",1161.cold_ids = { &az6027_usb_table[5], NULL },1162.warm_ids = { NULL },1163},1164{ NULL },1165}1166};11671168/* usb specific object needed to register this driver with the usb subsystem */1169static struct usb_driver az6027_usb_driver = {1170.name = "dvb_usb_az6027",1171.probe = az6027_usb_probe,1172.disconnect = az6027_usb_disconnect,1173.id_table = az6027_usb_table,1174};11751176/* module stuff */1177static int __init az6027_usb_module_init(void)1178{1179int result;11801181result = usb_register(&az6027_usb_driver);1182if (result) {1183err("usb_register failed. (%d)", result);1184return result;1185}11861187return 0;1188}11891190static void __exit az6027_usb_module_exit(void)1191{1192/* deregister this driver from the USB subsystem */1193usb_deregister(&az6027_usb_driver);1194}11951196module_init(az6027_usb_module_init);1197module_exit(az6027_usb_module_exit);11981199MODULE_AUTHOR("Adams Xu <[email protected]>");1200MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)");1201MODULE_VERSION("1.0");1202MODULE_LICENSE("GPL");120312041205