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