[PATCH] drivers/media: convert to dynamic input_dev allocation
[deliverable/linux.git] / drivers / media / dvb / ttpci / budget-ci.c
CommitLineData
1da177e4
LT
1/*
2 * budget-ci.c: driver for the SAA7146 based Budget DVB cards
3 *
4 * Compiled from various sources by Michael Hunold <michael@mihu.de>
5 *
6 * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
7 * partially based on the Siemens DVB driver by Ralph+Marcus Metzler
8 *
9 * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27 *
28 *
29 * the project's page is at http://www.linuxtv.org/dvb/
30 */
31
32#include "budget.h"
33
34#include <linux/module.h>
35#include <linux/errno.h>
36#include <linux/slab.h>
37#include <linux/interrupt.h>
38#include <linux/input.h>
39#include <linux/spinlock.h>
40
41#include "dvb_ca_en50221.h"
42#include "stv0299.h"
dc27a169 43#include "stv0297.h"
1da177e4
LT
44#include "tda1004x.h"
45
46#define DEBIADDR_IR 0x1234
47#define DEBIADDR_CICONTROL 0x0000
48#define DEBIADDR_CIVERSION 0x4000
49#define DEBIADDR_IO 0x1000
50#define DEBIADDR_ATTR 0x3000
51
52#define CICONTROL_RESET 0x01
53#define CICONTROL_ENABLETS 0x02
54#define CICONTROL_CAMDETECT 0x08
55
56#define DEBICICTL 0x00420000
57#define DEBICICAM 0x02420000
58
59#define SLOTSTATUS_NONE 1
60#define SLOTSTATUS_PRESENT 2
61#define SLOTSTATUS_RESET 4
62#define SLOTSTATUS_READY 8
63#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
64
65struct budget_ci {
66 struct budget budget;
b7df3910 67 struct input_dev *input_dev;
1da177e4
LT
68 struct tasklet_struct msp430_irq_tasklet;
69 struct tasklet_struct ciintf_irq_tasklet;
70 int slot_status;
71 struct dvb_ca_en50221 ca;
72 char ir_dev_name[50];
dd2bbb17 73 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
1da177e4
LT
74};
75
76/* from reading the following remotes:
77 Zenith Universal 7 / TV Mode 807 / VCR Mode 837
78 Hauppauge (from NOVA-CI-s box product)
79 i've taken a "middle of the road" approach and note the differences
80*/
81static u16 key_map[64] = {
82 /* 0x0X */
83 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
84 KEY_9,
85 KEY_ENTER,
86 KEY_RED,
87 KEY_POWER, /* RADIO on Hauppauge */
88 KEY_MUTE,
89 0,
90 KEY_A, /* TV on Hauppauge */
91 /* 0x1X */
92 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
93 0, 0,
94 KEY_B,
95 0, 0, 0, 0, 0, 0, 0,
96 KEY_UP, KEY_DOWN,
97 KEY_OPTION, /* RESERVED on Hauppauge */
98 KEY_BREAK,
99 /* 0x2X */
100 KEY_CHANNELUP, KEY_CHANNELDOWN,
101 KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
102 0, KEY_RESTART, KEY_OK,
103 KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
104 0,
105 KEY_ENTER, /* VCR mode on Zenith */
106 KEY_PAUSE,
107 0,
108 KEY_RIGHT, KEY_LEFT,
109 0,
110 KEY_MENU, /* FULL SCREEN on Hauppauge */
111 0,
112 /* 0x3X */
113 KEY_SLOW,
114 KEY_PREVIOUS, /* VCR mode on Zenith */
115 KEY_REWIND,
116 0,
117 KEY_FASTFORWARD,
118 KEY_PLAY, KEY_STOP,
119 KEY_RECORD,
120 KEY_TUNER, /* TV/VCR on Zenith */
121 0,
122 KEY_C,
123 0,
124 KEY_EXIT,
125 KEY_POWER2,
126 KEY_TUNER, /* VCR mode on Zenith */
127 0,
128};
129
130static void msp430_ir_debounce(unsigned long data)
131{
132 struct input_dev *dev = (struct input_dev *) data;
133
134 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
135 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
136 return;
137 }
138
139 dev->rep[0] = 0;
140 dev->timer.expires = jiffies + HZ * 350 / 1000;
141 add_timer(&dev->timer);
142 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
143}
144
145static void msp430_ir_interrupt(unsigned long data)
146{
147 struct budget_ci *budget_ci = (struct budget_ci *) data;
b7df3910 148 struct input_dev *dev = budget_ci->input_dev;
1da177e4
LT
149 unsigned int code =
150 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
151
152 if (code & 0x40) {
153 code &= 0x3f;
154
155 if (timer_pending(&dev->timer)) {
156 if (code == dev->repeat_key) {
157 ++dev->rep[0];
158 return;
159 }
160 del_timer(&dev->timer);
161 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
162 }
163
164 if (!key_map[code]) {
165 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
166 return;
167 }
168
169 /* initialize debounce and repeat */
170 dev->repeat_key = code;
171 /* Zenith remote _always_ sends 2 sequences */
172 dev->rep[0] = ~0;
173 /* 350 milliseconds */
174 dev->timer.expires = jiffies + HZ * 350 / 1000;
175 /* MAKE */
176 input_event(dev, EV_KEY, key_map[code], !0);
177 add_timer(&dev->timer);
178 }
179}
180
181static int msp430_ir_init(struct budget_ci *budget_ci)
182{
183 struct saa7146_dev *saa = budget_ci->budget.dev;
b7df3910 184 struct input_dev *input_dev;
1da177e4
LT
185 int i;
186
b7df3910
DT
187 budget_ci->input_dev = input_dev = input_allocate_device();
188 if (!input_dev)
189 return -ENOMEM;
1da177e4
LT
190
191 sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
1da177e4 192
b7df3910 193 input_dev->name = budget_ci->ir_dev_name;
1da177e4 194
b7df3910
DT
195 set_bit(EV_KEY, input_dev->evbit);
196 for (i = 0; i < ARRAY_SIZE(key_map); i++)
1da177e4 197 if (key_map[i])
b7df3910 198 set_bit(key_map[i], input_dev->keybit);
1da177e4 199
b7df3910 200 input_register_device(budget_ci->input_dev);
1da177e4 201
b7df3910 202 input_dev->timer.function = msp430_ir_debounce;
1da177e4
LT
203
204 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
1da177e4
LT
205 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
206
207 return 0;
208}
209
210static void msp430_ir_deinit(struct budget_ci *budget_ci)
211{
212 struct saa7146_dev *saa = budget_ci->budget.dev;
b7df3910 213 struct input_dev *dev = budget_ci->input_dev;
1da177e4
LT
214
215 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
216 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
217
218 if (del_timer(&dev->timer))
219 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
220
221 input_unregister_device(dev);
222}
223
224static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
225{
226 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
227
228 if (slot != 0)
229 return -EINVAL;
230
231 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
232 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
233}
234
235static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
236{
237 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
238
239 if (slot != 0)
240 return -EINVAL;
241
242 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
243 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
244}
245
246static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
247{
248 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
249
250 if (slot != 0)
251 return -EINVAL;
252
253 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
254 DEBIADDR_IO | (address & 3), 1, 1, 0);
255}
256
257static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
258{
259 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
260
261 if (slot != 0)
262 return -EINVAL;
263
264 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
265 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
266}
267
268static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
269{
270 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
271 struct saa7146_dev *saa = budget_ci->budget.dev;
272
273 if (slot != 0)
274 return -EINVAL;
275
276 // trigger on RISING edge during reset so we know when READY is re-asserted
277 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
278 budget_ci->slot_status = SLOTSTATUS_RESET;
279 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
280 msleep(1);
281 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
282 CICONTROL_RESET, 1, 0);
283
284 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
285 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
286 return 0;
287}
288
289static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
290{
291 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
292 struct saa7146_dev *saa = budget_ci->budget.dev;
293
294 if (slot != 0)
295 return -EINVAL;
296
297 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
298 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
299 return 0;
300}
301
302static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
303{
304 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
305 struct saa7146_dev *saa = budget_ci->budget.dev;
306 int tmp;
307
308 if (slot != 0)
309 return -EINVAL;
310
311 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
312
313 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
314 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
315 tmp | CICONTROL_ENABLETS, 1, 0);
316
317 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
318 return 0;
319}
320
321static void ciintf_interrupt(unsigned long data)
322{
323 struct budget_ci *budget_ci = (struct budget_ci *) data;
324 struct saa7146_dev *saa = budget_ci->budget.dev;
325 unsigned int flags;
326
327 // ensure we don't get spurious IRQs during initialisation
328 if (!budget_ci->budget.ci_present)
329 return;
330
331 // read the CAM status
332 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
333 if (flags & CICONTROL_CAMDETECT) {
334
335 // GPIO should be set to trigger on falling edge if a CAM is present
336 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
337
338 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
339 // CAM insertion IRQ
340 budget_ci->slot_status = SLOTSTATUS_PRESENT;
341 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
342 DVB_CA_EN50221_CAMCHANGE_INSERTED);
343
344 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
345 // CAM ready (reset completed)
346 budget_ci->slot_status = SLOTSTATUS_READY;
347 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
348
349 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
350 // FR/DA IRQ
351 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
352 }
353 } else {
354
355 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
356 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
357 // the CAM might not actually be ready yet.
358 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
359
360 // generate a CAM removal IRQ if we haven't already
361 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
362 // CAM removal IRQ
363 budget_ci->slot_status = SLOTSTATUS_NONE;
364 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
365 DVB_CA_EN50221_CAMCHANGE_REMOVED);
366 }
367 }
368}
369
370static int ciintf_init(struct budget_ci *budget_ci)
371{
372 struct saa7146_dev *saa = budget_ci->budget.dev;
373 int flags;
374 int result;
375
376 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
377
378 // enable DEBI pins
379 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
380
381 // test if it is there
382 if ((ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0) & 0xa0) != 0xa0) {
383 result = -ENODEV;
384 goto error;
385 }
386 // determine whether a CAM is present or not
387 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
388 budget_ci->slot_status = SLOTSTATUS_NONE;
389 if (flags & CICONTROL_CAMDETECT)
390 budget_ci->slot_status = SLOTSTATUS_PRESENT;
391
392 // register CI interface
393 budget_ci->ca.owner = THIS_MODULE;
394 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
395 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
396 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
397 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
398 budget_ci->ca.slot_reset = ciintf_slot_reset;
399 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
400 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
401 budget_ci->ca.data = budget_ci;
fdc53a6d 402 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
1da177e4
LT
403 &budget_ci->ca,
404 DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
405 DVB_CA_EN50221_FLAG_IRQ_FR |
406 DVB_CA_EN50221_FLAG_IRQ_DA, 1)) != 0) {
407 printk("budget_ci: CI interface detected, but initialisation failed.\n");
408 goto error;
409 }
410 // Setup CI slot IRQ
411 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
412 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
413 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
414 } else {
415 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
416 }
417 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
418 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
419 CICONTROL_RESET, 1, 0);
420
421 // success!
422 printk("budget_ci: CI interface initialised\n");
423 budget_ci->budget.ci_present = 1;
424
425 // forge a fake CI IRQ so the CAM state is setup correctly
426 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
427 if (budget_ci->slot_status != SLOTSTATUS_NONE)
428 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
429 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
430
431 return 0;
432
433error:
434 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
435 return result;
436}
437
438static void ciintf_deinit(struct budget_ci *budget_ci)
439{
440 struct saa7146_dev *saa = budget_ci->budget.dev;
441
442 // disable CI interrupts
443 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
444 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
445 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
446 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
447 msleep(1);
448 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
449 CICONTROL_RESET, 1, 0);
450
451 // disable TS data stream to CI interface
452 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
453
454 // release the CA device
455 dvb_ca_en50221_release(&budget_ci->ca);
456
457 // disable DEBI pins
458 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
459}
460
461static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
462{
463 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
464
465 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
466
467 if (*isr & MASK_06)
468 tasklet_schedule(&budget_ci->msp430_irq_tasklet);
469
470 if (*isr & MASK_10)
471 ttpci_budget_irq10_handler(dev, isr);
472
473 if ((*isr & MASK_03) && (budget_ci->budget.ci_present))
474 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
475}
476
477
478static u8 alps_bsru6_inittab[] = {
479 0x01, 0x15,
480 0x02, 0x00,
481 0x03, 0x00,
482 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
483 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
484 0x06, 0x40, /* DAC not used, set to high impendance mode */
485 0x07, 0x00, /* DAC LSB */
486 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
487 0x09, 0x00, /* FIFO */
488 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
489 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
490 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
491 0x10, 0x3f, // AGC2 0x3d
492 0x11, 0x84,
493 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
494 0x15, 0xc9, // lock detector threshold
495 0x16, 0x00,
496 0x17, 0x00,
497 0x18, 0x00,
498 0x19, 0x00,
499 0x1a, 0x00,
500 0x1f, 0x50,
501 0x20, 0x00,
502 0x21, 0x00,
503 0x22, 0x00,
504 0x23, 0x00,
505 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
506 0x29, 0x1e, // 1/2 threshold
507 0x2a, 0x14, // 2/3 threshold
508 0x2b, 0x0f, // 3/4 threshold
509 0x2c, 0x09, // 5/6 threshold
510 0x2d, 0x05, // 7/8 threshold
511 0x2e, 0x01,
512 0x31, 0x1f, // test all FECs
513 0x32, 0x19, // viterbi and synchro search
514 0x33, 0xfc, // rs control
515 0x34, 0x93, // error control
516 0x0f, 0x52,
517 0xff, 0xff
518};
519
520static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
521{
522 u8 aclk = 0;
523 u8 bclk = 0;
524
525 if (srate < 1500000) {
526 aclk = 0xb7;
527 bclk = 0x47;
528 } else if (srate < 3000000) {
529 aclk = 0xb7;
530 bclk = 0x4b;
531 } else if (srate < 7000000) {
532 aclk = 0xb7;
533 bclk = 0x4f;
534 } else if (srate < 14000000) {
535 aclk = 0xb7;
536 bclk = 0x53;
537 } else if (srate < 30000000) {
538 aclk = 0xb6;
539 bclk = 0x53;
540 } else if (srate < 45000000) {
541 aclk = 0xb4;
542 bclk = 0x51;
543 }
544
545 stv0299_writereg(fe, 0x13, aclk);
546 stv0299_writereg(fe, 0x14, bclk);
547 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
548 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
549 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
550
551 return 0;
552}
553
cfbfce15 554static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
1da177e4 555{
1da177e4
LT
556 u8 buf[4];
557 u32 div;
558 struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
559
560 if ((params->frequency < 950000) || (params->frequency > 2150000))
561 return -EINVAL;
562
563 div = (params->frequency + (125 - 1)) / 125; // round correctly
564 buf[0] = (div >> 8) & 0x7f;
565 buf[1] = div & 0xff;
566 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
567 buf[3] = 0xC4;
568
569 if (params->frequency > 1530000)
570 buf[3] = 0xc0;
571
cfbfce15 572 if (i2c_transfer(i2c, &msg, 1) != 1)
1da177e4
LT
573 return -EIO;
574 return 0;
575}
576
577static struct stv0299_config alps_bsru6_config = {
578
579 .demod_address = 0x68,
580 .inittab = alps_bsru6_inittab,
581 .mclk = 88000000UL,
582 .invert = 1,
583 .enhanced_tuning = 0,
584 .skip_reinit = 0,
585 .lock_output = STV0229_LOCKOUTPUT_1,
586 .volt13_op0_op1 = STV0299_VOLT13_OP1,
587 .min_delay_ms = 100,
588 .set_symbol_rate = alps_bsru6_set_symbol_rate,
589 .pll_set = alps_bsru6_pll_set,
590};
591
592
593
594
595static u8 philips_su1278_tt_inittab[] = {
596 0x01, 0x0f,
597 0x02, 0x30,
598 0x03, 0x00,
599 0x04, 0x5b,
600 0x05, 0x85,
601 0x06, 0x02,
602 0x07, 0x00,
603 0x08, 0x02,
604 0x09, 0x00,
605 0x0C, 0x01,
606 0x0D, 0x81,
607 0x0E, 0x44,
608 0x0f, 0x14,
609 0x10, 0x3c,
610 0x11, 0x84,
611 0x12, 0xda,
612 0x13, 0x97,
613 0x14, 0x95,
614 0x15, 0xc9,
615 0x16, 0x19,
616 0x17, 0x8c,
617 0x18, 0x59,
618 0x19, 0xf8,
619 0x1a, 0xfe,
620 0x1c, 0x7f,
621 0x1d, 0x00,
622 0x1e, 0x00,
623 0x1f, 0x50,
624 0x20, 0x00,
625 0x21, 0x00,
626 0x22, 0x00,
627 0x23, 0x00,
628 0x28, 0x00,
629 0x29, 0x28,
630 0x2a, 0x14,
631 0x2b, 0x0f,
632 0x2c, 0x09,
633 0x2d, 0x09,
634 0x31, 0x1f,
635 0x32, 0x19,
636 0x33, 0xfc,
637 0x34, 0x93,
638 0xff, 0xff
639};
640
641static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
642{
643 stv0299_writereg(fe, 0x0e, 0x44);
644 if (srate >= 10000000) {
645 stv0299_writereg(fe, 0x13, 0x97);
646 stv0299_writereg(fe, 0x14, 0x95);
647 stv0299_writereg(fe, 0x15, 0xc9);
648 stv0299_writereg(fe, 0x17, 0x8c);
649 stv0299_writereg(fe, 0x1a, 0xfe);
650 stv0299_writereg(fe, 0x1c, 0x7f);
651 stv0299_writereg(fe, 0x2d, 0x09);
652 } else {
653 stv0299_writereg(fe, 0x13, 0x99);
654 stv0299_writereg(fe, 0x14, 0x8d);
655 stv0299_writereg(fe, 0x15, 0xce);
656 stv0299_writereg(fe, 0x17, 0x43);
657 stv0299_writereg(fe, 0x1a, 0x1d);
658 stv0299_writereg(fe, 0x1c, 0x12);
659 stv0299_writereg(fe, 0x2d, 0x05);
660 }
661 stv0299_writereg(fe, 0x0e, 0x23);
662 stv0299_writereg(fe, 0x0f, 0x94);
663 stv0299_writereg(fe, 0x10, 0x39);
664 stv0299_writereg(fe, 0x15, 0xc9);
665
666 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
667 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
668 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
669
670 return 0;
671}
672
673static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
cfbfce15 674 struct i2c_adapter *i2c,
1da177e4
LT
675 struct dvb_frontend_parameters *params)
676{
1da177e4
LT
677 u32 div;
678 u8 buf[4];
679 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
680
681 if ((params->frequency < 950000) || (params->frequency > 2150000))
682 return -EINVAL;
683
684 div = (params->frequency + (500 - 1)) / 500; // round correctly
685 buf[0] = (div >> 8) & 0x7f;
686 buf[1] = div & 0xff;
687 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
688 buf[3] = 0x20;
689
690 if (params->u.qpsk.symbol_rate < 4000000)
691 buf[3] |= 1;
692
693 if (params->frequency < 1250000)
694 buf[3] |= 0;
695 else if (params->frequency < 1550000)
696 buf[3] |= 0x40;
697 else if (params->frequency < 2050000)
698 buf[3] |= 0x80;
699 else if (params->frequency < 2150000)
700 buf[3] |= 0xC0;
701
cfbfce15 702 if (i2c_transfer(i2c, &msg, 1) != 1)
1da177e4
LT
703 return -EIO;
704 return 0;
705}
706
707static struct stv0299_config philips_su1278_tt_config = {
708
709 .demod_address = 0x68,
710 .inittab = philips_su1278_tt_inittab,
711 .mclk = 64000000UL,
712 .invert = 0,
713 .enhanced_tuning = 1,
714 .skip_reinit = 1,
715 .lock_output = STV0229_LOCKOUTPUT_1,
716 .volt13_op0_op1 = STV0299_VOLT13_OP1,
717 .min_delay_ms = 50,
718 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
719 .pll_set = philips_su1278_tt_pll_set,
720};
721
722
723
724static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
725{
726 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
727 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
728 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
dd2bbb17 729 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
1da177e4
LT
730 sizeof(td1316_init) };
731
732 // setup PLL configuration
733 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
734 return -EIO;
735 msleep(1);
736
737 // disable the mc44BC374c (do not check for errors)
738 tuner_msg.addr = 0x65;
739 tuner_msg.buf = disable_mc44BC374c;
740 tuner_msg.len = sizeof(disable_mc44BC374c);
741 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
742 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
743 }
744
745 return 0;
746}
747
748static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
749{
750 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
751 u8 tuner_buf[4];
dd2bbb17 752 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
1da177e4
LT
753 int tuner_frequency = 0;
754 u8 band, cp, filter;
755
756 // determine charge pump
757 tuner_frequency = params->frequency + 36130000;
758 if (tuner_frequency < 87000000)
759 return -EINVAL;
760 else if (tuner_frequency < 130000000)
761 cp = 3;
762 else if (tuner_frequency < 160000000)
763 cp = 5;
764 else if (tuner_frequency < 200000000)
765 cp = 6;
766 else if (tuner_frequency < 290000000)
767 cp = 3;
768 else if (tuner_frequency < 420000000)
769 cp = 5;
770 else if (tuner_frequency < 480000000)
771 cp = 6;
772 else if (tuner_frequency < 620000000)
773 cp = 3;
774 else if (tuner_frequency < 830000000)
775 cp = 5;
776 else if (tuner_frequency < 895000000)
777 cp = 7;
778 else
779 return -EINVAL;
780
781 // determine band
782 if (params->frequency < 49000000)
783 return -EINVAL;
784 else if (params->frequency < 159000000)
785 band = 1;
786 else if (params->frequency < 444000000)
787 band = 2;
788 else if (params->frequency < 861000000)
789 band = 4;
790 else
791 return -EINVAL;
792
793 // setup PLL filter and TDA9889
794 switch (params->u.ofdm.bandwidth) {
795 case BANDWIDTH_6_MHZ:
796 tda1004x_write_byte(fe, 0x0C, 0x14);
797 filter = 0;
798 break;
799
800 case BANDWIDTH_7_MHZ:
801 tda1004x_write_byte(fe, 0x0C, 0x80);
802 filter = 0;
803 break;
804
805 case BANDWIDTH_8_MHZ:
806 tda1004x_write_byte(fe, 0x0C, 0x14);
807 filter = 1;
808 break;
809
810 default:
811 return -EINVAL;
812 }
813
814 // calculate divisor
815 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
816 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
817
818 // setup tuner buffer
819 tuner_buf[0] = tuner_frequency >> 8;
820 tuner_buf[1] = tuner_frequency & 0xff;
821 tuner_buf[2] = 0xca;
822 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
823
824 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
825 return -EIO;
826
827 msleep(1);
828 return 0;
829}
830
831static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
832 const struct firmware **fw, char *name)
833{
834 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
835
836 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
837}
838
839static struct tda1004x_config philips_tdm1316l_config = {
840
841 .demod_address = 0x8,
842 .invert = 0,
843 .invert_oclk = 0,
ecb60deb
HH
844 .xtal_freq = TDA10046_XTAL_4M,
845 .agc_config = TDA10046_AGC_DEFAULT,
846 .if_freq = TDA10046_FREQ_3617,
1da177e4
LT
847 .pll_init = philips_tdm1316l_pll_init,
848 .pll_set = philips_tdm1316l_pll_set,
ecb60deb 849 .pll_sleep = NULL,
1da177e4
LT
850 .request_firmware = philips_tdm1316l_request_firmware,
851};
852
dc27a169
AQ
853static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
854{
855 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
856 u8 tuner_buf[5];
857 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
858 .flags = 0,
859 .buf = tuner_buf,
860 .len = sizeof(tuner_buf) };
861 int tuner_frequency = 0;
862 u8 band, cp, filter;
863
864 // determine charge pump
865 tuner_frequency = params->frequency + 36125000;
866 if (tuner_frequency < 87000000)
867 return -EINVAL;
868 else if (tuner_frequency < 130000000) {
869 cp = 3;
870 band = 1;
871 } else if (tuner_frequency < 160000000) {
872 cp = 5;
873 band = 1;
874 } else if (tuner_frequency < 200000000) {
875 cp = 6;
876 band = 1;
877 } else if (tuner_frequency < 290000000) {
878 cp = 3;
879 band = 2;
880 } else if (tuner_frequency < 420000000) {
881 cp = 5;
882 band = 2;
883 } else if (tuner_frequency < 480000000) {
884 cp = 6;
885 band = 2;
886 } else if (tuner_frequency < 620000000) {
887 cp = 3;
888 band = 4;
889 } else if (tuner_frequency < 830000000) {
890 cp = 5;
891 band = 4;
892 } else if (tuner_frequency < 895000000) {
893 cp = 7;
894 band = 4;
895 } else
896 return -EINVAL;
897
898 // assume PLL filter should always be 8MHz for the moment.
899 filter = 1;
900
901 // calculate divisor
902 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
903
904 // setup tuner buffer
905 tuner_buf[0] = tuner_frequency >> 8;
906 tuner_buf[1] = tuner_frequency & 0xff;
907 tuner_buf[2] = 0xc8;
908 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
909 tuner_buf[4] = 0x80;
910
911 stv0297_enable_plli2c(fe);
912 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
913 return -EIO;
914
915 msleep(50);
916
917 stv0297_enable_plli2c(fe);
918 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
919 return -EIO;
920
921 msleep(1);
922
923 return 0;
924}
925
926static u8 dvbc_philips_tdm1316l_inittab[] = {
927 0x80, 0x01,
928 0x80, 0x00,
929 0x81, 0x01,
930 0x81, 0x00,
931 0x00, 0x09,
932 0x01, 0x69,
933 0x03, 0x00,
934 0x04, 0x00,
935 0x07, 0x00,
936 0x08, 0x00,
937 0x20, 0x00,
938 0x21, 0x40,
939 0x22, 0x00,
940 0x23, 0x00,
941 0x24, 0x40,
942 0x25, 0x88,
943 0x30, 0xff,
944 0x31, 0x00,
945 0x32, 0xff,
946 0x33, 0x00,
947 0x34, 0x50,
948 0x35, 0x7f,
949 0x36, 0x00,
950 0x37, 0x20,
951 0x38, 0x00,
952 0x40, 0x1c,
953 0x41, 0xff,
954 0x42, 0x29,
955 0x43, 0x20,
956 0x44, 0xff,
957 0x45, 0x00,
958 0x46, 0x00,
959 0x49, 0x04,
960 0x4a, 0x00,
961 0x4b, 0x7b,
962 0x52, 0x30,
963 0x55, 0xae,
964 0x56, 0x47,
965 0x57, 0xe1,
966 0x58, 0x3a,
967 0x5a, 0x1e,
968 0x5b, 0x34,
969 0x60, 0x00,
970 0x63, 0x00,
971 0x64, 0x00,
972 0x65, 0x00,
973 0x66, 0x00,
974 0x67, 0x00,
975 0x68, 0x00,
976 0x69, 0x00,
977 0x6a, 0x02,
978 0x6b, 0x00,
979 0x70, 0xff,
980 0x71, 0x00,
981 0x72, 0x00,
982 0x73, 0x00,
983 0x74, 0x0c,
984 0x80, 0x00,
985 0x81, 0x00,
986 0x82, 0x00,
987 0x83, 0x00,
988 0x84, 0x04,
989 0x85, 0x80,
990 0x86, 0x24,
991 0x87, 0x78,
992 0x88, 0x10,
993 0x89, 0x00,
994 0x90, 0x01,
995 0x91, 0x01,
996 0xa0, 0x04,
997 0xa1, 0x00,
998 0xa2, 0x00,
999 0xb0, 0x91,
1000 0xb1, 0x0b,
1001 0xc0, 0x53,
1002 0xc1, 0x70,
1003 0xc2, 0x12,
1004 0xd0, 0x00,
1005 0xd1, 0x00,
1006 0xd2, 0x00,
1007 0xd3, 0x00,
1008 0xd4, 0x00,
1009 0xd5, 0x00,
1010 0xde, 0x00,
1011 0xdf, 0x00,
1012 0x61, 0x38,
1013 0x62, 0x0a,
1014 0x53, 0x13,
1015 0x59, 0x08,
1016 0xff, 0xff,
1017};
1018
1019static struct stv0297_config dvbc_philips_tdm1316l_config = {
1020 .demod_address = 0x1c,
1021 .inittab = dvbc_philips_tdm1316l_inittab,
1022 .invert = 0,
1023 .pll_set = dvbc_philips_tdm1316l_pll_set,
1024};
1025
1026
1da177e4
LT
1027
1028
1029static void frontend_init(struct budget_ci *budget_ci)
1030{
1031 switch (budget_ci->budget.dev->pci->subsystem_device) {
1032 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1033 budget_ci->budget.dvb_frontend =
1034 stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
1035 if (budget_ci->budget.dvb_frontend) {
1036 break;
1037 }
1038 break;
1039
1040 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1041 budget_ci->budget.dvb_frontend =
1042 stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
1043 if (budget_ci->budget.dvb_frontend) {
1044 break;
1045 }
1046 break;
1047
dc27a169
AQ
1048 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1049 budget_ci->tuner_pll_address = 0x61;
1050 budget_ci->budget.dvb_frontend =
1051 stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
1052 if (budget_ci->budget.dvb_frontend) {
1053 break;
1054 }
1055 break;
1056
1da177e4 1057 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
dd2bbb17 1058 budget_ci->tuner_pll_address = 0x63;
1da177e4
LT
1059 budget_ci->budget.dvb_frontend =
1060 tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
1061 if (budget_ci->budget.dvb_frontend) {
1062 break;
1063 }
1064 break;
dd2bbb17 1065
dc27a169 1066 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
dd2bbb17
AQ
1067 budget_ci->tuner_pll_address = 0x60;
1068 budget_ci->budget.dvb_frontend =
1069 tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
1070 if (budget_ci->budget.dvb_frontend) {
1071 break;
1072 }
1073 break;
1da177e4
LT
1074 }
1075
1076 if (budget_ci->budget.dvb_frontend == NULL) {
1077 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1078 budget_ci->budget.dev->pci->vendor,
1079 budget_ci->budget.dev->pci->device,
1080 budget_ci->budget.dev->pci->subsystem_vendor,
1081 budget_ci->budget.dev->pci->subsystem_device);
1082 } else {
1083 if (dvb_register_frontend
fdc53a6d 1084 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
1da177e4
LT
1085 printk("budget-ci: Frontend registration failed!\n");
1086 if (budget_ci->budget.dvb_frontend->ops->release)
1087 budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
1088 budget_ci->budget.dvb_frontend = NULL;
1089 }
1090 }
1091}
1092
1093static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1094{
1095 struct budget_ci *budget_ci;
1096 int err;
1097
1098 if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
1099 return -ENOMEM;
1100
1101 dprintk(2, "budget_ci: %p\n", budget_ci);
1102
1103 budget_ci->budget.ci_present = 0;
1104
1105 dev->ext_priv = budget_ci;
1106
1107 if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
1108 kfree(budget_ci);
1109 return err;
1110 }
1111
1112 tasklet_init(&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
1113 (unsigned long) budget_ci);
1114
1115 msp430_ir_init(budget_ci);
1116
1117 ciintf_init(budget_ci);
1118
fdc53a6d 1119 budget_ci->budget.dvb_adapter.priv = budget_ci;
1da177e4
LT
1120 frontend_init(budget_ci);
1121
1122 return 0;
1123}
1124
1125static int budget_ci_detach(struct saa7146_dev *dev)
1126{
1127 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1128 struct saa7146_dev *saa = budget_ci->budget.dev;
1129 int err;
1130
1131 if (budget_ci->budget.ci_present)
1132 ciintf_deinit(budget_ci);
1133 if (budget_ci->budget.dvb_frontend)
1134 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
1135 err = ttpci_budget_deinit(&budget_ci->budget);
1136
1137 tasklet_kill(&budget_ci->msp430_irq_tasklet);
1138
1139 msp430_ir_deinit(budget_ci);
1140
1141 // disable frontend and CI interface
1142 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1143
1144 kfree(budget_ci);
1145
1146 return err;
1147}
1148
1149static struct saa7146_extension budget_extension;
1150
1151MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1152MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
dd2bbb17 1153MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
dc27a169 1154MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
1da177e4
LT
1155
1156static struct pci_device_id pci_tbl[] = {
1157 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1158 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
dc27a169 1159 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
1da177e4 1160 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
dd2bbb17 1161 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
1da177e4
LT
1162 {
1163 .vendor = 0,
1164 }
1165};
1166
1167MODULE_DEVICE_TABLE(pci, pci_tbl);
1168
1169static struct saa7146_extension budget_extension = {
1170 .name = "budget_ci dvb\0",
1171 .flags = 0,
1172
1173 .module = THIS_MODULE,
1174 .pci_tbl = &pci_tbl[0],
1175 .attach = budget_ci_attach,
1176 .detach = budget_ci_detach,
1177
1178 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1179 .irq_func = budget_ci_irq,
1180};
1181
1182static int __init budget_ci_init(void)
1183{
1184 return saa7146_register_extension(&budget_extension);
1185}
1186
1187static void __exit budget_ci_exit(void)
1188{
1189 saa7146_unregister_extension(&budget_extension);
1190}
1191
1192module_init(budget_ci_init);
1193module_exit(budget_ci_exit);
1194
1195MODULE_LICENSE("GPL");
1196MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1197MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1198 "budget PCI DVB cards w/ CI-module produced by "
1199 "Siemens, Technotrend, Hauppauge");
This page took 0.126867 seconds and 5 git commands to generate.