diff options
Diffstat (limited to 'drivers/media/video/au0828/au0828-dvb.c')
-rw-r--r-- | drivers/media/video/au0828/au0828-dvb.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c new file mode 100644 index 000000000000..3c8a29eafc2d --- /dev/null +++ b/drivers/media/video/au0828/au0828-dvb.c | |||
@@ -0,0 +1,371 @@ | |||
1 | /* | ||
2 | * Driver for the Auvitek USB bridge | ||
3 | * | ||
4 | * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/suspend.h> | ||
26 | #include <media/v4l2-common.h> | ||
27 | |||
28 | #include "au0828.h" | ||
29 | |||
30 | #include "au8522.h" | ||
31 | #include "xc5000.h" | ||
32 | |||
33 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
34 | |||
35 | unsigned int dvb_debug = 1; | ||
36 | |||
37 | #define _dbg(level, fmt, arg...)\ | ||
38 | do { if (dvb_debug >= level)\ | ||
39 | printk(KERN_DEBUG "%s/0: " fmt, DRIVER_NAME, ## arg);\ | ||
40 | } while (0) | ||
41 | |||
42 | static struct au8522_config hauppauge_hvr950q_config = { | ||
43 | .demod_address = 0x8e >> 1, | ||
44 | .status_mode = AU8522_DEMODLOCKING, | ||
45 | }; | ||
46 | |||
47 | static struct xc5000_config hauppauge_hvr950q_tunerconfig = { | ||
48 | .i2c_address = 0x61, | ||
49 | .if_khz = 6000, | ||
50 | .tuner_callback = au0828_tuner_callback | ||
51 | }; | ||
52 | |||
53 | /*-------------------------------------------------------------------*/ | ||
54 | static void urb_completion(struct urb *purb) | ||
55 | { | ||
56 | u8 *ptr; | ||
57 | struct au0828_dev *dev = purb->context; | ||
58 | int ptype = usb_pipetype(purb->pipe); | ||
59 | |||
60 | if (dev->urb_streaming == 0) | ||
61 | return; | ||
62 | |||
63 | if (ptype != PIPE_BULK) { | ||
64 | printk(KERN_ERR "%s() Unsupported URB type %d\n", __FUNCTION__, ptype); | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | ptr = (u8 *)purb->transfer_buffer; | ||
69 | |||
70 | /* Feed the transport payload into the kernel demux */ | ||
71 | dvb_dmx_swfilter_packets(&dev->dvb.demux, purb->transfer_buffer, purb->actual_length / 188); | ||
72 | |||
73 | /* Clean the buffer before we requeue */ | ||
74 | memset(purb->transfer_buffer, 0, URB_BUFSIZE); | ||
75 | |||
76 | /* Requeue URB */ | ||
77 | usb_submit_urb(purb, GFP_ATOMIC); | ||
78 | } | ||
79 | |||
80 | static int stop_urb_transfer(struct au0828_dev *dev) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | printk(KERN_INFO "%s()\n", __FUNCTION__); | ||
85 | |||
86 | /* FIXME: Do we need to free the transfer_buffers? */ | ||
87 | for (i = 0; i < URB_COUNT; i++) { | ||
88 | usb_kill_urb(dev->urbs[i]); | ||
89 | kfree(dev->urbs[i]->transfer_buffer); | ||
90 | usb_free_urb(dev->urbs[i]); | ||
91 | } | ||
92 | |||
93 | dev->urb_streaming = 0; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | #define _AU0828_BULKPIPE 0x83 | ||
99 | #define _BULKPIPESIZE 0xe522 | ||
100 | |||
101 | static int start_urb_transfer(struct au0828_dev *dev) | ||
102 | { | ||
103 | struct urb *purb; | ||
104 | int i, ret = -ENOMEM; | ||
105 | unsigned int pipe = usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE); | ||
106 | int pipesize = usb_maxpacket(dev->usbdev, pipe, usb_pipeout(pipe)); | ||
107 | int packets = _BULKPIPESIZE / pipesize; | ||
108 | int transfer_buflen = packets * pipesize; | ||
109 | |||
110 | printk(KERN_INFO "%s() transfer_buflen = %d\n", __FUNCTION__, transfer_buflen); | ||
111 | |||
112 | if (dev->urb_streaming) { | ||
113 | printk("%s: iso xfer already running!\n", __FUNCTION__); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | for (i = 0; i < URB_COUNT; i++) { | ||
118 | |||
119 | dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); | ||
120 | if (!dev->urbs[i]) { | ||
121 | goto err; | ||
122 | } | ||
123 | |||
124 | purb = dev->urbs[i]; | ||
125 | |||
126 | purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); | ||
127 | if (!purb->transfer_buffer) { | ||
128 | usb_free_urb(purb); | ||
129 | dev->urbs[i] = 0; | ||
130 | goto err; | ||
131 | } | ||
132 | |||
133 | purb->status = -EINPROGRESS; | ||
134 | usb_fill_bulk_urb(purb, | ||
135 | dev->usbdev, | ||
136 | usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE), | ||
137 | purb->transfer_buffer, | ||
138 | URB_BUFSIZE, | ||
139 | urb_completion, | ||
140 | dev); | ||
141 | |||
142 | } | ||
143 | |||
144 | for (i = 0; i < URB_COUNT; i++) { | ||
145 | ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC); | ||
146 | if (ret != 0) { | ||
147 | stop_urb_transfer(dev); | ||
148 | printk("%s: failed urb submission, err = %d\n", __FUNCTION__, ret); | ||
149 | return ret; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | dev->urb_streaming = 1; | ||
154 | ret = 0; | ||
155 | |||
156 | err: | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) | ||
161 | { | ||
162 | struct dvb_demux *demux = feed->demux; | ||
163 | struct au0828_dev *dev = (struct au0828_dev *) demux->priv; | ||
164 | struct au0828_dvb *dvb = &dev->dvb; | ||
165 | int ret = 0; | ||
166 | |||
167 | printk(KERN_INFO "%s() pid = 0x%x index = %d\n", __FUNCTION__, feed->pid, feed->index); | ||
168 | |||
169 | if (!demux->dmx.frontend) | ||
170 | return -EINVAL; | ||
171 | |||
172 | printk(KERN_INFO "%s() Preparing, feeding = %d\n", __FUNCTION__, dvb->feeding); | ||
173 | if (dvb) { | ||
174 | mutex_lock(&dvb->lock); | ||
175 | if (dvb->feeding++ == 0) { | ||
176 | printk(KERN_INFO "%s() Starting Transport DMA\n", | ||
177 | __FUNCTION__); | ||
178 | au0828_write(dev, 0x608, 0x90); | ||
179 | au0828_write(dev, 0x609, 0x72); | ||
180 | au0828_write(dev, 0x60a, 0x71); | ||
181 | au0828_write(dev, 0x60b, 0x01); | ||
182 | ret = start_urb_transfer(dev); | ||
183 | } | ||
184 | mutex_unlock(&dvb->lock); | ||
185 | } | ||
186 | |||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) | ||
191 | { | ||
192 | struct dvb_demux *demux = feed->demux; | ||
193 | struct au0828_dev *dev = (struct au0828_dev *) demux->priv; | ||
194 | struct au0828_dvb *dvb = &dev->dvb; | ||
195 | int ret = 0; | ||
196 | |||
197 | printk(KERN_INFO "%s() pid = 0x%x index = %d\n", __FUNCTION__, feed->pid, feed->index); | ||
198 | |||
199 | if (dvb) { | ||
200 | mutex_lock(&dvb->lock); | ||
201 | if (--dvb->feeding == 0) { | ||
202 | printk(KERN_INFO "%s() Stopping Transport DMA\n", | ||
203 | __FUNCTION__); | ||
204 | au0828_write(dev, 0x608, 0x00); | ||
205 | au0828_write(dev, 0x609, 0x00); | ||
206 | au0828_write(dev, 0x60a, 0x00); | ||
207 | au0828_write(dev, 0x60b, 0x00); | ||
208 | ret = stop_urb_transfer(dev); | ||
209 | } | ||
210 | mutex_unlock(&dvb->lock); | ||
211 | } | ||
212 | |||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | int dvb_register(struct au0828_dev *dev) | ||
217 | { | ||
218 | struct au0828_dvb *dvb = &dev->dvb; | ||
219 | int result; | ||
220 | |||
221 | /* register adapter */ | ||
222 | result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, | ||
223 | &dev->usbdev->dev, adapter_nr); | ||
224 | if (result < 0) { | ||
225 | printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", | ||
226 | DRIVER_NAME, result); | ||
227 | goto fail_adapter; | ||
228 | } | ||
229 | dvb->adapter.priv = dev; | ||
230 | |||
231 | /* register frontend */ | ||
232 | result = dvb_register_frontend(&dvb->adapter, dvb->frontend); | ||
233 | if (result < 0) { | ||
234 | printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", | ||
235 | DRIVER_NAME, result); | ||
236 | goto fail_frontend; | ||
237 | } | ||
238 | |||
239 | /* register demux stuff */ | ||
240 | dvb->demux.dmx.capabilities = | ||
241 | DMX_TS_FILTERING | DMX_SECTION_FILTERING | | ||
242 | DMX_MEMORY_BASED_FILTERING; | ||
243 | dvb->demux.priv = dev; | ||
244 | dvb->demux.filternum = 256; | ||
245 | dvb->demux.feednum = 256; | ||
246 | dvb->demux.start_feed = au0828_dvb_start_feed; | ||
247 | dvb->demux.stop_feed = au0828_dvb_stop_feed; | ||
248 | result = dvb_dmx_init(&dvb->demux); | ||
249 | if (result < 0) { | ||
250 | printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", | ||
251 | DRIVER_NAME, result); | ||
252 | goto fail_dmx; | ||
253 | } | ||
254 | |||
255 | dvb->dmxdev.filternum = 256; | ||
256 | dvb->dmxdev.demux = &dvb->demux.dmx; | ||
257 | dvb->dmxdev.capabilities = 0; | ||
258 | result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); | ||
259 | if (result < 0) { | ||
260 | printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", | ||
261 | DRIVER_NAME, result); | ||
262 | goto fail_dmxdev; | ||
263 | } | ||
264 | |||
265 | dvb->fe_hw.source = DMX_FRONTEND_0; | ||
266 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
267 | if (result < 0) { | ||
268 | printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", | ||
269 | DRIVER_NAME, result); | ||
270 | goto fail_fe_hw; | ||
271 | } | ||
272 | |||
273 | dvb->fe_mem.source = DMX_MEMORY_FE; | ||
274 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
275 | if (result < 0) { | ||
276 | printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", | ||
277 | DRIVER_NAME, result); | ||
278 | goto fail_fe_mem; | ||
279 | } | ||
280 | |||
281 | result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
282 | if (result < 0) { | ||
283 | printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", | ||
284 | DRIVER_NAME, result); | ||
285 | goto fail_fe_conn; | ||
286 | } | ||
287 | |||
288 | /* register network adapter */ | ||
289 | dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); | ||
290 | return 0; | ||
291 | |||
292 | fail_fe_conn: | ||
293 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
294 | fail_fe_mem: | ||
295 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
296 | fail_fe_hw: | ||
297 | dvb_dmxdev_release(&dvb->dmxdev); | ||
298 | fail_dmxdev: | ||
299 | dvb_dmx_release(&dvb->demux); | ||
300 | fail_dmx: | ||
301 | dvb_unregister_frontend(dvb->frontend); | ||
302 | fail_frontend: | ||
303 | dvb_frontend_detach(dvb->frontend); | ||
304 | dvb_unregister_adapter(&dvb->adapter); | ||
305 | fail_adapter: | ||
306 | return result; | ||
307 | } | ||
308 | |||
309 | void au0828_dvb_unregister(struct au0828_dev *dev) | ||
310 | { | ||
311 | struct au0828_dvb *dvb = &dev->dvb; | ||
312 | |||
313 | dvb_net_release(&dvb->net); | ||
314 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
315 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
316 | dvb_dmxdev_release(&dvb->dmxdev); | ||
317 | dvb_dmx_release(&dvb->demux); | ||
318 | dvb_unregister_frontend(dvb->frontend); | ||
319 | dvb_frontend_detach(dvb->frontend); | ||
320 | dvb_unregister_adapter(&dvb->adapter); | ||
321 | } | ||
322 | |||
323 | /* All the DVB attach calls go here, this function get's modified | ||
324 | * for each new card. No other function in this file needs | ||
325 | * to change. | ||
326 | */ | ||
327 | int au0828_dvb_register(struct au0828_dev *dev) | ||
328 | { | ||
329 | struct au0828_dvb *dvb = &dev->dvb; | ||
330 | int ret; | ||
331 | |||
332 | /* init frontend */ | ||
333 | switch (dev->board) { | ||
334 | case AU0828_BOARD_HAUPPAUGE_HVR850: | ||
335 | case AU0828_BOARD_HAUPPAUGE_HVR950Q: | ||
336 | case AU0828_BOARD_DVICO_FUSIONHDTV7: | ||
337 | dvb->frontend = dvb_attach(au8522_attach, | ||
338 | &hauppauge_hvr950q_config, | ||
339 | &dev->i2c_adap); | ||
340 | if (dvb->frontend != NULL) { | ||
341 | hauppauge_hvr950q_tunerconfig.priv = dev; | ||
342 | dvb_attach(xc5000_attach, dvb->frontend, | ||
343 | &dev->i2c_adap, | ||
344 | &hauppauge_hvr950q_tunerconfig); | ||
345 | } | ||
346 | break; | ||
347 | default: | ||
348 | printk("The frontend of your DVB/ATSC card isn't supported yet\n"); | ||
349 | break; | ||
350 | } | ||
351 | if (NULL == dvb->frontend) { | ||
352 | printk("Frontend initialization failed\n"); | ||
353 | return -1; | ||
354 | } | ||
355 | |||
356 | /* Put the analog decoder in standby to keep it quiet */ | ||
357 | au0828_call_i2c_clients(dev, TUNER_SET_STANDBY, NULL); | ||
358 | |||
359 | if (dvb->frontend->ops.analog_ops.standby) | ||
360 | dvb->frontend->ops.analog_ops.standby(dvb->frontend); | ||
361 | |||
362 | /* register everything */ | ||
363 | ret = dvb_register(dev); | ||
364 | if (ret < 0) { | ||
365 | if (dvb->frontend->ops.release) | ||
366 | dvb->frontend->ops.release(dvb->frontend); | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | return 0; | ||
371 | } | ||