Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
15111 views
1
/*
2
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
3
* flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
4
* see flexcop.c for copyright information
5
*/
6
#include <media/tuner.h>
7
#include "flexcop.h"
8
#include "mt312.h"
9
#include "stv0299.h"
10
#include "s5h1420.h"
11
#include "itd1000.h"
12
#include "cx24113.h"
13
#include "cx24123.h"
14
#include "isl6421.h"
15
#include "mt352.h"
16
#include "bcm3510.h"
17
#include "nxt200x.h"
18
#include "dvb-pll.h"
19
#include "lgdt330x.h"
20
#include "tuner-simple.h"
21
#include "stv0297.h"
22
23
24
/* Can we use the specified front-end? Remember that if we are compiled
25
* into the kernel we can't call code that's in modules. */
26
#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
27
(defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
28
29
/* lnb control */
30
#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
31
static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
32
{
33
struct flexcop_device *fc = fe->dvb->priv;
34
flexcop_ibi_value v;
35
deb_tuner("polarity/voltage = %u\n", voltage);
36
37
v = fc->read_ibi_reg(fc, misc_204);
38
switch (voltage) {
39
case SEC_VOLTAGE_OFF:
40
v.misc_204.ACPI1_sig = 1;
41
break;
42
case SEC_VOLTAGE_13:
43
v.misc_204.ACPI1_sig = 0;
44
v.misc_204.LNB_L_H_sig = 0;
45
break;
46
case SEC_VOLTAGE_18:
47
v.misc_204.ACPI1_sig = 0;
48
v.misc_204.LNB_L_H_sig = 1;
49
break;
50
default:
51
err("unknown SEC_VOLTAGE value");
52
return -EINVAL;
53
}
54
return fc->write_ibi_reg(fc, misc_204, v);
55
}
56
#endif
57
58
#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
59
static int flexcop_sleep(struct dvb_frontend* fe)
60
{
61
struct flexcop_device *fc = fe->dvb->priv;
62
if (fc->fe_sleep)
63
return fc->fe_sleep(fe);
64
return 0;
65
}
66
#endif
67
68
/* SkyStar2 DVB-S rev 2.3 */
69
#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
70
static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
71
{
72
/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
73
struct flexcop_device *fc = fe->dvb->priv;
74
flexcop_ibi_value v;
75
u16 ax;
76
v.raw = 0;
77
deb_tuner("tone = %u\n",tone);
78
79
switch (tone) {
80
case SEC_TONE_ON:
81
ax = 0x01ff;
82
break;
83
case SEC_TONE_OFF:
84
ax = 0;
85
break;
86
default:
87
err("unknown SEC_TONE value");
88
return -EINVAL;
89
}
90
91
v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
92
v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
93
v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
94
return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
95
}
96
97
static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
98
{
99
flexcop_set_tone(fe, SEC_TONE_ON);
100
udelay(data ? 500 : 1000);
101
flexcop_set_tone(fe, SEC_TONE_OFF);
102
udelay(data ? 1000 : 500);
103
}
104
105
static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
106
{
107
int i, par = 1, d;
108
for (i = 7; i >= 0; i--) {
109
d = (data >> i) & 1;
110
par ^= d;
111
flexcop_diseqc_send_bit(fe, d);
112
}
113
flexcop_diseqc_send_bit(fe, par);
114
}
115
116
static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
117
int len, u8 *msg, unsigned long burst)
118
{
119
int i;
120
121
flexcop_set_tone(fe, SEC_TONE_OFF);
122
mdelay(16);
123
124
for (i = 0; i < len; i++)
125
flexcop_diseqc_send_byte(fe,msg[i]);
126
mdelay(16);
127
128
if (burst != -1) {
129
if (burst)
130
flexcop_diseqc_send_byte(fe, 0xff);
131
else {
132
flexcop_set_tone(fe, SEC_TONE_ON);
133
mdelay(12);
134
udelay(500);
135
flexcop_set_tone(fe, SEC_TONE_OFF);
136
}
137
msleep(20);
138
}
139
return 0;
140
}
141
142
static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
143
struct dvb_diseqc_master_cmd *cmd)
144
{
145
return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
146
}
147
148
static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
149
fe_sec_mini_cmd_t minicmd)
150
{
151
return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
152
}
153
154
static struct mt312_config skystar23_samsung_tbdu18132_config = {
155
.demod_address = 0x0e,
156
};
157
158
static int skystar2_rev23_attach(struct flexcop_device *fc,
159
struct i2c_adapter *i2c)
160
{
161
struct dvb_frontend_ops *ops;
162
163
fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
164
if (!fc->fe)
165
return 0;
166
167
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
168
DVB_PLL_SAMSUNG_TBDU18132))
169
return 0;
170
171
ops = &fc->fe->ops;
172
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
173
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
174
ops->set_tone = flexcop_set_tone;
175
ops->set_voltage = flexcop_set_voltage;
176
fc->fe_sleep = ops->sleep;
177
ops->sleep = flexcop_sleep;
178
return 1;
179
}
180
#else
181
#define skystar2_rev23_attach NULL
182
#endif
183
184
/* SkyStar2 DVB-S rev 2.6 */
185
#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
186
static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
187
u32 srate, u32 ratio)
188
{
189
u8 aclk = 0;
190
u8 bclk = 0;
191
192
if (srate < 1500000) {
193
aclk = 0xb7; bclk = 0x47;
194
} else if (srate < 3000000) {
195
aclk = 0xb7; bclk = 0x4b;
196
} else if (srate < 7000000) {
197
aclk = 0xb7; bclk = 0x4f;
198
} else if (srate < 14000000) {
199
aclk = 0xb7; bclk = 0x53;
200
} else if (srate < 30000000) {
201
aclk = 0xb6; bclk = 0x53;
202
} else if (srate < 45000000) {
203
aclk = 0xb4; bclk = 0x51;
204
}
205
206
stv0299_writereg(fe, 0x13, aclk);
207
stv0299_writereg(fe, 0x14, bclk);
208
stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
209
stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
210
stv0299_writereg(fe, 0x21, ratio & 0xf0);
211
return 0;
212
}
213
214
static u8 samsung_tbmu24112_inittab[] = {
215
0x01, 0x15,
216
0x02, 0x30,
217
0x03, 0x00,
218
0x04, 0x7D,
219
0x05, 0x35,
220
0x06, 0x02,
221
0x07, 0x00,
222
0x08, 0xC3,
223
0x0C, 0x00,
224
0x0D, 0x81,
225
0x0E, 0x23,
226
0x0F, 0x12,
227
0x10, 0x7E,
228
0x11, 0x84,
229
0x12, 0xB9,
230
0x13, 0x88,
231
0x14, 0x89,
232
0x15, 0xC9,
233
0x16, 0x00,
234
0x17, 0x5C,
235
0x18, 0x00,
236
0x19, 0x00,
237
0x1A, 0x00,
238
0x1C, 0x00,
239
0x1D, 0x00,
240
0x1E, 0x00,
241
0x1F, 0x3A,
242
0x20, 0x2E,
243
0x21, 0x80,
244
0x22, 0xFF,
245
0x23, 0xC1,
246
0x28, 0x00,
247
0x29, 0x1E,
248
0x2A, 0x14,
249
0x2B, 0x0F,
250
0x2C, 0x09,
251
0x2D, 0x05,
252
0x31, 0x1F,
253
0x32, 0x19,
254
0x33, 0xFE,
255
0x34, 0x93,
256
0xff, 0xff,
257
};
258
259
static struct stv0299_config samsung_tbmu24112_config = {
260
.demod_address = 0x68,
261
.inittab = samsung_tbmu24112_inittab,
262
.mclk = 88000000UL,
263
.invert = 0,
264
.skip_reinit = 0,
265
.lock_output = STV0299_LOCKOUTPUT_LK,
266
.volt13_op0_op1 = STV0299_VOLT13_OP1,
267
.min_delay_ms = 100,
268
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
269
};
270
271
static int skystar2_rev26_attach(struct flexcop_device *fc,
272
struct i2c_adapter *i2c)
273
{
274
fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
275
if (!fc->fe)
276
return 0;
277
278
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
279
DVB_PLL_SAMSUNG_TBMU24112))
280
return 0;
281
282
fc->fe->ops.set_voltage = flexcop_set_voltage;
283
fc->fe_sleep = fc->fe->ops.sleep;
284
fc->fe->ops.sleep = flexcop_sleep;
285
return 1;
286
287
}
288
#else
289
#define skystar2_rev26_attach NULL
290
#endif
291
292
/* SkyStar2 DVB-S rev 2.7 */
293
#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
294
static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
295
.demod_address = 0x53,
296
.invert = 1,
297
.repeated_start_workaround = 1,
298
.serial_mpeg = 1,
299
};
300
301
static struct itd1000_config skystar2_rev2_7_itd1000_config = {
302
.i2c_address = 0x61,
303
};
304
305
static int skystar2_rev27_attach(struct flexcop_device *fc,
306
struct i2c_adapter *i2c)
307
{
308
flexcop_ibi_value r108;
309
struct i2c_adapter *i2c_tuner;
310
311
/* enable no_base_addr - no repeated start when reading */
312
fc->fc_i2c_adap[0].no_base_addr = 1;
313
fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
314
i2c);
315
if (!fc->fe)
316
goto fail;
317
318
i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
319
if (!i2c_tuner)
320
goto fail;
321
322
fc->fe_sleep = fc->fe->ops.sleep;
323
fc->fe->ops.sleep = flexcop_sleep;
324
325
/* enable no_base_addr - no repeated start when reading */
326
fc->fc_i2c_adap[2].no_base_addr = 1;
327
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
328
0x08, 1, 1)) {
329
err("ISL6421 could NOT be attached");
330
goto fail_isl;
331
}
332
info("ISL6421 successfully attached");
333
334
/* the ITD1000 requires a lower i2c clock - is it a problem ? */
335
r108.raw = 0x00000506;
336
fc->write_ibi_reg(fc, tw_sm_c_108, r108);
337
if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
338
&skystar2_rev2_7_itd1000_config)) {
339
err("ITD1000 could NOT be attached");
340
/* Should i2c clock be restored? */
341
goto fail_isl;
342
}
343
info("ITD1000 successfully attached");
344
345
return 1;
346
347
fail_isl:
348
fc->fc_i2c_adap[2].no_base_addr = 0;
349
fail:
350
/* for the next devices we need it again */
351
fc->fc_i2c_adap[0].no_base_addr = 0;
352
return 0;
353
}
354
#else
355
#define skystar2_rev27_attach NULL
356
#endif
357
358
/* SkyStar2 rev 2.8 */
359
#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
360
static struct cx24123_config skystar2_rev2_8_cx24123_config = {
361
.demod_address = 0x55,
362
.dont_use_pll = 1,
363
.agc_callback = cx24113_agc_callback,
364
};
365
366
static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
367
.i2c_addr = 0x54,
368
.xtal_khz = 10111,
369
};
370
371
static int skystar2_rev28_attach(struct flexcop_device *fc,
372
struct i2c_adapter *i2c)
373
{
374
struct i2c_adapter *i2c_tuner;
375
376
fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
377
i2c);
378
if (!fc->fe)
379
return 0;
380
381
i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
382
if (!i2c_tuner)
383
return 0;
384
385
if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
386
i2c_tuner)) {
387
err("CX24113 could NOT be attached");
388
return 0;
389
}
390
info("CX24113 successfully attached");
391
392
fc->fc_i2c_adap[2].no_base_addr = 1;
393
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
394
0x08, 0, 0)) {
395
err("ISL6421 could NOT be attached");
396
fc->fc_i2c_adap[2].no_base_addr = 0;
397
return 0;
398
}
399
info("ISL6421 successfully attached");
400
/* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
401
* IR-receiver (PIC16F818) - but the card has no input for that ??? */
402
return 1;
403
}
404
#else
405
#define skystar2_rev28_attach NULL
406
#endif
407
408
/* AirStar DVB-T */
409
#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
410
static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
411
{
412
static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
413
static u8 mt352_reset[] = { 0x50, 0x80 };
414
static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
415
static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
416
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
417
418
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
419
udelay(2000);
420
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
421
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
422
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
423
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
424
return 0;
425
}
426
427
static struct mt352_config samsung_tdtc9251dh0_config = {
428
.demod_address = 0x0f,
429
.demod_init = samsung_tdtc9251dh0_demod_init,
430
};
431
432
static int airstar_dvbt_attach(struct flexcop_device *fc,
433
struct i2c_adapter *i2c)
434
{
435
fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
436
if (!fc->fe)
437
return 0;
438
439
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
440
DVB_PLL_SAMSUNG_TDTC9251DH0);
441
}
442
#else
443
#define airstar_dvbt_attach NULL
444
#endif
445
446
/* AirStar ATSC 1st generation */
447
#if FE_SUPPORTED(BCM3510)
448
static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
449
const struct firmware **fw, char* name)
450
{
451
struct flexcop_device *fc = fe->dvb->priv;
452
return request_firmware(fw, name, fc->dev);
453
}
454
455
static struct bcm3510_config air2pc_atsc_first_gen_config = {
456
.demod_address = 0x0f,
457
.request_firmware = flexcop_fe_request_firmware,
458
};
459
460
static int airstar_atsc1_attach(struct flexcop_device *fc,
461
struct i2c_adapter *i2c)
462
{
463
fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
464
return fc->fe != NULL;
465
}
466
#else
467
#define airstar_atsc1_attach NULL
468
#endif
469
470
/* AirStar ATSC 2nd generation */
471
#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
472
static struct nxt200x_config samsung_tbmv_config = {
473
.demod_address = 0x0a,
474
};
475
476
static int airstar_atsc2_attach(struct flexcop_device *fc,
477
struct i2c_adapter *i2c)
478
{
479
fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
480
if (!fc->fe)
481
return 0;
482
483
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
484
DVB_PLL_SAMSUNG_TBMV);
485
}
486
#else
487
#define airstar_atsc2_attach NULL
488
#endif
489
490
/* AirStar ATSC 3rd generation */
491
#if FE_SUPPORTED(LGDT330X)
492
static struct lgdt330x_config air2pc_atsc_hd5000_config = {
493
.demod_address = 0x59,
494
.demod_chip = LGDT3303,
495
.serial_mpeg = 0x04,
496
.clock_polarity_flip = 1,
497
};
498
499
static int airstar_atsc3_attach(struct flexcop_device *fc,
500
struct i2c_adapter *i2c)
501
{
502
fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
503
if (!fc->fe)
504
return 0;
505
506
return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
507
TUNER_LG_TDVS_H06XF);
508
}
509
#else
510
#define airstar_atsc3_attach NULL
511
#endif
512
513
/* CableStar2 DVB-C */
514
#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
515
static u8 alps_tdee4_stv0297_inittab[] = {
516
0x80, 0x01,
517
0x80, 0x00,
518
0x81, 0x01,
519
0x81, 0x00,
520
0x00, 0x48,
521
0x01, 0x58,
522
0x03, 0x00,
523
0x04, 0x00,
524
0x07, 0x00,
525
0x08, 0x00,
526
0x30, 0xff,
527
0x31, 0x9d,
528
0x32, 0xff,
529
0x33, 0x00,
530
0x34, 0x29,
531
0x35, 0x55,
532
0x36, 0x80,
533
0x37, 0x6e,
534
0x38, 0x9c,
535
0x40, 0x1a,
536
0x41, 0xfe,
537
0x42, 0x33,
538
0x43, 0x00,
539
0x44, 0xff,
540
0x45, 0x00,
541
0x46, 0x00,
542
0x49, 0x04,
543
0x4a, 0x51,
544
0x4b, 0xf8,
545
0x52, 0x30,
546
0x53, 0x06,
547
0x59, 0x06,
548
0x5a, 0x5e,
549
0x5b, 0x04,
550
0x61, 0x49,
551
0x62, 0x0a,
552
0x70, 0xff,
553
0x71, 0x04,
554
0x72, 0x00,
555
0x73, 0x00,
556
0x74, 0x0c,
557
0x80, 0x20,
558
0x81, 0x00,
559
0x82, 0x30,
560
0x83, 0x00,
561
0x84, 0x04,
562
0x85, 0x22,
563
0x86, 0x08,
564
0x87, 0x1b,
565
0x88, 0x00,
566
0x89, 0x00,
567
0x90, 0x00,
568
0x91, 0x04,
569
0xa0, 0x86,
570
0xa1, 0x00,
571
0xa2, 0x00,
572
0xb0, 0x91,
573
0xb1, 0x0b,
574
0xc0, 0x5b,
575
0xc1, 0x10,
576
0xc2, 0x12,
577
0xd0, 0x02,
578
0xd1, 0x00,
579
0xd2, 0x00,
580
0xd3, 0x00,
581
0xd4, 0x02,
582
0xd5, 0x00,
583
0xde, 0x00,
584
0xdf, 0x01,
585
0xff, 0xff,
586
};
587
588
static struct stv0297_config alps_tdee4_stv0297_config = {
589
.demod_address = 0x1c,
590
.inittab = alps_tdee4_stv0297_inittab,
591
};
592
593
static int cablestar2_attach(struct flexcop_device *fc,
594
struct i2c_adapter *i2c)
595
{
596
fc->fc_i2c_adap[0].no_base_addr = 1;
597
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
598
if (!fc->fe)
599
goto fail;
600
601
/* This tuner doesn't use the stv0297's I2C gate, but instead the
602
* tuner is connected to a different flexcop I2C adapter. */
603
if (fc->fe->ops.i2c_gate_ctrl)
604
fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
605
fc->fe->ops.i2c_gate_ctrl = NULL;
606
607
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
608
&fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
609
goto fail;
610
611
return 1;
612
613
fail:
614
/* Reset for next frontend to try */
615
fc->fc_i2c_adap[0].no_base_addr = 0;
616
return 0;
617
}
618
#else
619
#define cablestar2_attach NULL
620
#endif
621
622
static struct {
623
flexcop_device_type_t type;
624
int (*attach)(struct flexcop_device *, struct i2c_adapter *);
625
} flexcop_frontends[] = {
626
{ FC_SKY_REV27, skystar2_rev27_attach },
627
{ FC_SKY_REV28, skystar2_rev28_attach },
628
{ FC_SKY_REV26, skystar2_rev26_attach },
629
{ FC_AIR_DVBT, airstar_dvbt_attach },
630
{ FC_AIR_ATSC2, airstar_atsc2_attach },
631
{ FC_AIR_ATSC3, airstar_atsc3_attach },
632
{ FC_AIR_ATSC1, airstar_atsc1_attach },
633
{ FC_CABLE, cablestar2_attach },
634
{ FC_SKY_REV23, skystar2_rev23_attach },
635
};
636
637
/* try to figure out the frontend */
638
int flexcop_frontend_init(struct flexcop_device *fc)
639
{
640
int i;
641
for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
642
if (!flexcop_frontends[i].attach)
643
continue;
644
/* type needs to be set before, because of some workarounds
645
* done based on the probed card type */
646
fc->dev_type = flexcop_frontends[i].type;
647
if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
648
goto fe_found;
649
/* Clean up partially attached frontend */
650
if (fc->fe) {
651
dvb_frontend_detach(fc->fe);
652
fc->fe = NULL;
653
}
654
}
655
fc->dev_type = FC_UNK;
656
err("no frontend driver found for this B2C2/FlexCop adapter");
657
return -ENODEV;
658
659
fe_found:
660
info("found '%s' .", fc->fe->ops.info.name);
661
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
662
err("frontend registration failed!");
663
dvb_frontend_detach(fc->fe);
664
fc->fe = NULL;
665
return -EINVAL;
666
}
667
fc->init_state |= FC_STATE_FE_INIT;
668
return 0;
669
}
670
671
void flexcop_frontend_exit(struct flexcop_device *fc)
672
{
673
if (fc->init_state & FC_STATE_FE_INIT) {
674
dvb_unregister_frontend(fc->fe);
675
dvb_frontend_detach(fc->fe);
676
}
677
fc->init_state &= ~FC_STATE_FE_INIT;
678
}
679
680