Commit | Line | Data |
---|---|---|
776338e1 JS |
1 | /* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0 |
2 | * receiver | |
3 | * | |
78c6e73f | 4 | * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) |
776338e1 | 5 | * |
78c6e73f | 6 | * partly based on the SDK published by Nebula Electronics |
776338e1 JS |
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 | 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 | ||
24 | static int digitv_ctrl_msg(struct dvb_usb_device *d, | |
25 | u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) | |
26 | { | |
27 | int wo = (rbuf == NULL || rlen == 0); /* write-only */ | |
28 | u8 sndbuf[7],rcvbuf[7]; | |
29 | memset(sndbuf,0,7); memset(rcvbuf,0,7); | |
30 | ||
31 | sndbuf[0] = cmd; | |
32 | sndbuf[1] = vv; | |
33 | sndbuf[2] = wo ? wlen : rlen; | |
34 | ||
4302c15e | 35 | if (wo) { |
776338e1 JS |
36 | memcpy(&sndbuf[3],wbuf,wlen); |
37 | dvb_usb_generic_write(d,sndbuf,7); | |
38 | } else { | |
39 | dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10); | |
97432808 | 40 | memcpy(rbuf,&rcvbuf[3],rlen); |
776338e1 JS |
41 | } |
42 | return 0; | |
43 | } | |
44 | ||
45 | /* I2C */ | |
46 | static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) | |
47 | { | |
48 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | |
49 | int i; | |
50 | ||
3593cab5 | 51 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) |
776338e1 JS |
52 | return -EAGAIN; |
53 | ||
54 | if (num > 2) | |
55 | warn("more than 2 i2c messages at a time is not handled yet. TODO."); | |
56 | ||
57 | for (i = 0; i < num; i++) { | |
58 | /* write/read request */ | |
59 | if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { | |
60 | if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, | |
61 | msg[i+1].buf,msg[i+1].len) < 0) | |
62 | break; | |
63 | i++; | |
64 | } else | |
65 | if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0], | |
66 | &msg[i].buf[1],msg[i].len-1,NULL,0) < 0) | |
67 | break; | |
68 | } | |
69 | ||
3593cab5 | 70 | mutex_unlock(&d->i2c_mutex); |
776338e1 JS |
71 | return i; |
72 | } | |
73 | ||
74 | static u32 digitv_i2c_func(struct i2c_adapter *adapter) | |
75 | { | |
76 | return I2C_FUNC_I2C; | |
77 | } | |
78 | ||
79 | static struct i2c_algorithm digitv_i2c_algo = { | |
776338e1 JS |
80 | .master_xfer = digitv_i2c_xfer, |
81 | .functionality = digitv_i2c_func, | |
82 | }; | |
83 | ||
84 | /* Callbacks for DVB USB */ | |
85 | static int digitv_identify_state (struct usb_device *udev, struct | |
86 | dvb_usb_properties *props, struct dvb_usb_device_description **desc, | |
87 | int *cold) | |
88 | { | |
89 | *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; | |
90 | return 0; | |
91 | } | |
92 | ||
93 | static int digitv_mt352_demod_init(struct dvb_frontend *fe) | |
94 | { | |
78c6e73f PB |
95 | static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; |
96 | static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, | |
97 | 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, | |
98 | 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, | |
99 | 0x75, 0x32 }; | |
100 | int i; | |
776338e1 | 101 | |
78c6e73f PB |
102 | for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) |
103 | mt352_write(fe, &reset_buf[i], 2); | |
776338e1 | 104 | |
776338e1 | 105 | msleep(1); |
776338e1 | 106 | |
78c6e73f PB |
107 | for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) |
108 | mt352_write(fe, &init_buf[i], 2); | |
776338e1 JS |
109 | |
110 | return 0; | |
111 | } | |
112 | ||
113 | static struct mt352_config digitv_mt352_config = { | |
776338e1 | 114 | .demod_init = digitv_mt352_demod_init, |
78c6e73f | 115 | .pll_set = dvb_usb_pll_set, |
776338e1 JS |
116 | }; |
117 | ||
115eea4e SO |
118 | static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) |
119 | { | |
120 | struct dvb_usb_device *d = fe->dvb->priv; | |
121 | u8 b[5]; | |
122 | dvb_usb_pll_set(fe,fep,b); | |
123 | return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0); | |
124 | } | |
776338e1 | 125 | |
115eea4e SO |
126 | static struct nxt6000_config digitv_nxt6000_config = { |
127 | .clock_inversion = 1, | |
128 | .pll_set = digitv_nxt6000_pll_set, | |
776338e1 JS |
129 | }; |
130 | ||
131 | static int digitv_frontend_attach(struct dvb_usb_device *d) | |
132 | { | |
115eea4e SO |
133 | if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL || |
134 | (d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) | |
776338e1 | 135 | return 0; |
776338e1 JS |
136 | return -EIO; |
137 | } | |
138 | ||
78c6e73f PB |
139 | static int digitv_tuner_attach(struct dvb_usb_device *d) |
140 | { | |
141 | d->pll_addr = 0x60; | |
142 | d->pll_desc = &dvb_pll_tded4; | |
143 | return 0; | |
144 | } | |
145 | ||
776338e1 JS |
146 | static struct dvb_usb_rc_key digitv_rc_keys[] = { |
147 | { 0x00, 0x16, KEY_POWER }, /* dummy key */ | |
148 | }; | |
149 | ||
150 | /* TODO is it really the NEC protocol ? */ | |
15ac8e66 | 151 | static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) |
776338e1 JS |
152 | { |
153 | u8 key[5]; | |
154 | ||
155 | digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4); | |
156 | /* TODO state, maybe it is VV ? */ | |
157 | if (key[1] != 0) | |
158 | key[0] = 0x01; /* if something is inside the buffer, simulate key press */ | |
159 | ||
160 | /* call the universal NEC remote processor, to find out the key's state and event */ | |
161 | dvb_usb_nec_rc_key_to_event(d,key,event,state); | |
162 | if (key[0] != 0) | |
163 | deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); | |
164 | return 0; | |
165 | } | |
166 | ||
776338e1 JS |
167 | /* DVB USB Driver stuff */ |
168 | static struct dvb_usb_properties digitv_properties; | |
169 | ||
170 | static int digitv_probe(struct usb_interface *intf, | |
171 | const struct usb_device_id *id) | |
172 | { | |
115eea4e SO |
173 | struct dvb_usb_device *d; |
174 | int ret; | |
175 | if ((ret = dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE,&d)) == 0) { | |
176 | u8 b[4] = { 0 }; | |
177 | ||
21d06544 PB |
178 | if (d != NULL) { /* do that only when the firmware is loaded */ |
179 | b[0] = 1; | |
180 | digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); | |
115eea4e | 181 | |
21d06544 PB |
182 | b[0] = 0; |
183 | digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); | |
184 | } | |
115eea4e SO |
185 | } |
186 | return ret; | |
776338e1 JS |
187 | } |
188 | ||
189 | static struct usb_device_id digitv_table [] = { | |
190 | { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) }, | |
191 | { } /* Terminating entry */ | |
192 | }; | |
193 | MODULE_DEVICE_TABLE (usb, digitv_table); | |
194 | ||
195 | static struct dvb_usb_properties digitv_properties = { | |
196 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | |
197 | ||
198 | .usb_ctrl = CYPRESS_FX2, | |
21d06544 | 199 | .firmware = "dvb-usb-digitv-02.fw", |
776338e1 JS |
200 | |
201 | .size_of_priv = 0, | |
202 | ||
776338e1 | 203 | .frontend_attach = digitv_frontend_attach, |
78c6e73f | 204 | .tuner_attach = digitv_tuner_attach, |
776338e1 JS |
205 | |
206 | .rc_interval = 1000, | |
207 | .rc_key_map = digitv_rc_keys, | |
208 | .rc_key_map_size = ARRAY_SIZE(digitv_rc_keys), | |
209 | .rc_query = digitv_rc_query, | |
210 | ||
211 | .identify_state = digitv_identify_state, | |
212 | ||
213 | .i2c_algo = &digitv_i2c_algo, | |
214 | ||
215 | .generic_bulk_ctrl_endpoint = 0x01, | |
216 | /* parameter for the MPEG2-data transfer */ | |
217 | .urb = { | |
218 | .type = DVB_USB_BULK, | |
219 | .count = 7, | |
220 | .endpoint = 0x02, | |
221 | .u = { | |
222 | .bulk = { | |
223 | .buffersize = 4096, | |
224 | } | |
225 | } | |
226 | }, | |
227 | ||
78c6e73f | 228 | .num_device_descs = 1, |
776338e1 JS |
229 | .devices = { |
230 | { "Nebula Electronics uDigiTV DVB-T USB2.0)", | |
231 | { &digitv_table[0], NULL }, | |
232 | { NULL }, | |
233 | }, | |
21d06544 | 234 | { NULL }, |
776338e1 JS |
235 | } |
236 | }; | |
237 | ||
238 | static struct usb_driver digitv_driver = { | |
63b5c1c4 | 239 | .name = "dvb_usb_digitv", |
776338e1 JS |
240 | .probe = digitv_probe, |
241 | .disconnect = dvb_usb_device_exit, | |
242 | .id_table = digitv_table, | |
243 | }; | |
244 | ||
245 | /* module stuff */ | |
246 | static int __init digitv_module_init(void) | |
247 | { | |
248 | int result; | |
249 | if ((result = usb_register(&digitv_driver))) { | |
250 | err("usb_register failed. Error number %d",result); | |
251 | return result; | |
252 | } | |
253 | ||
254 | return 0; | |
255 | } | |
256 | ||
257 | static void __exit digitv_module_exit(void) | |
258 | { | |
259 | /* deregister this driver from the USB subsystem */ | |
260 | usb_deregister(&digitv_driver); | |
261 | } | |
262 | ||
263 | module_init (digitv_module_init); | |
264 | module_exit (digitv_module_exit); | |
265 | ||
266 | MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); | |
267 | MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0"); | |
268 | MODULE_VERSION("1.0-alpha"); | |
269 | MODULE_LICENSE("GPL"); |