diff options
author | Steven Toth <stoth@hauppauge.com> | 2006-01-09 12:25:12 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@brturbo.com.br> | 2006-01-09 12:25:12 -0500 |
commit | 611900c1858747a87657eb405ebab5b1e72bb57c (patch) | |
tree | 661e767af2ee8a655dae18cd8872cfcb897e3ebb | |
parent | 35dc0fefb18eea1b4180a8fafbb83db6a9b7c401 (diff) |
V4L/DVB (3089): Adding support for the Hauppauge HVR1100 and HVR1100-LP products.
- Add support for the Hauppauge HVR1100 and HVR1100-LP products.
- Add i2c_gate_ctrl callback function to dvb_frontend_ops struct.
Signed-off-by: Steven Toth <stoth@hauppauge.com>
Signed-off-by: Michael Krufky <mkrufky@m1k.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
-rw-r--r-- | Documentation/video4linux/CARDLIST.cx88 | 2 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-core/dvb_frontend.h | 1 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/cx22702.c | 22 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-cards.c | 63 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-dvb.c | 17 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-i2c.c | 15 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-input.c | 1 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88.h | 5 |
8 files changed, 114 insertions, 12 deletions
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 13ec5e965f41..fa88056dbe85 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 | |||
@@ -38,3 +38,5 @@ | |||
38 | 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202] | 38 | 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202] |
39 | 38 -> Hauppauge Nova-SE2 DVB-S [0070:9200] | 39 | 38 -> Hauppauge Nova-SE2 DVB-S [0070:9200] |
40 | 39 -> KWorld DVB-S 100 [17de:08b2] | 40 | 39 -> KWorld DVB-S 100 [17de:08b2] |
41 | 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402] | ||
42 | 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802] | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 48c3f81be912..f40ee4efbe31 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h | |||
@@ -85,6 +85,7 @@ struct dvb_frontend_ops { | |||
85 | int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); | 85 | int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); |
86 | int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg); | 86 | int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg); |
87 | int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); | 87 | int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); |
88 | int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); | ||
88 | }; | 89 | }; |
89 | 90 | ||
90 | #define MAX_EVENT 8 | 91 | #define MAX_EVENT 8 |
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 5de0e6d350b1..0fc899f81c5e 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c | |||
@@ -195,6 +195,16 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet | |||
195 | return 0; | 195 | return 0; |
196 | } | 196 | } |
197 | 197 | ||
198 | static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) | ||
199 | { | ||
200 | struct cx22702_state* state = fe->demodulator_priv; | ||
201 | dprintk ("%s(%d)\n", __FUNCTION__, enable); | ||
202 | if (enable) | ||
203 | return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe); | ||
204 | else | ||
205 | return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1); | ||
206 | } | ||
207 | |||
198 | /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ | 208 | /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ |
199 | static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | 209 | static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) |
200 | { | 210 | { |
@@ -202,7 +212,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet | |||
202 | struct cx22702_state* state = fe->demodulator_priv; | 212 | struct cx22702_state* state = fe->demodulator_priv; |
203 | 213 | ||
204 | /* set PLL */ | 214 | /* set PLL */ |
205 | cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); | 215 | cx22702_i2c_gate_ctrl(fe, 1); |
206 | if (state->config->pll_set) { | 216 | if (state->config->pll_set) { |
207 | state->config->pll_set(fe, p); | 217 | state->config->pll_set(fe, p); |
208 | } else if (state->config->pll_desc) { | 218 | } else if (state->config->pll_desc) { |
@@ -216,7 +226,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet | |||
216 | } else { | 226 | } else { |
217 | BUG(); | 227 | BUG(); |
218 | } | 228 | } |
219 | cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); | 229 | cx22702_i2c_gate_ctrl(fe, 0); |
220 | 230 | ||
221 | /* set inversion */ | 231 | /* set inversion */ |
222 | cx22702_set_inversion (state, p->inversion); | 232 | cx22702_set_inversion (state, p->inversion); |
@@ -349,11 +359,10 @@ static int cx22702_init (struct dvb_frontend* fe) | |||
349 | cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02); | 359 | cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02); |
350 | 360 | ||
351 | /* init PLL */ | 361 | /* init PLL */ |
352 | if (state->config->pll_init) { | 362 | if (state->config->pll_init) |
353 | cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe); | ||
354 | state->config->pll_init(fe); | 363 | state->config->pll_init(fe); |
355 | cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); | 364 | |
356 | } | 365 | cx22702_i2c_gate_ctrl(fe, 0); |
357 | 366 | ||
358 | return 0; | 367 | return 0; |
359 | } | 368 | } |
@@ -531,6 +540,7 @@ static struct dvb_frontend_ops cx22702_ops = { | |||
531 | .read_signal_strength = cx22702_read_signal_strength, | 540 | .read_signal_strength = cx22702_read_signal_strength, |
532 | .read_snr = cx22702_read_snr, | 541 | .read_snr = cx22702_read_snr, |
533 | .read_ucblocks = cx22702_read_ucblocks, | 542 | .read_ucblocks = cx22702_read_ucblocks, |
543 | .i2c_gate_ctrl = cx22702_i2c_gate_ctrl, | ||
534 | }; | 544 | }; |
535 | 545 | ||
536 | module_param(debug, int, 0644); | 546 | module_param(debug, int, 0644); |
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index fd173e6ac605..b4fd1ef007ea 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -903,7 +903,6 @@ struct cx88_board cx88_boards[] = { | |||
903 | .radio_type = UNSET, | 903 | .radio_type = UNSET, |
904 | .tuner_addr = ADDR_UNSET, | 904 | .tuner_addr = ADDR_UNSET, |
905 | .radio_addr = ADDR_UNSET, | 905 | .radio_addr = ADDR_UNSET, |
906 | /* fixme: add the analog gpio stuff here */ | ||
907 | .input = {{ | 906 | .input = {{ |
908 | .type = CX88_VMUX_DVB, | 907 | .type = CX88_VMUX_DVB, |
909 | .vmux = 0, | 908 | .vmux = 0, |
@@ -946,6 +945,43 @@ struct cx88_board cx88_boards[] = { | |||
946 | }}, | 945 | }}, |
947 | .dvb = 1, | 946 | .dvb = 1, |
948 | }, | 947 | }, |
948 | [CX88_BOARD_HAUPPAUGE_HVR1100] = { | ||
949 | .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid", | ||
950 | .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, | ||
951 | .radio_type = UNSET, | ||
952 | .tuner_addr = ADDR_UNSET, | ||
953 | .radio_addr = ADDR_UNSET, | ||
954 | .tda9887_conf = TDA9887_PRESENT, | ||
955 | .input = {{ | ||
956 | .type = CX88_VMUX_TELEVISION, | ||
957 | .vmux = 0, | ||
958 | },{ | ||
959 | .type = CX88_VMUX_COMPOSITE1, | ||
960 | .vmux = 1, | ||
961 | },{ | ||
962 | .type = CX88_VMUX_SVIDEO, | ||
963 | .vmux = 2, | ||
964 | }}, | ||
965 | /* fixme: Add radio support */ | ||
966 | .dvb = 1, | ||
967 | }, | ||
968 | [CX88_BOARD_HAUPPAUGE_HVR1100LP] = { | ||
969 | .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)", | ||
970 | .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, | ||
971 | .radio_type = UNSET, | ||
972 | .tuner_addr = ADDR_UNSET, | ||
973 | .radio_addr = ADDR_UNSET, | ||
974 | .tda9887_conf = TDA9887_PRESENT, | ||
975 | .input = {{ | ||
976 | .type = CX88_VMUX_TELEVISION, | ||
977 | .vmux = 0, | ||
978 | },{ | ||
979 | .type = CX88_VMUX_COMPOSITE1, | ||
980 | .vmux = 1, | ||
981 | }}, | ||
982 | /* fixme: Add radio support */ | ||
983 | .dvb = 1, | ||
984 | }, | ||
949 | }; | 985 | }; |
950 | const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); | 986 | const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); |
951 | 987 | ||
@@ -1109,6 +1145,22 @@ struct cx88_subid cx88_subids[] = { | |||
1109 | .subvendor = 0x17de, | 1145 | .subvendor = 0x17de, |
1110 | .subdevice = 0x08b2, | 1146 | .subdevice = 0x08b2, |
1111 | .card = CX88_BOARD_KWORLD_DVBS_100, | 1147 | .card = CX88_BOARD_KWORLD_DVBS_100, |
1148 | },{ | ||
1149 | .subvendor = 0x0070, | ||
1150 | .subdevice = 0x9400, | ||
1151 | .card = CX88_BOARD_HAUPPAUGE_HVR1100, | ||
1152 | },{ | ||
1153 | .subvendor = 0x0070, | ||
1154 | .subdevice = 0x9402, | ||
1155 | .card = CX88_BOARD_HAUPPAUGE_HVR1100, | ||
1156 | },{ | ||
1157 | .subvendor = 0x0070, | ||
1158 | .subdevice = 0x9800, | ||
1159 | .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, | ||
1160 | },{ | ||
1161 | .subvendor = 0x0070, | ||
1162 | .subdevice = 0x9802, | ||
1163 | .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, | ||
1112 | }, | 1164 | }, |
1113 | }; | 1165 | }; |
1114 | const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); | 1166 | const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); |
@@ -1140,9 +1192,6 @@ static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) | |||
1140 | core->name, core->tuner_type, eeprom_data[0]); | 1192 | core->name, core->tuner_type, eeprom_data[0]); |
1141 | } | 1193 | } |
1142 | 1194 | ||
1143 | |||
1144 | /* ----------------------------------------------------------------------- */ | ||
1145 | |||
1146 | static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) | 1195 | static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) |
1147 | { | 1196 | { |
1148 | struct tveeprom tv; | 1197 | struct tveeprom tv; |
@@ -1161,7 +1210,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) | |||
1161 | case 90500: /* Nova-T-PCI (oem) */ | 1210 | case 90500: /* Nova-T-PCI (oem) */ |
1162 | case 90501: /* Nova-T-PCI (oem/IR) */ | 1211 | case 90501: /* Nova-T-PCI (oem/IR) */ |
1163 | case 92000: /* Nova-SE2 (OEM, No Video or IR) */ | 1212 | case 92000: /* Nova-SE2 (OEM, No Video or IR) */ |
1164 | 1213 | case 94009: /* WinTV-HVR1100 (Video and IR Retail) */ | |
1214 | case 94501: /* WinTV-HVR1100 (Video and IR OEM) */ | ||
1215 | case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */ | ||
1165 | /* known */ | 1216 | /* known */ |
1166 | break; | 1217 | break; |
1167 | default: | 1218 | default: |
@@ -1279,6 +1330,8 @@ void cx88_card_setup(struct cx88_core *core) | |||
1279 | case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: | 1330 | case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: |
1280 | case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: | 1331 | case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: |
1281 | case CX88_BOARD_HAUPPAUGE_DVB_T1: | 1332 | case CX88_BOARD_HAUPPAUGE_DVB_T1: |
1333 | case CX88_BOARD_HAUPPAUGE_HVR1100: | ||
1334 | case CX88_BOARD_HAUPPAUGE_HVR1100LP: | ||
1282 | if (0 == core->i2c_rc) | 1335 | if (0 == core->i2c_rc) |
1283 | hauppauge_eeprom(core,eeprom); | 1336 | hauppauge_eeprom(core,eeprom); |
1284 | break; | 1337 | break; |
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 054094e48fc3..c4551d996119 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c | |||
@@ -191,6 +191,12 @@ static struct cx22702_config hauppauge_novat_config = { | |||
191 | .pll_address = 0x61, | 191 | .pll_address = 0x61, |
192 | .pll_desc = &dvb_pll_thomson_dtt759x, | 192 | .pll_desc = &dvb_pll_thomson_dtt759x, |
193 | }; | 193 | }; |
194 | static struct cx22702_config hauppauge_hvr1100_config = { | ||
195 | .demod_address = 0x63, | ||
196 | .output_mode = CX22702_SERIAL_OUTPUT, | ||
197 | .pll_address = 0x61, | ||
198 | .pll_desc = &dvb_pll_fmd1216me, | ||
199 | }; | ||
194 | #endif | 200 | #endif |
195 | 201 | ||
196 | #ifdef HAVE_OR51132 | 202 | #ifdef HAVE_OR51132 |
@@ -370,6 +376,11 @@ static int dvb_register(struct cx8802_dev *dev) | |||
370 | dev->dvb.frontend = cx22702_attach(&connexant_refboard_config, | 376 | dev->dvb.frontend = cx22702_attach(&connexant_refboard_config, |
371 | &dev->core->i2c_adap); | 377 | &dev->core->i2c_adap); |
372 | break; | 378 | break; |
379 | case CX88_BOARD_HAUPPAUGE_HVR1100: | ||
380 | case CX88_BOARD_HAUPPAUGE_HVR1100LP: | ||
381 | dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config, | ||
382 | &dev->core->i2c_adap); | ||
383 | break; | ||
373 | #endif | 384 | #endif |
374 | #ifdef HAVE_MT352 | 385 | #ifdef HAVE_MT352 |
375 | case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: | 386 | case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: |
@@ -532,6 +543,9 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev, | |||
532 | err = dvb_register(dev); | 543 | err = dvb_register(dev); |
533 | if (0 != err) | 544 | if (0 != err) |
534 | goto fail_fini; | 545 | goto fail_fini; |
546 | |||
547 | /* Maintain a reference to cx88-video can query the 8802 device. */ | ||
548 | core->dvbdev = dev; | ||
535 | return 0; | 549 | return 0; |
536 | 550 | ||
537 | fail_fini: | 551 | fail_fini: |
@@ -547,6 +561,9 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev) | |||
547 | { | 561 | { |
548 | struct cx8802_dev *dev = pci_get_drvdata(pci_dev); | 562 | struct cx8802_dev *dev = pci_get_drvdata(pci_dev); |
549 | 563 | ||
564 | /* Destroy any 8802 reference. */ | ||
565 | dev->core->dvbdev = NULL; | ||
566 | |||
550 | /* dvb */ | 567 | /* dvb */ |
551 | videobuf_dvb_unregister(&dev->dvb); | 568 | videobuf_dvb_unregister(&dev->dvb); |
552 | 569 | ||
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 4a8fb161b16a..7363dd6e66e2 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c | |||
@@ -135,7 +135,20 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) | |||
135 | { | 135 | { |
136 | if (0 != core->i2c_rc) | 136 | if (0 != core->i2c_rc) |
137 | return; | 137 | return; |
138 | i2c_clients_command(&core->i2c_adap, cmd, arg); | 138 | |
139 | if (core->dvbdev == NULL) { | ||
140 | i2c_clients_command(&core->i2c_adap, cmd, arg); | ||
141 | } else { | ||
142 | |||
143 | if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl) | ||
144 | core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1); | ||
145 | |||
146 | i2c_clients_command(&core->i2c_adap, cmd, arg); | ||
147 | |||
148 | if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl) | ||
149 | core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0); | ||
150 | } | ||
151 | |||
139 | } | 152 | } |
140 | 153 | ||
141 | static struct i2c_algo_bit_data cx8800_i2c_algo_template = { | 154 | static struct i2c_algo_bit_data cx8800_i2c_algo_template = { |
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index d7e9813384d8..a89bb2b195f3 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c | |||
@@ -390,6 +390,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) | |||
390 | case CX88_BOARD_HAUPPAUGE_DVB_T1: | 390 | case CX88_BOARD_HAUPPAUGE_DVB_T1: |
391 | case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: | 391 | case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: |
392 | case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: | 392 | case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: |
393 | case CX88_BOARD_HAUPPAUGE_HVR1100: | ||
393 | ir_codes = ir_codes_hauppauge_new; | 394 | ir_codes = ir_codes_hauppauge_new; |
394 | ir_type = IR_TYPE_RC5; | 395 | ir_type = IR_TYPE_RC5; |
395 | ir->sampling = 1; | 396 | ir->sampling = 1; |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 11dc0335151c..3e2bcd241a27 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -182,6 +182,8 @@ extern struct sram_channel cx88_sram_channels[]; | |||
182 | #define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37 | 182 | #define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37 |
183 | #define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38 | 183 | #define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38 |
184 | #define CX88_BOARD_KWORLD_DVBS_100 39 | 184 | #define CX88_BOARD_KWORLD_DVBS_100 39 |
185 | #define CX88_BOARD_HAUPPAUGE_HVR1100 40 | ||
186 | #define CX88_BOARD_HAUPPAUGE_HVR1100LP 41 | ||
185 | 187 | ||
186 | enum cx88_itype { | 188 | enum cx88_itype { |
187 | CX88_VMUX_COMPOSITE1 = 1, | 189 | CX88_VMUX_COMPOSITE1 = 1, |
@@ -304,6 +306,9 @@ struct cx88_core { | |||
304 | 306 | ||
305 | /* various v4l controls */ | 307 | /* various v4l controls */ |
306 | u32 freq; | 308 | u32 freq; |
309 | |||
310 | /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ | ||
311 | struct cx8802_dev *dvbdev; | ||
307 | }; | 312 | }; |
308 | 313 | ||
309 | struct cx8800_dev; | 314 | struct cx8800_dev; |