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