Commit | Line | Data |
---|---|---|
4c66c920 MK |
1 | /* |
2 | * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the Free | |
6 | * Software Foundation, version 2. | |
7 | * | |
8 | * see Documentation/dvb/README.dvb-usb for more information | |
9 | */ | |
10 | ||
11 | #include <linux/vmalloc.h> | |
12 | #include <linux/i2c.h> | |
13 | ||
14 | #include "mxl111sf.h" | |
15 | #include "mxl111sf-reg.h" | |
16 | #include "mxl111sf-phy.h" | |
17 | #include "mxl111sf-i2c.h" | |
18 | #include "mxl111sf-gpio.h" | |
19 | ||
4f98480f | 20 | #include "mxl111sf-demod.h" |
4c66c920 MK |
21 | #include "mxl111sf-tuner.h" |
22 | ||
23 | #include "lgdt3305.h" | |
24 | ||
25 | int dvb_usb_mxl111sf_debug; | |
26 | module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); | |
27 | MODULE_PARM_DESC(debug, "set debugging level " | |
28 | "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); | |
29 | ||
30 | int dvb_usb_mxl111sf_isoc; | |
31 | module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); | |
32 | MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc)."); | |
33 | ||
34 | #define ANT_PATH_AUTO 0 | |
35 | #define ANT_PATH_EXTERNAL 1 | |
36 | #define ANT_PATH_INTERNAL 2 | |
37 | ||
38 | int dvb_usb_mxl111sf_rfswitch = | |
39 | #if 0 | |
40 | ANT_PATH_AUTO; | |
41 | #else | |
42 | ANT_PATH_EXTERNAL; | |
43 | #endif | |
44 | ||
45 | module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644); | |
46 | MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int)."); | |
47 | ||
48 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |
49 | ||
50 | #define deb_info(args...) dprintk(dvb_usb_mxl111sf_debug, 0x13, args) | |
51 | #define deb_reg(args...) dprintk(dvb_usb_mxl111sf_debug, 0x08, args) | |
52 | #define deb_adv(args...) dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args) | |
53 | ||
54 | int mxl111sf_ctrl_msg(struct dvb_usb_device *d, | |
55 | u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) | |
56 | { | |
57 | int wo = (rbuf == NULL || rlen == 0); /* write-only */ | |
58 | int ret; | |
59 | u8 sndbuf[1+wlen]; | |
60 | ||
61 | deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen); | |
62 | ||
63 | memset(sndbuf, 0, 1+wlen); | |
64 | ||
65 | sndbuf[0] = cmd; | |
66 | memcpy(&sndbuf[1], wbuf, wlen); | |
67 | ||
68 | ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) : | |
69 | dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); | |
70 | mxl_fail(ret); | |
71 | ||
72 | return ret; | |
73 | } | |
74 | ||
75 | /* ------------------------------------------------------------------------ */ | |
76 | ||
77 | #define MXL_CMD_REG_READ 0xaa | |
78 | #define MXL_CMD_REG_WRITE 0x55 | |
79 | ||
80 | int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data) | |
81 | { | |
82 | u8 buf[2]; | |
83 | int ret; | |
84 | ||
85 | ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2); | |
86 | if (mxl_fail(ret)) { | |
87 | mxl_debug("error reading reg: 0x%02x", addr); | |
88 | goto fail; | |
89 | } | |
90 | ||
91 | if (buf[0] == addr) | |
92 | *data = buf[1]; | |
93 | else { | |
94 | err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x", | |
95 | addr, buf[0], buf[1]); | |
96 | ret = -EINVAL; | |
97 | } | |
98 | ||
99 | deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data); | |
100 | fail: | |
101 | return ret; | |
102 | } | |
103 | ||
104 | int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data) | |
105 | { | |
106 | u8 buf[] = { addr, data }; | |
107 | int ret; | |
108 | ||
109 | deb_reg("W: (0x%02x, 0x%02x)\n", addr, data); | |
110 | ||
111 | ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0); | |
112 | if (mxl_fail(ret)) | |
113 | err("error writing reg: 0x%02x, val: 0x%02x", addr, data); | |
114 | return ret; | |
115 | } | |
116 | ||
117 | /* ------------------------------------------------------------------------ */ | |
118 | ||
119 | int mxl111sf_write_reg_mask(struct mxl111sf_state *state, | |
120 | u8 addr, u8 mask, u8 data) | |
121 | { | |
122 | int ret; | |
123 | u8 val; | |
124 | ||
125 | if (mask != 0xff) { | |
126 | ret = mxl111sf_read_reg(state, addr, &val); | |
127 | #if 1 | |
128 | /* dont know why this usually errors out on the first try */ | |
129 | if (mxl_fail(ret)) | |
130 | err("error writing addr: 0x%02x, mask: 0x%02x, " | |
131 | "data: 0x%02x, retrying...", addr, mask, data); | |
132 | ||
133 | ret = mxl111sf_read_reg(state, addr, &val); | |
134 | #endif | |
135 | if (mxl_fail(ret)) | |
136 | goto fail; | |
137 | } | |
138 | val &= ~mask; | |
139 | val |= data; | |
140 | ||
141 | ret = mxl111sf_write_reg(state, addr, val); | |
142 | mxl_fail(ret); | |
143 | fail: | |
144 | return ret; | |
145 | } | |
146 | ||
147 | /* ------------------------------------------------------------------------ */ | |
148 | ||
149 | int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state, | |
150 | struct mxl111sf_reg_ctrl_info *ctrl_reg_info) | |
151 | { | |
152 | int i, ret = 0; | |
153 | ||
154 | for (i = 0; ctrl_reg_info[i].addr | | |
155 | ctrl_reg_info[i].mask | | |
156 | ctrl_reg_info[i].data; i++) { | |
157 | ||
158 | ret = mxl111sf_write_reg_mask(state, | |
159 | ctrl_reg_info[i].addr, | |
160 | ctrl_reg_info[i].mask, | |
161 | ctrl_reg_info[i].data); | |
162 | if (mxl_fail(ret)) { | |
163 | err("failed on reg #%d (0x%02x)", i, | |
164 | ctrl_reg_info[i].addr); | |
165 | break; | |
166 | } | |
167 | } | |
168 | return ret; | |
169 | } | |
170 | ||
171 | /* ------------------------------------------------------------------------ */ | |
172 | ||
173 | static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state) | |
174 | { | |
175 | int ret; | |
176 | u8 id, ver; | |
177 | char *mxl_chip, *mxl_rev; | |
178 | ||
179 | if ((state->chip_id) && (state->chip_ver)) | |
180 | return 0; | |
181 | ||
182 | ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id); | |
183 | if (mxl_fail(ret)) | |
184 | goto fail; | |
185 | state->chip_id = id; | |
186 | ||
187 | ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver); | |
188 | if (mxl_fail(ret)) | |
189 | goto fail; | |
190 | state->chip_ver = ver; | |
191 | ||
192 | switch (id) { | |
193 | case 0x61: | |
194 | mxl_chip = "MxL101SF"; | |
195 | break; | |
196 | case 0x63: | |
197 | mxl_chip = "MxL111SF"; | |
198 | break; | |
199 | default: | |
200 | mxl_chip = "UNKNOWN MxL1X1"; | |
201 | break; | |
202 | } | |
203 | switch (ver) { | |
204 | case 0x36: | |
205 | state->chip_rev = MXL111SF_V6; | |
206 | mxl_rev = "v6"; | |
207 | break; | |
208 | case 0x08: | |
209 | state->chip_rev = MXL111SF_V8_100; | |
210 | mxl_rev = "v8_100"; | |
211 | break; | |
212 | case 0x18: | |
213 | state->chip_rev = MXL111SF_V8_200; | |
214 | mxl_rev = "v8_200"; | |
215 | break; | |
216 | default: | |
217 | state->chip_rev = 0; | |
218 | mxl_rev = "UNKNOWN REVISION"; | |
219 | break; | |
220 | } | |
221 | info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver); | |
222 | fail: | |
223 | return ret; | |
224 | } | |
225 | ||
226 | #define get_chip_info(state) \ | |
227 | ({ \ | |
228 | int ___ret; \ | |
229 | ___ret = mxl1x1sf_get_chip_info(state); \ | |
230 | if (mxl_fail(___ret)) { \ | |
231 | mxl_debug("failed to get chip info" \ | |
232 | " on first probe attempt"); \ | |
233 | ___ret = mxl1x1sf_get_chip_info(state); \ | |
234 | if (mxl_fail(___ret)) \ | |
235 | err("failed to get chip info during probe"); \ | |
236 | else \ | |
237 | mxl_debug("probe needed a retry " \ | |
238 | "in order to succeed."); \ | |
239 | } \ | |
240 | ___ret; \ | |
241 | }) | |
242 | ||
243 | /* ------------------------------------------------------------------------ */ | |
244 | ||
245 | static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff) | |
246 | { | |
247 | /* power control depends on which adapter is being woken: | |
248 | * save this for init, instead, via mxl111sf_adap_fe_init */ | |
249 | return 0; | |
250 | } | |
251 | ||
252 | static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) | |
253 | { | |
254 | struct dvb_usb_adapter *adap = fe->dvb->priv; | |
255 | struct dvb_usb_device *d = adap->dev; | |
256 | struct mxl111sf_state *state = d->priv; | |
77eed219 MK |
257 | struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv; |
258 | ||
4c66c920 MK |
259 | int err; |
260 | ||
261 | /* exit if we didnt initialize the driver yet */ | |
262 | if (!state->chip_id) { | |
263 | mxl_debug("driver not yet initialized, exit."); | |
264 | goto fail; | |
265 | } | |
266 | ||
267 | deb_info("%s()\n", __func__); | |
268 | ||
269 | mutex_lock(&state->fe_lock); | |
270 | ||
271 | state->alt_mode = adap_state->alt_mode; | |
272 | ||
273 | if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) | |
274 | err("set interface failed"); | |
275 | ||
276 | err = mxl1x1sf_soft_reset(state); | |
277 | mxl_fail(err); | |
278 | err = mxl111sf_init_tuner_demod(state); | |
279 | mxl_fail(err); | |
280 | err = mxl1x1sf_set_device_mode(state, adap_state->device_mode); | |
281 | ||
282 | mxl_fail(err); | |
283 | mxl111sf_enable_usb_output(state); | |
284 | mxl_fail(err); | |
285 | mxl1x1sf_top_master_ctrl(state, 1); | |
286 | mxl_fail(err); | |
287 | ||
288 | if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) && | |
289 | (state->chip_rev > MXL111SF_V6)) { | |
290 | mxl111sf_config_pin_mux_modes(state, | |
291 | PIN_MUX_TS_SPI_IN_MODE_1); | |
292 | mxl_fail(err); | |
293 | } | |
294 | err = mxl111sf_init_port_expander(state); | |
295 | if (!mxl_fail(err)) { | |
296 | state->gpio_mode = adap_state->gpio_mode; | |
297 | err = mxl111sf_gpio_mode_switch(state, state->gpio_mode); | |
298 | mxl_fail(err); | |
299 | #if 0 | |
300 | err = fe->ops.init(fe); | |
301 | #endif | |
302 | msleep(100); /* add short delay after enabling | |
303 | * the demod before touching it */ | |
304 | } | |
305 | ||
306 | return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0; | |
307 | fail: | |
308 | return -ENODEV; | |
309 | } | |
310 | ||
311 | static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) | |
312 | { | |
313 | struct dvb_usb_adapter *adap = fe->dvb->priv; | |
314 | struct dvb_usb_device *d = adap->dev; | |
315 | struct mxl111sf_state *state = d->priv; | |
77eed219 | 316 | struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv; |
4c66c920 MK |
317 | int err; |
318 | ||
319 | /* exit if we didnt initialize the driver yet */ | |
320 | if (!state->chip_id) { | |
321 | mxl_debug("driver not yet initialized, exit."); | |
322 | goto fail; | |
323 | } | |
324 | ||
325 | deb_info("%s()\n", __func__); | |
326 | ||
327 | err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0; | |
328 | ||
329 | mutex_unlock(&state->fe_lock); | |
330 | ||
331 | return err; | |
332 | fail: | |
333 | return -ENODEV; | |
334 | } | |
335 | ||
336 | ||
337 | static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |
338 | { | |
339 | struct dvb_usb_device *d = adap->dev; | |
340 | struct mxl111sf_state *state = d->priv; | |
77eed219 | 341 | struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv; |
4c66c920 MK |
342 | int ret = 0; |
343 | u8 tmp; | |
344 | ||
345 | deb_info("%s(%d)\n", __func__, onoff); | |
346 | ||
347 | if (onoff) { | |
348 | ret = mxl111sf_enable_usb_output(state); | |
349 | mxl_fail(ret); | |
350 | ret = mxl111sf_config_mpeg_in(state, 1, 1, | |
351 | adap_state->ep6_clockphase, | |
352 | 0, 0); | |
353 | mxl_fail(ret); | |
354 | } else { | |
355 | ret = mxl111sf_disable_656_port(state); | |
356 | mxl_fail(ret); | |
357 | } | |
358 | ||
359 | mxl111sf_read_reg(state, 0x12, &tmp); | |
360 | tmp &= ~0x04; | |
361 | mxl111sf_write_reg(state, 0x12, tmp); | |
362 | ||
363 | return ret; | |
364 | } | |
365 | ||
4f98480f MK |
366 | static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) |
367 | { | |
368 | struct dvb_usb_device *d = adap->dev; | |
369 | struct mxl111sf_state *state = d->priv; | |
370 | int ret = 0; | |
371 | ||
372 | deb_info("%s(%d)\n", __func__, onoff); | |
373 | ||
374 | if (onoff) { | |
375 | ret = mxl111sf_enable_usb_output(state); | |
376 | mxl_fail(ret); | |
377 | } | |
378 | ||
379 | return ret; | |
380 | } | |
381 | ||
4c66c920 MK |
382 | /* ------------------------------------------------------------------------ */ |
383 | ||
384 | static struct lgdt3305_config hauppauge_lgdt3305_config = { | |
385 | .i2c_addr = 0xb2 >> 1, | |
386 | .mpeg_mode = LGDT3305_MPEG_SERIAL, | |
387 | .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE, | |
388 | .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, | |
389 | .deny_i2c_rptr = 1, | |
390 | .spectral_inversion = 0, | |
391 | .qam_if_khz = 6000, | |
392 | .vsb_if_khz = 6000, | |
393 | }; | |
394 | ||
395 | static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) | |
396 | { | |
397 | struct dvb_usb_device *d = adap->dev; | |
398 | struct mxl111sf_state *state = d->priv; | |
1251312a MK |
399 | int fe_id = adap->num_frontends_initialized; |
400 | struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; | |
4c66c920 MK |
401 | int ret; |
402 | ||
403 | deb_adv("%s()\n", __func__); | |
404 | ||
405 | /* save a pointer to the dvb_usb_device in device state */ | |
406 | state->d = d; | |
407 | adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; | |
408 | state->alt_mode = adap_state->alt_mode; | |
409 | ||
410 | if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) | |
411 | err("set interface failed"); | |
412 | ||
413 | state->gpio_mode = MXL111SF_GPIO_MOD_ATSC; | |
414 | adap_state->gpio_mode = state->gpio_mode; | |
415 | adap_state->device_mode = MXL_TUNER_MODE; | |
416 | adap_state->ep6_clockphase = 1; | |
417 | ||
418 | ret = mxl1x1sf_soft_reset(state); | |
419 | if (mxl_fail(ret)) | |
420 | goto fail; | |
421 | ret = mxl111sf_init_tuner_demod(state); | |
422 | if (mxl_fail(ret)) | |
423 | goto fail; | |
424 | ||
425 | ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); | |
426 | if (mxl_fail(ret)) | |
427 | goto fail; | |
428 | ||
429 | ret = mxl111sf_enable_usb_output(state); | |
430 | if (mxl_fail(ret)) | |
431 | goto fail; | |
432 | ret = mxl1x1sf_top_master_ctrl(state, 1); | |
433 | if (mxl_fail(ret)) | |
434 | goto fail; | |
435 | ||
436 | ret = mxl111sf_init_port_expander(state); | |
437 | if (mxl_fail(ret)) | |
438 | goto fail; | |
439 | ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode); | |
440 | if (mxl_fail(ret)) | |
441 | goto fail; | |
442 | ||
1251312a | 443 | adap->fe_adap[fe_id].fe = dvb_attach(lgdt3305_attach, |
4c66c920 MK |
444 | &hauppauge_lgdt3305_config, |
445 | &adap->dev->i2c_adap); | |
1251312a MK |
446 | if (adap->fe_adap[fe_id].fe) { |
447 | adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; | |
448 | adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; | |
449 | adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; | |
450 | adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; | |
4c66c920 MK |
451 | return 0; |
452 | } | |
453 | ret = -EIO; | |
454 | fail: | |
455 | return ret; | |
456 | } | |
457 | ||
4f98480f MK |
458 | static struct mxl111sf_demod_config mxl_demod_config = { |
459 | .read_reg = mxl111sf_read_reg, | |
460 | .write_reg = mxl111sf_write_reg, | |
461 | .program_regs = mxl111sf_ctrl_program_regs, | |
462 | }; | |
463 | ||
464 | static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap) | |
465 | { | |
466 | struct dvb_usb_device *d = adap->dev; | |
467 | struct mxl111sf_state *state = d->priv; | |
468 | int fe_id = adap->num_frontends_initialized; | |
469 | struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; | |
470 | int ret; | |
471 | ||
472 | deb_adv("%s()\n", __func__); | |
473 | ||
474 | /* save a pointer to the dvb_usb_device in device state */ | |
475 | state->d = d; | |
476 | adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; | |
477 | state->alt_mode = adap_state->alt_mode; | |
478 | ||
479 | if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) | |
480 | err("set interface failed"); | |
481 | ||
482 | state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; | |
483 | adap_state->gpio_mode = state->gpio_mode; | |
484 | adap_state->device_mode = MXL_SOC_MODE; | |
485 | adap_state->ep6_clockphase = 1; | |
486 | ||
487 | ret = mxl1x1sf_soft_reset(state); | |
488 | if (mxl_fail(ret)) | |
489 | goto fail; | |
490 | ret = mxl111sf_init_tuner_demod(state); | |
491 | if (mxl_fail(ret)) | |
492 | goto fail; | |
493 | ||
494 | ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); | |
495 | if (mxl_fail(ret)) | |
496 | goto fail; | |
497 | ||
498 | ret = mxl111sf_enable_usb_output(state); | |
499 | if (mxl_fail(ret)) | |
500 | goto fail; | |
501 | ret = mxl1x1sf_top_master_ctrl(state, 1); | |
502 | if (mxl_fail(ret)) | |
503 | goto fail; | |
504 | ||
505 | /* dont care if this fails */ | |
506 | mxl111sf_init_port_expander(state); | |
507 | ||
508 | adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state, | |
509 | &mxl_demod_config); | |
510 | if (adap->fe_adap[fe_id].fe) { | |
511 | adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; | |
512 | adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; | |
513 | adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; | |
514 | adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; | |
515 | return 0; | |
516 | } | |
517 | ret = -EIO; | |
518 | fail: | |
519 | return ret; | |
520 | } | |
521 | ||
4c66c920 MK |
522 | static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, |
523 | int antpath) | |
524 | { | |
525 | return mxl111sf_idac_config(state, 1, 1, | |
526 | (antpath == ANT_PATH_INTERNAL) ? | |
527 | 0x3f : 0x00, 0); | |
528 | } | |
529 | ||
530 | #define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \ | |
531 | err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \ | |
532 | __func__, __LINE__, \ | |
533 | (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \ | |
534 | pwr0, pwr1, pwr2, pwr3) | |
535 | ||
536 | #define ANT_HUNT_SLEEP 90 | |
537 | #define ANT_EXT_TWEAK 0 | |
538 | ||
539 | static int mxl111sf_ant_hunt(struct dvb_frontend *fe) | |
540 | { | |
541 | struct dvb_usb_adapter *adap = fe->dvb->priv; | |
542 | struct dvb_usb_device *d = adap->dev; | |
543 | struct mxl111sf_state *state = d->priv; | |
544 | ||
545 | int antctrl = dvb_usb_mxl111sf_rfswitch; | |
546 | ||
547 | u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2; | |
548 | ||
549 | /* FIXME: must force EXTERNAL for QAM - done elsewhere */ | |
550 | mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ? | |
551 | ANT_PATH_EXTERNAL : antctrl); | |
552 | ||
553 | if (antctrl == ANT_PATH_AUTO) { | |
554 | #if 0 | |
555 | msleep(ANT_HUNT_SLEEP); | |
556 | #endif | |
557 | fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA); | |
558 | ||
559 | mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); | |
560 | msleep(ANT_HUNT_SLEEP); | |
561 | fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0); | |
562 | ||
563 | mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); | |
564 | msleep(ANT_HUNT_SLEEP); | |
565 | fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1); | |
566 | ||
567 | mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL); | |
568 | msleep(ANT_HUNT_SLEEP); | |
569 | fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2); | |
570 | ||
571 | if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) { | |
572 | /* return with EXTERNAL enabled */ | |
573 | mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL); | |
574 | DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA, | |
575 | rxPwr0, rxPwr1, rxPwr2); | |
576 | } else { | |
577 | /* return with INTERNAL enabled */ | |
578 | DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA, | |
579 | rxPwr0, rxPwr1, rxPwr2); | |
580 | } | |
581 | } | |
582 | return 0; | |
583 | } | |
584 | ||
585 | static struct mxl111sf_tuner_config mxl_tuner_config = { | |
586 | .if_freq = MXL_IF_6_0, /* applies to external IF output, only */ | |
587 | .invert_spectrum = 0, | |
588 | .read_reg = mxl111sf_read_reg, | |
589 | .write_reg = mxl111sf_write_reg, | |
590 | .program_regs = mxl111sf_ctrl_program_regs, | |
591 | .top_master_ctrl = mxl1x1sf_top_master_ctrl, | |
592 | .ant_hunt = mxl111sf_ant_hunt, | |
593 | }; | |
594 | ||
595 | static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) | |
596 | { | |
597 | struct dvb_usb_device *d = adap->dev; | |
598 | struct mxl111sf_state *state = d->priv; | |
1251312a | 599 | int fe_id = adap->num_frontends_initialized; |
4c66c920 MK |
600 | |
601 | deb_adv("%s()\n", __func__); | |
602 | ||
1251312a MK |
603 | if (NULL != dvb_attach(mxl111sf_tuner_attach, |
604 | adap->fe_adap[fe_id].fe, state, | |
4c66c920 MK |
605 | &mxl_tuner_config)) |
606 | return 0; | |
607 | ||
608 | return -EIO; | |
609 | } | |
610 | ||
611 | static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe, | |
612 | unsigned int cmd, void *parg, | |
613 | unsigned int stage) | |
614 | { | |
615 | int err = 0; | |
616 | ||
617 | switch (stage) { | |
618 | case DVB_FE_IOCTL_PRE: | |
619 | ||
620 | switch (cmd) { | |
621 | case FE_READ_SIGNAL_STRENGTH: | |
622 | err = fe->ops.tuner_ops.get_rf_strength(fe, parg); | |
623 | /* If no error occurs, prevent dvb-core from handling | |
624 | * this IOCTL, otherwise return the error */ | |
625 | if (0 == err) | |
626 | err = 1; | |
627 | break; | |
628 | } | |
629 | break; | |
630 | ||
631 | case DVB_FE_IOCTL_POST: | |
632 | /* no post-ioctl handling required */ | |
633 | break; | |
634 | } | |
635 | return err; | |
636 | }; | |
637 | ||
638 | static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter) | |
639 | { | |
640 | return I2C_FUNC_I2C; | |
641 | } | |
642 | ||
643 | struct i2c_algorithm mxl111sf_i2c_algo = { | |
644 | .master_xfer = mxl111sf_i2c_xfer, | |
645 | .functionality = mxl111sf_i2c_func, | |
646 | #ifdef NEED_ALGO_CONTROL | |
647 | .algo_control = dummy_algo_control, | |
648 | #endif | |
649 | }; | |
650 | ||
4f98480f MK |
651 | static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties; |
652 | static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties; | |
4c66c920 MK |
653 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; |
654 | static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; | |
655 | ||
656 | static int mxl111sf_probe(struct usb_interface *intf, | |
657 | const struct usb_device_id *id) | |
658 | { | |
659 | struct dvb_usb_device *d = NULL; | |
660 | ||
661 | deb_adv("%s()\n", __func__); | |
662 | ||
663 | if (((dvb_usb_mxl111sf_isoc) && | |
664 | (0 == dvb_usb_device_init(intf, | |
4f98480f MK |
665 | &mxl111sf_dvbt_isoc_properties, |
666 | THIS_MODULE, &d, adapter_nr) || | |
667 | 0 == dvb_usb_device_init(intf, | |
4c66c920 MK |
668 | &mxl111sf_atsc_isoc_properties, |
669 | THIS_MODULE, &d, adapter_nr))) || | |
4f98480f MK |
670 | 0 == dvb_usb_device_init(intf, |
671 | &mxl111sf_dvbt_bulk_properties, | |
672 | THIS_MODULE, &d, adapter_nr) || | |
4c66c920 MK |
673 | 0 == dvb_usb_device_init(intf, |
674 | &mxl111sf_atsc_bulk_properties, | |
675 | THIS_MODULE, &d, adapter_nr) || 0) { | |
676 | ||
677 | struct mxl111sf_state *state = d->priv; | |
678 | static u8 eeprom[256]; | |
679 | struct i2c_client c; | |
680 | int ret; | |
681 | ||
682 | ret = get_chip_info(state); | |
683 | if (mxl_fail(ret)) | |
684 | err("failed to get chip info during probe"); | |
685 | ||
686 | mutex_init(&state->fe_lock); | |
687 | ||
688 | if (state->chip_rev > MXL111SF_V6) | |
689 | mxl111sf_config_pin_mux_modes(state, | |
690 | PIN_MUX_TS_SPI_IN_MODE_1); | |
691 | ||
692 | c.adapter = &d->i2c_adap; | |
693 | c.addr = 0xa0 >> 1; | |
694 | ||
695 | ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); | |
696 | if (mxl_fail(ret)) | |
697 | return 0; | |
698 | tveeprom_hauppauge_analog(&c, &state->tv, | |
699 | (0x84 == eeprom[0xa0]) ? | |
700 | eeprom + 0xa0 : eeprom + 0x80); | |
701 | #if 0 | |
702 | switch (state->tv.model) { | |
703 | case 117001: | |
704 | case 126001: | |
705 | case 138001: | |
706 | break; | |
707 | default: | |
708 | printk(KERN_WARNING "%s: warning: " | |
709 | "unknown hauppauge model #%d\n", | |
710 | __func__, state->tv.model); | |
711 | } | |
712 | #endif | |
713 | return 0; | |
714 | } | |
715 | err("Your device is not yet supported by this driver. " | |
716 | "See kernellabs.com for more info"); | |
717 | return -EINVAL; | |
718 | } | |
719 | ||
720 | static struct usb_device_id mxl111sf_table[] = { | |
721 | /* 0 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600) }, /* ATSC+ IR */ | |
722 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601) }, /* ATSC */ | |
723 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602) }, /* + */ | |
724 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603) }, /* ATSC+ */ | |
725 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604) }, /* DVBT */ | |
726 | /* 5 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609) }, /* ATSC IR */ | |
727 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a) }, /* + IR */ | |
728 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b) }, /* ATSC+ IR */ | |
729 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c) }, /* DVBT IR */ | |
730 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653) }, /* ATSC+ */ | |
731 | /*10 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b) }, /* ATSC+ IR */ | |
732 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700) }, /* ATSC+ sw */ | |
733 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701) }, /* ATSC sw */ | |
734 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702) }, /* + sw */ | |
735 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703) }, /* ATSC+ sw */ | |
736 | /*15 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704) }, /* DVBT sw */ | |
737 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753) }, /* ATSC+ sw */ | |
738 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763) }, /* ATSC+ no */ | |
739 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764) }, /* DVBT no */ | |
740 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853) }, /* ATSC+ sw */ | |
741 | /*20 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854) }, /* DVBT sw */ | |
742 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863) }, /* ATSC+ no */ | |
743 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864) }, /* DVBT no */ | |
744 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3) }, /* ATSC+ sw */ | |
745 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4) }, /* DVBT sw */ | |
746 | /*25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3) }, /* ATSC+ no */ | |
747 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4) }, /* DVBT no */ | |
748 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff) }, /* ATSC+ */ | |
749 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612) }, /* + */ | |
750 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613) }, /* ATSC+ */ | |
751 | /*30 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a) }, /* + IR */ | |
752 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b) }, /* ATSC+ IR */ | |
753 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757) }, /* ATSC+DVBT sw */ | |
754 | { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767) }, /* ATSC+DVBT no */ | |
755 | {} /* Terminating entry */ | |
756 | }; | |
757 | MODULE_DEVICE_TABLE(usb, mxl111sf_table); | |
758 | ||
759 | ||
4f98480f | 760 | #define MXL111SF_EP4_BULK_STREAMING_CONFIG \ |
0d6ac1f8 | 761 | .size_of_priv = sizeof(struct mxl111sf_adap_state), \ |
4f98480f MK |
762 | .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ |
763 | .stream = { \ | |
764 | .type = USB_BULK, \ | |
765 | .count = 5, \ | |
766 | .endpoint = 0x04, \ | |
767 | .u = { \ | |
768 | .bulk = { \ | |
769 | .buffersize = 8192, \ | |
770 | } \ | |
771 | } \ | |
772 | } | |
773 | ||
774 | /* FIXME: works for v6 but not v8 silicon */ | |
775 | #define MXL111SF_EP4_ISOC_STREAMING_CONFIG \ | |
0d6ac1f8 | 776 | .size_of_priv = sizeof(struct mxl111sf_adap_state), \ |
4f98480f MK |
777 | .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ |
778 | .stream = { \ | |
779 | .type = USB_ISOC, \ | |
780 | .count = 5, \ | |
781 | .endpoint = 0x04, \ | |
782 | .u = { \ | |
783 | .isoc = { \ | |
784 | .framesperurb = 96, \ | |
785 | /* FIXME: v6 SILICON: */ \ | |
786 | .framesize = 564, \ | |
787 | .interval = 1, \ | |
788 | } \ | |
789 | } \ | |
790 | } | |
791 | ||
4c66c920 | 792 | #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ |
0d6ac1f8 | 793 | .size_of_priv = sizeof(struct mxl111sf_adap_state), \ |
4c66c920 MK |
794 | .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ |
795 | .stream = { \ | |
796 | .type = USB_BULK, \ | |
797 | .count = 5, \ | |
798 | .endpoint = 0x06, \ | |
799 | .u = { \ | |
800 | .bulk = { \ | |
801 | .buffersize = 8192, \ | |
802 | } \ | |
803 | } \ | |
804 | } | |
805 | ||
806 | /* FIXME */ | |
807 | #define MXL111SF_EP6_ISOC_STREAMING_CONFIG \ | |
0d6ac1f8 | 808 | .size_of_priv = sizeof(struct mxl111sf_adap_state), \ |
4c66c920 MK |
809 | .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ |
810 | .stream = { \ | |
811 | .type = USB_ISOC, \ | |
812 | .count = 5, \ | |
813 | .endpoint = 0x06, \ | |
814 | .u = { \ | |
815 | .isoc = { \ | |
816 | .framesperurb = 24, \ | |
817 | .framesize = 3072, \ | |
818 | .interval = 1, \ | |
819 | } \ | |
820 | } \ | |
821 | } | |
822 | ||
823 | #define MXL111SF_DEFAULT_DEVICE_PROPERTIES \ | |
824 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ | |
825 | .usb_ctrl = DEVICE_SPECIFIC, \ | |
826 | /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), \ | |
827 | EP6 BULK transfer (atsc/qam), \ | |
828 | use usb alt setting 2 for EP4 BULK transfer (dvb-t), \ | |
829 | EP6 ISOC transfer (atsc/qam), \ | |
830 | */ \ | |
831 | .power_ctrl = mxl111sf_power_ctrl, \ | |
832 | .i2c_algo = &mxl111sf_i2c_algo, \ | |
833 | .generic_bulk_ctrl_endpoint = MXL_EP2_REG_WRITE, \ | |
834 | .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \ | |
835 | .size_of_priv = sizeof(struct mxl111sf_state) | |
836 | ||
4f98480f | 837 | static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { |
4c66c920 MK |
838 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, |
839 | ||
840 | .num_adapters = 1, | |
841 | .adapter = { | |
842 | { | |
77eed219 MK |
843 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, |
844 | .num_frontends = 1, | |
845 | .fe = {{ | |
4f98480f MK |
846 | .frontend_attach = mxl111sf_attach_demod, |
847 | .tuner_attach = mxl111sf_attach_tuner, | |
848 | ||
849 | MXL111SF_EP4_BULK_STREAMING_CONFIG, | |
850 | } }, | |
851 | }, | |
852 | }, | |
853 | .num_device_descs = 4, | |
854 | .devices = { | |
855 | { "Hauppauge 126xxx DVBT (bulk)", | |
856 | { NULL }, | |
857 | { &mxl111sf_table[4], &mxl111sf_table[8], | |
858 | NULL }, | |
859 | }, | |
860 | { "Hauppauge 117xxx DVBT (bulk)", | |
861 | { NULL }, | |
862 | { &mxl111sf_table[15], &mxl111sf_table[18], | |
863 | NULL }, | |
864 | }, | |
865 | { "Hauppauge 138xxx DVBT (bulk)", | |
866 | { NULL }, | |
867 | { &mxl111sf_table[20], &mxl111sf_table[22], | |
868 | &mxl111sf_table[24], &mxl111sf_table[26], | |
869 | NULL }, | |
870 | }, | |
871 | { "Hauppauge 126xxx (tp-bulk)", | |
872 | { NULL }, | |
873 | { &mxl111sf_table[28], &mxl111sf_table[30], | |
874 | NULL }, | |
875 | }, | |
876 | } | |
877 | }; | |
878 | ||
879 | static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { | |
880 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | |
881 | ||
882 | .num_adapters = 1, | |
883 | .adapter = { | |
884 | { | |
885 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, | |
886 | .num_frontends = 1, | |
887 | .fe = {{ | |
4f98480f MK |
888 | .frontend_attach = mxl111sf_attach_demod, |
889 | .tuner_attach = mxl111sf_attach_tuner, | |
890 | ||
891 | MXL111SF_EP4_ISOC_STREAMING_CONFIG, | |
892 | } }, | |
893 | }, | |
894 | }, | |
895 | .num_device_descs = 4, | |
896 | .devices = { | |
897 | { "Hauppauge 126xxx DVBT (isoc)", | |
898 | { NULL }, | |
899 | { &mxl111sf_table[4], &mxl111sf_table[8], | |
900 | NULL }, | |
901 | }, | |
902 | { "Hauppauge 117xxx DVBT (isoc)", | |
903 | { NULL }, | |
904 | { &mxl111sf_table[15], &mxl111sf_table[18], | |
905 | NULL }, | |
906 | }, | |
907 | { "Hauppauge 138xxx DVBT (isoc)", | |
908 | { NULL }, | |
909 | { &mxl111sf_table[20], &mxl111sf_table[22], | |
910 | &mxl111sf_table[24], &mxl111sf_table[26], | |
911 | NULL }, | |
912 | }, | |
913 | { "Hauppauge 126xxx (tp-isoc)", | |
914 | { NULL }, | |
915 | { &mxl111sf_table[28], &mxl111sf_table[30], | |
916 | NULL }, | |
917 | }, | |
918 | } | |
919 | }; | |
920 | ||
921 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { | |
922 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | |
923 | ||
924 | .num_adapters = 1, | |
925 | .adapter = { | |
926 | { | |
927 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, | |
928 | .num_frontends = 2, | |
929 | .fe = {{ | |
4c66c920 MK |
930 | .frontend_attach = mxl111sf_lgdt3305_frontend_attach, |
931 | .tuner_attach = mxl111sf_attach_tuner, | |
932 | ||
933 | MXL111SF_EP6_BULK_STREAMING_CONFIG, | |
4f98480f MK |
934 | }, |
935 | { | |
4f98480f MK |
936 | .frontend_attach = mxl111sf_attach_demod, |
937 | .tuner_attach = mxl111sf_attach_tuner, | |
938 | ||
939 | MXL111SF_EP4_BULK_STREAMING_CONFIG, | |
77eed219 | 940 | }}, |
4c66c920 MK |
941 | }, |
942 | }, | |
943 | .num_device_descs = 6, | |
944 | .devices = { | |
945 | { "Hauppauge 126xxx ATSC (bulk)", | |
946 | { NULL }, | |
947 | { &mxl111sf_table[1], &mxl111sf_table[5], | |
948 | NULL }, | |
949 | }, | |
950 | { "Hauppauge 117xxx ATSC (bulk)", | |
951 | { NULL }, | |
952 | { &mxl111sf_table[12], | |
953 | NULL }, | |
954 | }, | |
955 | { "Hauppauge 126xxx ATSC+ (bulk)", | |
956 | { NULL }, | |
957 | { &mxl111sf_table[0], &mxl111sf_table[3], | |
958 | &mxl111sf_table[7], &mxl111sf_table[9], | |
959 | &mxl111sf_table[10], NULL }, | |
960 | }, | |
961 | { "Hauppauge 117xxx ATSC+ (bulk)", | |
962 | { NULL }, | |
963 | { &mxl111sf_table[11], &mxl111sf_table[14], | |
964 | &mxl111sf_table[16], &mxl111sf_table[17], | |
965 | &mxl111sf_table[32], &mxl111sf_table[33], | |
966 | NULL }, | |
967 | }, | |
968 | { "Hauppauge Mercury (tp-bulk)", | |
969 | { NULL }, | |
970 | { &mxl111sf_table[19], &mxl111sf_table[21], | |
971 | &mxl111sf_table[23], &mxl111sf_table[25], | |
972 | &mxl111sf_table[27], NULL }, | |
973 | }, | |
974 | { "Hauppauge WinTV-Aero-M", | |
975 | { NULL }, | |
976 | { &mxl111sf_table[29], &mxl111sf_table[31], | |
977 | NULL }, | |
978 | }, | |
979 | } | |
980 | }; | |
981 | ||
982 | static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { | |
983 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | |
984 | ||
985 | .num_adapters = 1, | |
986 | .adapter = { | |
987 | { | |
77eed219 | 988 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, |
4f98480f | 989 | .num_frontends = 2, |
77eed219 | 990 | .fe = {{ |
4c66c920 MK |
991 | .frontend_attach = mxl111sf_lgdt3305_frontend_attach, |
992 | .tuner_attach = mxl111sf_attach_tuner, | |
993 | ||
994 | MXL111SF_EP6_ISOC_STREAMING_CONFIG, | |
4f98480f MK |
995 | }, |
996 | { | |
4f98480f MK |
997 | .frontend_attach = mxl111sf_attach_demod, |
998 | .tuner_attach = mxl111sf_attach_tuner, | |
999 | ||
1000 | MXL111SF_EP4_ISOC_STREAMING_CONFIG, | |
77eed219 | 1001 | }}, |
4c66c920 MK |
1002 | }, |
1003 | }, | |
1004 | .num_device_descs = 6, | |
1005 | .devices = { | |
1006 | { "Hauppauge 126xxx ATSC (isoc)", | |
1007 | { NULL }, | |
1008 | { &mxl111sf_table[1], &mxl111sf_table[5], | |
1009 | NULL }, | |
1010 | }, | |
1011 | { "Hauppauge 117xxx ATSC (isoc)", | |
1012 | { NULL }, | |
1013 | { &mxl111sf_table[12], | |
1014 | NULL }, | |
1015 | }, | |
1016 | { "Hauppauge 126xxx ATSC+ (isoc)", | |
1017 | { NULL }, | |
1018 | { &mxl111sf_table[0], &mxl111sf_table[3], | |
1019 | &mxl111sf_table[7], &mxl111sf_table[9], | |
1020 | &mxl111sf_table[10], NULL }, | |
1021 | }, | |
1022 | { "Hauppauge 117xxx ATSC+ (isoc)", | |
1023 | { NULL }, | |
1024 | { &mxl111sf_table[11], &mxl111sf_table[14], | |
1025 | &mxl111sf_table[16], &mxl111sf_table[17], | |
1026 | &mxl111sf_table[32], &mxl111sf_table[33], | |
1027 | NULL }, | |
1028 | }, | |
1029 | { "Hauppauge Mercury (tp-isoc)", | |
1030 | { NULL }, | |
1031 | { &mxl111sf_table[19], &mxl111sf_table[21], | |
1032 | &mxl111sf_table[23], &mxl111sf_table[25], | |
1033 | &mxl111sf_table[27], NULL }, | |
1034 | }, | |
1035 | { "Hauppauge WinTV-Aero-M (tp-isoc)", | |
1036 | { NULL }, | |
1037 | { &mxl111sf_table[29], &mxl111sf_table[31], | |
1038 | NULL }, | |
1039 | }, | |
1040 | } | |
1041 | }; | |
1042 | ||
1043 | static struct usb_driver mxl111sf_driver = { | |
1044 | .name = "dvb_usb_mxl111sf", | |
1045 | .probe = mxl111sf_probe, | |
1046 | .disconnect = dvb_usb_device_exit, | |
1047 | .id_table = mxl111sf_table, | |
1048 | }; | |
1049 | ||
ecb3b2b3 | 1050 | module_usb_driver(mxl111sf_driver); |
4c66c920 MK |
1051 | |
1052 | MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>"); | |
1053 | MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); | |
1054 | MODULE_VERSION("1.0"); | |
1055 | MODULE_LICENSE("GPL"); | |
1056 | ||
1057 | /* | |
1058 | * Local variables: | |
1059 | * c-basic-offset: 8 | |
1060 | * End: | |
1061 | */ |