diff options
-rw-r--r-- | drivers/media/video/em28xx/em28xx-dvb.c | 349 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 5 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 6 |
3 files changed, 302 insertions, 58 deletions
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 65e0ab65fbe1..fd8f44cb6cbc 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c | |||
@@ -6,7 +6,9 @@ | |||
6 | (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> | 6 | (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> |
7 | - Fixes for the driver to properly work with HVR-950 | 7 | - Fixes for the driver to properly work with HVR-950 |
8 | 8 | ||
9 | Based on cx88-dvb and saa7134-dvb originally written by: | 9 | (c) 2008 Aidan Thornton <makosoft@googlemail.com> |
10 | |||
11 | Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: | ||
10 | (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au> | 12 | (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au> |
11 | (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | 13 | (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] |
12 | 14 | ||
@@ -37,28 +39,157 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |||
37 | 39 | ||
38 | #define dprintk(level, fmt, arg...) do { \ | 40 | #define dprintk(level, fmt, arg...) do { \ |
39 | if (debug >= level) \ | 41 | if (debug >= level) \ |
40 | printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg) \ | 42 | printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ |
41 | } while (0) | 43 | } while (0) |
42 | 44 | ||
43 | static int | 45 | #define EM28XX_DVB_NUM_BUFS 5 |
44 | buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) | 46 | #define EM28XX_DVB_MAX_PACKETSIZE 564 |
47 | #define EM28XX_DVB_MAX_PACKETS 64 | ||
48 | |||
49 | struct em28xx_dvb { | ||
50 | struct dvb_frontend *frontend; | ||
51 | |||
52 | /* feed count management */ | ||
53 | struct mutex lock; | ||
54 | int nfeeds; | ||
55 | |||
56 | /* general boilerplate stuff */ | ||
57 | struct dvb_adapter adapter; | ||
58 | struct dvb_demux demux; | ||
59 | struct dmxdev dmxdev; | ||
60 | struct dmx_frontend fe_hw; | ||
61 | struct dmx_frontend fe_mem; | ||
62 | struct dvb_net net; | ||
63 | }; | ||
64 | |||
65 | |||
66 | static inline void print_err_status(struct em28xx *dev, | ||
67 | int packet, int status) | ||
45 | { | 68 | { |
46 | struct em28xx_fh *fh = vq->priv_data; | 69 | char *errmsg = "Unknown"; |
47 | struct em28xx *dev = fh->dev; | ||
48 | 70 | ||
49 | /* FIXME: The better would be to allocate a smaller buffer */ | 71 | switch (status) { |
50 | *size = 16 * fh->dev->width * fh->dev->height >> 3; | 72 | case -ENOENT: |
51 | if (0 == *count) | 73 | errmsg = "unlinked synchronuously"; |
52 | *count = EM28XX_DEF_BUF; | 74 | break; |
75 | case -ECONNRESET: | ||
76 | errmsg = "unlinked asynchronuously"; | ||
77 | break; | ||
78 | case -ENOSR: | ||
79 | errmsg = "Buffer error (overrun)"; | ||
80 | break; | ||
81 | case -EPIPE: | ||
82 | errmsg = "Stalled (device not responding)"; | ||
83 | break; | ||
84 | case -EOVERFLOW: | ||
85 | errmsg = "Babble (bad cable?)"; | ||
86 | break; | ||
87 | case -EPROTO: | ||
88 | errmsg = "Bit-stuff error (bad cable?)"; | ||
89 | break; | ||
90 | case -EILSEQ: | ||
91 | errmsg = "CRC/Timeout (could be anything)"; | ||
92 | break; | ||
93 | case -ETIME: | ||
94 | errmsg = "Device does not respond"; | ||
95 | break; | ||
96 | } | ||
97 | if (packet < 0) { | ||
98 | dprintk(1, "URB status %d [%s].\n", status, errmsg); | ||
99 | } else { | ||
100 | dprintk(1, "URB packet %d, status %d [%s].\n", packet, status, errmsg); | ||
101 | } | ||
102 | } | ||
53 | 103 | ||
54 | if (*count < EM28XX_MIN_BUF) | 104 | static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) |
55 | *count = EM28XX_MIN_BUF; | 105 | { |
106 | int i; | ||
56 | 107 | ||
57 | dev->mode = EM28XX_DIGITAL_MODE; | 108 | if (!dev) |
109 | return 0; | ||
58 | 110 | ||
111 | if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) | ||
112 | return 0; | ||
113 | |||
114 | if (urb->status < 0) { | ||
115 | print_err_status(dev, -1, urb->status); | ||
116 | if (urb->status == -ENOENT) | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | for (i = 0; i < urb->number_of_packets; i++) { | ||
121 | int status = urb->iso_frame_desc[i].status; | ||
122 | |||
123 | if (status < 0) { | ||
124 | print_err_status(dev, i, status); | ||
125 | if (urb->iso_frame_desc[i].status != -EPROTO) | ||
126 | continue; | ||
127 | } | ||
128 | |||
129 | dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer + | ||
130 | urb->iso_frame_desc[i].offset, | ||
131 | urb->iso_frame_desc[i].actual_length); | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int start_streaming(struct em28xx_dvb* dvb) { | ||
138 | struct em28xx *dev = dvb->adapter.priv; | ||
139 | |||
140 | usb_set_interface(dev->udev, 0, 1); | ||
141 | dev->em28xx_write_regs_req(dev,0x00,0x48,"\x00",1); | ||
142 | |||
143 | return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, | ||
144 | EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE, | ||
145 | dvb_isoc_copy, EM28XX_DIGITAL_CAPTURE); | ||
146 | } | ||
147 | |||
148 | static int stop_streaming(struct em28xx_dvb* dvb) { | ||
149 | struct em28xx *dev = dvb->adapter.priv; | ||
150 | |||
151 | em28xx_uninit_isoc(dev); | ||
59 | return 0; | 152 | return 0; |
60 | } | 153 | } |
61 | 154 | ||
155 | static int start_feed(struct dvb_demux_feed *feed) | ||
156 | { | ||
157 | struct dvb_demux *demux = feed->demux; | ||
158 | struct em28xx_dvb *dvb = demux->priv; | ||
159 | int rc, ret; | ||
160 | |||
161 | if (!demux->dmx.frontend) | ||
162 | return -EINVAL; | ||
163 | |||
164 | mutex_lock(&dvb->lock); | ||
165 | dvb->nfeeds++; | ||
166 | rc = dvb->nfeeds; | ||
167 | |||
168 | if (dvb->nfeeds == 1) { | ||
169 | ret = start_streaming(dvb); | ||
170 | if(ret < 0) rc = ret; | ||
171 | } | ||
172 | |||
173 | mutex_unlock(&dvb->lock); | ||
174 | return rc; | ||
175 | } | ||
176 | |||
177 | static int stop_feed(struct dvb_demux_feed *feed) | ||
178 | { | ||
179 | struct dvb_demux *demux = feed->demux; | ||
180 | struct em28xx_dvb *dvb = demux->priv; | ||
181 | int err = 0; | ||
182 | |||
183 | mutex_lock(&dvb->lock); | ||
184 | dvb->nfeeds--; | ||
185 | if (0 == dvb->nfeeds) { | ||
186 | err = stop_streaming(dvb); | ||
187 | } | ||
188 | mutex_unlock(&dvb->lock); | ||
189 | return err; | ||
190 | } | ||
191 | |||
192 | |||
62 | /* ------------------------------------------------------------------ */ | 193 | /* ------------------------------------------------------------------ */ |
63 | 194 | ||
64 | static struct lgdt330x_config em2880_lgdt3303_dev = { | 195 | static struct lgdt330x_config em2880_lgdt3303_dev = { |
@@ -89,20 +220,20 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) | |||
89 | 220 | ||
90 | em28xx_setup_xc3028(dev, &ctl); | 221 | em28xx_setup_xc3028(dev, &ctl); |
91 | 222 | ||
92 | if (!dev->dvb.frontend) { | 223 | if (!dev->dvb->frontend) { |
93 | printk(KERN_ERR "%s/2: dvb frontend not attached. " | 224 | printk(KERN_ERR "%s/2: dvb frontend not attached. " |
94 | "Can't attach xc3028\n", | 225 | "Can't attach xc3028\n", |
95 | dev->name); | 226 | dev->name); |
96 | return -EINVAL; | 227 | return -EINVAL; |
97 | } | 228 | } |
98 | 229 | ||
99 | fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg); | 230 | fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg); |
100 | if (!fe) { | 231 | if (!fe) { |
101 | printk(KERN_ERR "%s/2: xc3028 attach failed\n", | 232 | printk(KERN_ERR "%s/2: xc3028 attach failed\n", |
102 | dev->name); | 233 | dev->name); |
103 | dvb_frontend_detach(dev->dvb.frontend); | 234 | dvb_frontend_detach(dev->dvb->frontend); |
104 | dvb_unregister_frontend(dev->dvb.frontend); | 235 | dvb_unregister_frontend(dev->dvb->frontend); |
105 | dev->dvb.frontend = NULL; | 236 | dev->dvb->frontend = NULL; |
106 | return -EINVAL; | 237 | return -EINVAL; |
107 | } | 238 | } |
108 | 239 | ||
@@ -111,23 +242,129 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) | |||
111 | return 0; | 242 | return 0; |
112 | } | 243 | } |
113 | 244 | ||
114 | static int dvb_init(struct em28xx *dev) | 245 | /* ------------------------------------------------------------------ */ |
246 | |||
247 | int register_dvb(struct em28xx_dvb *dvb, | ||
248 | struct module *module, | ||
249 | struct em28xx *dev, | ||
250 | struct device *device) | ||
115 | { | 251 | { |
116 | /* init struct videobuf_dvb */ | 252 | int result; |
117 | dev->dvb.name = dev->name; | ||
118 | 253 | ||
119 | dev->qops->buf_setup = buffer_setup; | 254 | mutex_init(&dvb->lock); |
120 | 255 | ||
121 | /* FIXME: Do we need more initialization here? */ | 256 | /* register adapter */ |
122 | memset(&dev->dvb_fh, 0, sizeof (dev->dvb_fh)); | 257 | result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, |
123 | dev->dvb_fh.dev = dev; | 258 | adapter_nr); |
124 | dev->dvb_fh.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 259 | if (result < 0) { |
260 | printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", | ||
261 | dev->name, result); | ||
262 | goto fail_adapter; | ||
263 | } | ||
264 | dvb->adapter.priv = dev; | ||
265 | |||
266 | /* register frontend */ | ||
267 | result = dvb_register_frontend(&dvb->adapter, dvb->frontend); | ||
268 | if (result < 0) { | ||
269 | printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", | ||
270 | dev->name, result); | ||
271 | goto fail_frontend; | ||
272 | } | ||
273 | |||
274 | /* register demux stuff */ | ||
275 | dvb->demux.dmx.capabilities = | ||
276 | DMX_TS_FILTERING | DMX_SECTION_FILTERING | | ||
277 | DMX_MEMORY_BASED_FILTERING; | ||
278 | dvb->demux.priv = dvb; | ||
279 | dvb->demux.filternum = 256; | ||
280 | dvb->demux.feednum = 256; | ||
281 | dvb->demux.start_feed = start_feed; | ||
282 | dvb->demux.stop_feed = stop_feed; | ||
283 | result = dvb_dmx_init(&dvb->demux); | ||
284 | if (result < 0) { | ||
285 | printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", | ||
286 | dev->name, result); | ||
287 | goto fail_dmx; | ||
288 | } | ||
289 | |||
290 | dvb->dmxdev.filternum = 256; | ||
291 | dvb->dmxdev.demux = &dvb->demux.dmx; | ||
292 | dvb->dmxdev.capabilities = 0; | ||
293 | result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); | ||
294 | if (result < 0) { | ||
295 | printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", | ||
296 | dev->name, result); | ||
297 | goto fail_dmxdev; | ||
298 | } | ||
125 | 299 | ||
126 | videobuf_queue_vmalloc_init(&dev->dvb.dvbq, dev->qops, | 300 | dvb->fe_hw.source = DMX_FRONTEND_0; |
127 | &dev->udev->dev, &dev->slock, | 301 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); |
128 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | 302 | if (result < 0) { |
129 | V4L2_FIELD_ALTERNATE, | 303 | printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", |
130 | sizeof(struct em28xx_buffer), &dev->dvb_fh); | 304 | dev->name, result); |
305 | goto fail_fe_hw; | ||
306 | } | ||
307 | |||
308 | dvb->fe_mem.source = DMX_MEMORY_FE; | ||
309 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
310 | if (result < 0) { | ||
311 | printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", | ||
312 | dev->name, result); | ||
313 | goto fail_fe_mem; | ||
314 | } | ||
315 | |||
316 | result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
317 | if (result < 0) { | ||
318 | printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", | ||
319 | dev->name, result); | ||
320 | goto fail_fe_conn; | ||
321 | } | ||
322 | |||
323 | /* register network adapter */ | ||
324 | dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); | ||
325 | return 0; | ||
326 | |||
327 | fail_fe_conn: | ||
328 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
329 | fail_fe_mem: | ||
330 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
331 | fail_fe_hw: | ||
332 | dvb_dmxdev_release(&dvb->dmxdev); | ||
333 | fail_dmxdev: | ||
334 | dvb_dmx_release(&dvb->demux); | ||
335 | fail_dmx: | ||
336 | dvb_unregister_frontend(dvb->frontend); | ||
337 | fail_frontend: | ||
338 | dvb_frontend_detach(dvb->frontend); | ||
339 | dvb_unregister_adapter(&dvb->adapter); | ||
340 | fail_adapter: | ||
341 | return result; | ||
342 | } | ||
343 | |||
344 | static void unregister_dvb(struct em28xx_dvb *dvb) | ||
345 | { | ||
346 | dvb_net_release(&dvb->net); | ||
347 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
348 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
349 | dvb_dmxdev_release(&dvb->dmxdev); | ||
350 | dvb_dmx_release(&dvb->demux); | ||
351 | dvb_unregister_frontend(dvb->frontend); | ||
352 | dvb_frontend_detach(dvb->frontend); | ||
353 | dvb_unregister_adapter(&dvb->adapter); | ||
354 | } | ||
355 | |||
356 | |||
357 | static int dvb_init(struct em28xx *dev) | ||
358 | { | ||
359 | int result = 0; | ||
360 | struct em28xx_dvb *dvb; | ||
361 | |||
362 | dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); | ||
363 | if(dvb == NULL) { | ||
364 | printk("em28xx_dvb: memory allocation failed\n"); | ||
365 | return -ENOMEM; | ||
366 | } | ||
367 | dev->dvb = dvb; | ||
131 | 368 | ||
132 | /* init frontend */ | 369 | /* init frontend */ |
133 | switch (dev->model) { | 370 | switch (dev->model) { |
@@ -136,21 +373,25 @@ static int dvb_init(struct em28xx *dev) | |||
136 | dev->mode = EM28XX_DIGITAL_MODE; | 373 | dev->mode = EM28XX_DIGITAL_MODE; |
137 | em28xx_tuner_callback(dev, XC2028_TUNER_RESET, 0); | 374 | em28xx_tuner_callback(dev, XC2028_TUNER_RESET, 0); |
138 | 375 | ||
139 | dev->dvb.frontend = dvb_attach(lgdt330x_attach, | 376 | dvb->frontend = dvb_attach(lgdt330x_attach, |
140 | &em2880_lgdt3303_dev, | 377 | &em2880_lgdt3303_dev, |
141 | &dev->i2c_adap); | 378 | &dev->i2c_adap); |
142 | if (attach_xc3028(0x61, dev) < 0) | 379 | if (attach_xc3028(0x61, dev) < 0) { |
143 | return -EINVAL; | 380 | result = -EINVAL; |
381 | goto out_free; | ||
382 | } | ||
144 | break; | 383 | break; |
145 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: | 384 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: |
146 | /* Enable zl10353 */ | 385 | /* Enable zl10353 */ |
147 | dev->mode = EM28XX_DIGITAL_MODE; | 386 | dev->mode = EM28XX_DIGITAL_MODE; |
148 | em28xx_tuner_callback(dev, XC2028_TUNER_RESET, 0); | 387 | em28xx_tuner_callback(dev, XC2028_TUNER_RESET, 0); |
149 | dev->dvb.frontend = dvb_attach(zl10353_attach, | 388 | dvb->frontend = dvb_attach(zl10353_attach, |
150 | &em28xx_zl10353_with_xc3028, | 389 | &em28xx_zl10353_with_xc3028, |
151 | &dev->i2c_adap); | 390 | &dev->i2c_adap); |
152 | if (attach_xc3028(0x61, dev) < 0) | 391 | if (attach_xc3028(0x61, dev) < 0) { |
153 | return -EINVAL; | 392 | result = -EINVAL; |
393 | goto out_free; | ||
394 | } | ||
154 | break; | 395 | break; |
155 | default: | 396 | default: |
156 | printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" | 397 | printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" |
@@ -158,23 +399,35 @@ static int dvb_init(struct em28xx *dev) | |||
158 | dev->name); | 399 | dev->name); |
159 | break; | 400 | break; |
160 | } | 401 | } |
161 | if (NULL == dev->dvb.frontend) { | 402 | if (NULL == dvb->frontend) { |
162 | printk(KERN_ERR | 403 | printk(KERN_ERR |
163 | "%s/2: frontend initialization failed\n", | 404 | "%s/2: frontend initialization failed\n", |
164 | dev->name); | 405 | dev->name); |
165 | return -EINVAL; | 406 | result = -EINVAL; |
407 | goto out_free; | ||
166 | } | 408 | } |
167 | 409 | ||
168 | /* register everything */ | 410 | /* register everything */ |
169 | return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, | 411 | result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); |
170 | &dev->udev->dev, | 412 | |
171 | adapter_nr); | 413 | if (result < 0) { |
414 | goto out_free; | ||
415 | } | ||
416 | |||
417 | return 0; | ||
418 | |||
419 | out_free: | ||
420 | kfree(dvb); | ||
421 | dev->dvb = NULL; | ||
422 | return result; | ||
172 | } | 423 | } |
173 | 424 | ||
174 | static int dvb_fini(struct em28xx *dev) | 425 | static int dvb_fini(struct em28xx *dev) |
175 | { | 426 | { |
176 | if (dev->dvb.frontend) | 427 | if (dev->dvb) { |
177 | videobuf_dvb_unregister(&dev->dvb); | 428 | unregister_dvb(dev->dvb); |
429 | dev->dvb = NULL; | ||
430 | } | ||
178 | 431 | ||
179 | return 0; | 432 | return 0; |
180 | } | 433 | } |
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 1a0b09714af5..ffbc91f2ecbd 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -2190,11 +2190,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
2190 | /* save our data pointer in this interface device */ | 2190 | /* save our data pointer in this interface device */ |
2191 | usb_set_intfdata(interface, dev); | 2191 | usb_set_intfdata(interface, dev); |
2192 | 2192 | ||
2193 | #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) | ||
2194 | dev->qops = kmalloc(sizeof(em28xx_video_qops), GFP_KERNEL); | ||
2195 | memcpy(dev->qops, &em28xx_video_qops, sizeof(em28xx_video_qops)); | ||
2196 | #endif | ||
2197 | |||
2198 | request_modules(dev); | 2193 | request_modules(dev); |
2199 | 2194 | ||
2200 | return 0; | 2195 | return 0; |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 151bc57bd08b..e5fd2dc77355 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -422,11 +422,7 @@ struct em28xx { | |||
422 | 422 | ||
423 | enum em28xx_mode mode; | 423 | enum em28xx_mode mode; |
424 | 424 | ||
425 | #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) | 425 | struct em28xx_dvb *dvb; |
426 | struct videobuf_dvb dvb; | ||
427 | struct videobuf_queue_ops *qops; | ||
428 | struct em28xx_fh dvb_fh; | ||
429 | #endif | ||
430 | }; | 426 | }; |
431 | 427 | ||
432 | struct em28xx_ops { | 428 | struct em28xx_ops { |