Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
digitv.c
Go to the documentation of this file.
1 /* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
2  * receiver
3  *
4  * Copyright (C) 2005 Patrick Boettcher ([email protected])
5  *
6  * partly based on the SDK published by Nebula Electronics
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the Free
10  * Software Foundation, version 2.
11  *
12  * see Documentation/dvb/README.dvb-usb for more information
13  */
14 #include "digitv.h"
15 
16 #include "mt352.h"
17 #include "nxt6000.h"
18 
19 /* debug */
20 static int dvb_usb_digitv_debug;
21 module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
22 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
23 
25 
26 #define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args)
27 
28 static int digitv_ctrl_msg(struct dvb_usb_device *d,
29  u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
30 {
31  int wo = (rbuf == NULL || rlen == 0); /* write-only */
32  u8 sndbuf[7],rcvbuf[7];
33  memset(sndbuf,0,7); memset(rcvbuf,0,7);
34 
35  sndbuf[0] = cmd;
36  sndbuf[1] = vv;
37  sndbuf[2] = wo ? wlen : rlen;
38 
39  if (wo) {
40  memcpy(&sndbuf[3],wbuf,wlen);
41  dvb_usb_generic_write(d,sndbuf,7);
42  } else {
43  dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
44  memcpy(rbuf,&rcvbuf[3],rlen);
45  }
46  return 0;
47 }
48 
49 /* I2C */
50 static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
51 {
52  struct dvb_usb_device *d = i2c_get_adapdata(adap);
53  int i;
54 
56  return -EAGAIN;
57 
58  if (num > 2)
59  warn("more than 2 i2c messages at a time is not handled yet. TODO.");
60 
61  for (i = 0; i < num; i++) {
62  /* write/read request */
63  if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
64  if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
65  msg[i+1].buf,msg[i+1].len) < 0)
66  break;
67  i++;
68  } else
69  if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0],
70  &msg[i].buf[1],msg[i].len-1,NULL,0) < 0)
71  break;
72  }
73 
75  return i;
76 }
77 
78 static u32 digitv_i2c_func(struct i2c_adapter *adapter)
79 {
80  return I2C_FUNC_I2C;
81 }
82 
83 static struct i2c_algorithm digitv_i2c_algo = {
84  .master_xfer = digitv_i2c_xfer,
85  .functionality = digitv_i2c_func,
86 };
87 
88 /* Callbacks for DVB USB */
89 static int digitv_identify_state (struct usb_device *udev, struct
91  int *cold)
92 {
93  *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
94  return 0;
95 }
96 
97 static int digitv_mt352_demod_init(struct dvb_frontend *fe)
98 {
99  static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 };
100  static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50,
101  0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00,
102  0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f,
103  0x75, 0x32 };
104  int i;
105 
106  for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2)
107  mt352_write(fe, &reset_buf[i], 2);
108 
109  msleep(1);
110 
111  for (i = 0; i < ARRAY_SIZE(init_buf); i += 2)
112  mt352_write(fe, &init_buf[i], 2);
113 
114  return 0;
115 }
116 
117 static struct mt352_config digitv_mt352_config = {
118  .demod_init = digitv_mt352_demod_init,
119 };
120 
121 static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe)
122 {
123  struct dvb_usb_adapter *adap = fe->dvb->priv;
124  u8 b[5];
125 
126  fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b));
127  if (fe->ops.i2c_gate_ctrl)
128  fe->ops.i2c_gate_ctrl(fe, 1);
129  return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
130 }
131 
132 static struct nxt6000_config digitv_nxt6000_config = {
133  .clock_inversion = 1,
134 };
135 
136 static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
137 {
138  struct digitv_state *st = adap->dev->priv;
139 
140  adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config,
141  &adap->dev->i2c_adap);
142  if ((adap->fe_adap[0].fe) != NULL) {
143  st->is_nxt6000 = 0;
144  return 0;
145  }
146  adap->fe_adap[0].fe = dvb_attach(nxt6000_attach,
147  &digitv_nxt6000_config,
148  &adap->dev->i2c_adap);
149  if ((adap->fe_adap[0].fe) != NULL) {
150  st->is_nxt6000 = 1;
151  return 0;
152  }
153  return -EIO;
154 }
155 
156 static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
157 {
158  struct digitv_state *st = adap->dev->priv;
159 
160  if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4))
161  return -ENODEV;
162 
163  if (st->is_nxt6000)
164  adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
165 
166  return 0;
167 }
168 
169 static struct rc_map_table rc_map_digitv_table[] = {
170  { 0x5f55, KEY_0 },
171  { 0x6f55, KEY_1 },
172  { 0x9f55, KEY_2 },
173  { 0xaf55, KEY_3 },
174  { 0x5f56, KEY_4 },
175  { 0x6f56, KEY_5 },
176  { 0x9f56, KEY_6 },
177  { 0xaf56, KEY_7 },
178  { 0x5f59, KEY_8 },
179  { 0x6f59, KEY_9 },
180  { 0x9f59, KEY_TV },
181  { 0xaf59, KEY_AUX },
182  { 0x5f5a, KEY_DVD },
183  { 0x6f5a, KEY_POWER },
184  { 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */
185  { 0xaf5a, KEY_AUDIO },
186  { 0x5f65, KEY_INFO },
187  { 0x6f65, KEY_F13 }, /* 16:9 */
188  { 0x9f65, KEY_F14 }, /* 14:9 */
189  { 0xaf65, KEY_EPG },
190  { 0x5f66, KEY_EXIT },
191  { 0x6f66, KEY_MENU },
192  { 0x9f66, KEY_UP },
193  { 0xaf66, KEY_DOWN },
194  { 0x5f69, KEY_LEFT },
195  { 0x6f69, KEY_RIGHT },
196  { 0x9f69, KEY_ENTER },
197  { 0xaf69, KEY_CHANNELUP },
198  { 0x5f6a, KEY_CHANNELDOWN },
199  { 0x6f6a, KEY_VOLUMEUP },
200  { 0x9f6a, KEY_VOLUMEDOWN },
201  { 0xaf6a, KEY_RED },
202  { 0x5f95, KEY_GREEN },
203  { 0x6f95, KEY_YELLOW },
204  { 0x9f95, KEY_BLUE },
205  { 0xaf95, KEY_SUBTITLE },
206  { 0x5f96, KEY_F15 }, /* AD */
207  { 0x6f96, KEY_TEXT },
208  { 0x9f96, KEY_MUTE },
209  { 0xaf96, KEY_REWIND },
210  { 0x5f99, KEY_STOP },
211  { 0x6f99, KEY_PLAY },
212  { 0x9f99, KEY_FASTFORWARD },
213  { 0xaf99, KEY_F16 }, /* chapter */
214  { 0x5f9a, KEY_PAUSE },
215  { 0x6f9a, KEY_PLAY },
216  { 0x9f9a, KEY_RECORD },
217  { 0xaf9a, KEY_F17 }, /* picture in picture */
218  { 0x5fa5, KEY_KPPLUS }, /* zoom in */
219  { 0x6fa5, KEY_KPMINUS }, /* zoom out */
220  { 0x9fa5, KEY_F18 }, /* capture */
221  { 0xafa5, KEY_F19 }, /* web */
222  { 0x5fa6, KEY_EMAIL },
223  { 0x6fa6, KEY_PHONE },
224  { 0x9fa6, KEY_PC },
225 };
226 
227 static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
228 {
229  int i;
230  u8 key[5];
231  u8 b[4] = { 0 };
232 
233  *event = 0;
234  *state = REMOTE_NO_KEY_PRESSED;
235 
236  digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
237 
238  /* Tell the device we've read the remote. Not sure how necessary
239  this is, but the Nebula SDK does it. */
240  digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
241 
242  /* if something is inside the buffer, simulate key press */
243  if (key[1] != 0)
244  {
245  for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
246  if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] &&
247  rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) {
248  *event = d->props.rc.legacy.rc_map_table[i].keycode;
249  *state = REMOTE_KEY_PRESSED;
250  return 0;
251  }
252  }
253  }
254 
255  if (key[0] != 0)
256  deb_rc("key: %*ph\n", 5, key);
257  return 0;
258 }
259 
260 /* DVB USB Driver stuff */
261 static struct dvb_usb_device_properties digitv_properties;
262 
263 static int digitv_probe(struct usb_interface *intf,
264  const struct usb_device_id *id)
265 {
266  struct dvb_usb_device *d;
267  int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d,
268  adapter_nr);
269  if (ret == 0) {
270  u8 b[4] = { 0 };
271 
272  if (d != NULL) { /* do that only when the firmware is loaded */
273  b[0] = 1;
274  digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0);
275 
276  b[0] = 0;
277  digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
278  }
279  }
280  return ret;
281 }
282 
283 static struct usb_device_id digitv_table [] = {
284  { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) },
285  { } /* Terminating entry */
286 };
287 MODULE_DEVICE_TABLE (usb, digitv_table);
288 
289 static struct dvb_usb_device_properties digitv_properties = {
291 
292  .usb_ctrl = CYPRESS_FX2,
293  .firmware = "dvb-usb-digitv-02.fw",
294 
295  .size_of_priv = sizeof(struct digitv_state),
296 
297  .num_adapters = 1,
298  .adapter = {
299  {
300  .num_frontends = 1,
301  .fe = {{
302  .frontend_attach = digitv_frontend_attach,
303  .tuner_attach = digitv_tuner_attach,
304 
305  /* parameter for the MPEG2-data transfer */
306  .stream = {
307  .type = USB_BULK,
308  .count = 7,
309  .endpoint = 0x02,
310  .u = {
311  .bulk = {
312  .buffersize = 4096,
313  }
314  }
315  },
316  }},
317  }
318  },
319  .identify_state = digitv_identify_state,
320 
321  .rc.legacy = {
322  .rc_interval = 1000,
323  .rc_map_table = rc_map_digitv_table,
324  .rc_map_size = ARRAY_SIZE(rc_map_digitv_table),
325  .rc_query = digitv_rc_query,
326  },
327 
328  .i2c_algo = &digitv_i2c_algo,
329 
330  .generic_bulk_ctrl_endpoint = 0x01,
331 
332  .num_device_descs = 1,
333  .devices = {
334  { "Nebula Electronics uDigiTV DVB-T USB2.0)",
335  { &digitv_table[0], NULL },
336  { NULL },
337  },
338  { NULL },
339  }
340 };
341 
342 static struct usb_driver digitv_driver = {
343  .name = "dvb_usb_digitv",
344  .probe = digitv_probe,
345  .disconnect = dvb_usb_device_exit,
346  .id_table = digitv_table,
347 };
348 
349 module_usb_driver(digitv_driver);
350 
351 MODULE_AUTHOR("Patrick Boettcher <[email protected]>");
352 MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
353 MODULE_VERSION("1.0-alpha");
354 MODULE_LICENSE("GPL");