diff options
Diffstat (limited to 'drivers/media/video/cx88/cx88-video.c')
-rw-r--r-- | drivers/media/video/cx88/cx88-video.c | 2194 |
1 files changed, 2194 insertions, 0 deletions
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c new file mode 100644 index 00000000000..60d28fdd779 --- /dev/null +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -0,0 +1,2194 @@ | |||
1 | /* | ||
2 | * | ||
3 | * device driver for Conexant 2388x based TV cards | ||
4 | * video4linux video interface | ||
5 | * | ||
6 | * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
7 | * | ||
8 | * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> | ||
9 | * - Multituner support | ||
10 | * - video_ioctl2 conversion | ||
11 | * - PAL/M fixes | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/init.h> | ||
29 | #include <linux/list.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/kmod.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/kthread.h> | ||
38 | #include <asm/div64.h> | ||
39 | |||
40 | #include "cx88.h" | ||
41 | #include <media/v4l2-common.h> | ||
42 | #include <media/v4l2-ioctl.h> | ||
43 | #include <media/wm8775.h> | ||
44 | |||
45 | MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); | ||
46 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | MODULE_VERSION(CX88_VERSION); | ||
49 | |||
50 | /* ------------------------------------------------------------------ */ | ||
51 | |||
52 | static unsigned int video_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | ||
53 | static unsigned int vbi_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | ||
54 | static unsigned int radio_nr[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | ||
55 | |||
56 | module_param_array(video_nr, int, NULL, 0444); | ||
57 | module_param_array(vbi_nr, int, NULL, 0444); | ||
58 | module_param_array(radio_nr, int, NULL, 0444); | ||
59 | |||
60 | MODULE_PARM_DESC(video_nr,"video device numbers"); | ||
61 | MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); | ||
62 | MODULE_PARM_DESC(radio_nr,"radio device numbers"); | ||
63 | |||
64 | static unsigned int video_debug; | ||
65 | module_param(video_debug,int,0644); | ||
66 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); | ||
67 | |||
68 | static unsigned int irq_debug; | ||
69 | module_param(irq_debug,int,0644); | ||
70 | MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); | ||
71 | |||
72 | static unsigned int vid_limit = 16; | ||
73 | module_param(vid_limit,int,0644); | ||
74 | MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); | ||
75 | |||
76 | #define dprintk(level,fmt, arg...) if (video_debug >= level) \ | ||
77 | printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) | ||
78 | |||
79 | /* ------------------------------------------------------------------- */ | ||
80 | /* static data */ | ||
81 | |||
82 | static const struct cx8800_fmt formats[] = { | ||
83 | { | ||
84 | .name = "8 bpp, gray", | ||
85 | .fourcc = V4L2_PIX_FMT_GREY, | ||
86 | .cxformat = ColorFormatY8, | ||
87 | .depth = 8, | ||
88 | .flags = FORMAT_FLAGS_PACKED, | ||
89 | },{ | ||
90 | .name = "15 bpp RGB, le", | ||
91 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
92 | .cxformat = ColorFormatRGB15, | ||
93 | .depth = 16, | ||
94 | .flags = FORMAT_FLAGS_PACKED, | ||
95 | },{ | ||
96 | .name = "15 bpp RGB, be", | ||
97 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
98 | .cxformat = ColorFormatRGB15 | ColorFormatBSWAP, | ||
99 | .depth = 16, | ||
100 | .flags = FORMAT_FLAGS_PACKED, | ||
101 | },{ | ||
102 | .name = "16 bpp RGB, le", | ||
103 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
104 | .cxformat = ColorFormatRGB16, | ||
105 | .depth = 16, | ||
106 | .flags = FORMAT_FLAGS_PACKED, | ||
107 | },{ | ||
108 | .name = "16 bpp RGB, be", | ||
109 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
110 | .cxformat = ColorFormatRGB16 | ColorFormatBSWAP, | ||
111 | .depth = 16, | ||
112 | .flags = FORMAT_FLAGS_PACKED, | ||
113 | },{ | ||
114 | .name = "24 bpp RGB, le", | ||
115 | .fourcc = V4L2_PIX_FMT_BGR24, | ||
116 | .cxformat = ColorFormatRGB24, | ||
117 | .depth = 24, | ||
118 | .flags = FORMAT_FLAGS_PACKED, | ||
119 | },{ | ||
120 | .name = "32 bpp RGB, le", | ||
121 | .fourcc = V4L2_PIX_FMT_BGR32, | ||
122 | .cxformat = ColorFormatRGB32, | ||
123 | .depth = 32, | ||
124 | .flags = FORMAT_FLAGS_PACKED, | ||
125 | },{ | ||
126 | .name = "32 bpp RGB, be", | ||
127 | .fourcc = V4L2_PIX_FMT_RGB32, | ||
128 | .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, | ||
129 | .depth = 32, | ||
130 | .flags = FORMAT_FLAGS_PACKED, | ||
131 | },{ | ||
132 | .name = "4:2:2, packed, YUYV", | ||
133 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
134 | .cxformat = ColorFormatYUY2, | ||
135 | .depth = 16, | ||
136 | .flags = FORMAT_FLAGS_PACKED, | ||
137 | },{ | ||
138 | .name = "4:2:2, packed, UYVY", | ||
139 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
140 | .cxformat = ColorFormatYUY2 | ColorFormatBSWAP, | ||
141 | .depth = 16, | ||
142 | .flags = FORMAT_FLAGS_PACKED, | ||
143 | }, | ||
144 | }; | ||
145 | |||
146 | static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) | ||
147 | { | ||
148 | unsigned int i; | ||
149 | |||
150 | for (i = 0; i < ARRAY_SIZE(formats); i++) | ||
151 | if (formats[i].fourcc == fourcc) | ||
152 | return formats+i; | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | /* ------------------------------------------------------------------- */ | ||
157 | |||
158 | static const struct v4l2_queryctrl no_ctl = { | ||
159 | .name = "42", | ||
160 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
161 | }; | ||
162 | |||
163 | static const struct cx88_ctrl cx8800_ctls[] = { | ||
164 | /* --- video --- */ | ||
165 | { | ||
166 | .v = { | ||
167 | .id = V4L2_CID_BRIGHTNESS, | ||
168 | .name = "Brightness", | ||
169 | .minimum = 0x00, | ||
170 | .maximum = 0xff, | ||
171 | .step = 1, | ||
172 | .default_value = 0x7f, | ||
173 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
174 | }, | ||
175 | .off = 128, | ||
176 | .reg = MO_CONTR_BRIGHT, | ||
177 | .mask = 0x00ff, | ||
178 | .shift = 0, | ||
179 | },{ | ||
180 | .v = { | ||
181 | .id = V4L2_CID_CONTRAST, | ||
182 | .name = "Contrast", | ||
183 | .minimum = 0, | ||
184 | .maximum = 0xff, | ||
185 | .step = 1, | ||
186 | .default_value = 0x3f, | ||
187 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
188 | }, | ||
189 | .off = 0, | ||
190 | .reg = MO_CONTR_BRIGHT, | ||
191 | .mask = 0xff00, | ||
192 | .shift = 8, | ||
193 | },{ | ||
194 | .v = { | ||
195 | .id = V4L2_CID_HUE, | ||
196 | .name = "Hue", | ||
197 | .minimum = 0, | ||
198 | .maximum = 0xff, | ||
199 | .step = 1, | ||
200 | .default_value = 0x7f, | ||
201 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
202 | }, | ||
203 | .off = 128, | ||
204 | .reg = MO_HUE, | ||
205 | .mask = 0x00ff, | ||
206 | .shift = 0, | ||
207 | },{ | ||
208 | /* strictly, this only describes only U saturation. | ||
209 | * V saturation is handled specially through code. | ||
210 | */ | ||
211 | .v = { | ||
212 | .id = V4L2_CID_SATURATION, | ||
213 | .name = "Saturation", | ||
214 | .minimum = 0, | ||
215 | .maximum = 0xff, | ||
216 | .step = 1, | ||
217 | .default_value = 0x7f, | ||
218 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
219 | }, | ||
220 | .off = 0, | ||
221 | .reg = MO_UV_SATURATION, | ||
222 | .mask = 0x00ff, | ||
223 | .shift = 0, | ||
224 | }, { | ||
225 | .v = { | ||
226 | .id = V4L2_CID_SHARPNESS, | ||
227 | .name = "Sharpness", | ||
228 | .minimum = 0, | ||
229 | .maximum = 4, | ||
230 | .step = 1, | ||
231 | .default_value = 0x0, | ||
232 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
233 | }, | ||
234 | .off = 0, | ||
235 | /* NOTE: the value is converted and written to both even | ||
236 | and odd registers in the code */ | ||
237 | .reg = MO_FILTER_ODD, | ||
238 | .mask = 7 << 7, | ||
239 | .shift = 7, | ||
240 | }, { | ||
241 | .v = { | ||
242 | .id = V4L2_CID_CHROMA_AGC, | ||
243 | .name = "Chroma AGC", | ||
244 | .minimum = 0, | ||
245 | .maximum = 1, | ||
246 | .default_value = 0x1, | ||
247 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
248 | }, | ||
249 | .reg = MO_INPUT_FORMAT, | ||
250 | .mask = 1 << 10, | ||
251 | .shift = 10, | ||
252 | }, { | ||
253 | .v = { | ||
254 | .id = V4L2_CID_COLOR_KILLER, | ||
255 | .name = "Color killer", | ||
256 | .minimum = 0, | ||
257 | .maximum = 1, | ||
258 | .default_value = 0x1, | ||
259 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
260 | }, | ||
261 | .reg = MO_INPUT_FORMAT, | ||
262 | .mask = 1 << 9, | ||
263 | .shift = 9, | ||
264 | }, { | ||
265 | .v = { | ||
266 | .id = V4L2_CID_BAND_STOP_FILTER, | ||
267 | .name = "Notch filter", | ||
268 | .minimum = 0, | ||
269 | .maximum = 3, | ||
270 | .step = 1, | ||
271 | .default_value = 0x0, | ||
272 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
273 | }, | ||
274 | .off = 0, | ||
275 | .reg = MO_HTOTAL, | ||
276 | .mask = 3 << 11, | ||
277 | .shift = 11, | ||
278 | }, { | ||
279 | /* --- audio --- */ | ||
280 | .v = { | ||
281 | .id = V4L2_CID_AUDIO_MUTE, | ||
282 | .name = "Mute", | ||
283 | .minimum = 0, | ||
284 | .maximum = 1, | ||
285 | .default_value = 1, | ||
286 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
287 | }, | ||
288 | .reg = AUD_VOL_CTL, | ||
289 | .sreg = SHADOW_AUD_VOL_CTL, | ||
290 | .mask = (1 << 6), | ||
291 | .shift = 6, | ||
292 | },{ | ||
293 | .v = { | ||
294 | .id = V4L2_CID_AUDIO_VOLUME, | ||
295 | .name = "Volume", | ||
296 | .minimum = 0, | ||
297 | .maximum = 0x3f, | ||
298 | .step = 1, | ||
299 | .default_value = 0x3f, | ||
300 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
301 | }, | ||
302 | .reg = AUD_VOL_CTL, | ||
303 | .sreg = SHADOW_AUD_VOL_CTL, | ||
304 | .mask = 0x3f, | ||
305 | .shift = 0, | ||
306 | },{ | ||
307 | .v = { | ||
308 | .id = V4L2_CID_AUDIO_BALANCE, | ||
309 | .name = "Balance", | ||
310 | .minimum = 0, | ||
311 | .maximum = 0x7f, | ||
312 | .step = 1, | ||
313 | .default_value = 0x40, | ||
314 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
315 | }, | ||
316 | .reg = AUD_BAL_CTL, | ||
317 | .sreg = SHADOW_AUD_BAL_CTL, | ||
318 | .mask = 0x7f, | ||
319 | .shift = 0, | ||
320 | } | ||
321 | }; | ||
322 | enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) }; | ||
323 | |||
324 | /* Must be sorted from low to high control ID! */ | ||
325 | const u32 cx88_user_ctrls[] = { | ||
326 | V4L2_CID_USER_CLASS, | ||
327 | V4L2_CID_BRIGHTNESS, | ||
328 | V4L2_CID_CONTRAST, | ||
329 | V4L2_CID_SATURATION, | ||
330 | V4L2_CID_HUE, | ||
331 | V4L2_CID_AUDIO_VOLUME, | ||
332 | V4L2_CID_AUDIO_BALANCE, | ||
333 | V4L2_CID_AUDIO_MUTE, | ||
334 | V4L2_CID_SHARPNESS, | ||
335 | V4L2_CID_CHROMA_AGC, | ||
336 | V4L2_CID_COLOR_KILLER, | ||
337 | V4L2_CID_BAND_STOP_FILTER, | ||
338 | 0 | ||
339 | }; | ||
340 | EXPORT_SYMBOL(cx88_user_ctrls); | ||
341 | |||
342 | static const u32 * const ctrl_classes[] = { | ||
343 | cx88_user_ctrls, | ||
344 | NULL | ||
345 | }; | ||
346 | |||
347 | int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl) | ||
348 | { | ||
349 | int i; | ||
350 | |||
351 | if (qctrl->id < V4L2_CID_BASE || | ||
352 | qctrl->id >= V4L2_CID_LASTP1) | ||
353 | return -EINVAL; | ||
354 | for (i = 0; i < CX8800_CTLS; i++) | ||
355 | if (cx8800_ctls[i].v.id == qctrl->id) | ||
356 | break; | ||
357 | if (i == CX8800_CTLS) { | ||
358 | *qctrl = no_ctl; | ||
359 | return 0; | ||
360 | } | ||
361 | *qctrl = cx8800_ctls[i].v; | ||
362 | /* Report chroma AGC as inactive when SECAM is selected */ | ||
363 | if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC && | ||
364 | core->tvnorm & V4L2_STD_SECAM) | ||
365 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | EXPORT_SYMBOL(cx8800_ctrl_query); | ||
370 | |||
371 | /* ------------------------------------------------------------------- */ | ||
372 | /* resource management */ | ||
373 | |||
374 | static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit) | ||
375 | { | ||
376 | struct cx88_core *core = dev->core; | ||
377 | if (fh->resources & bit) | ||
378 | /* have it already allocated */ | ||
379 | return 1; | ||
380 | |||
381 | /* is it free? */ | ||
382 | mutex_lock(&core->lock); | ||
383 | if (dev->resources & bit) { | ||
384 | /* no, someone else uses it */ | ||
385 | mutex_unlock(&core->lock); | ||
386 | return 0; | ||
387 | } | ||
388 | /* it's free, grab it */ | ||
389 | fh->resources |= bit; | ||
390 | dev->resources |= bit; | ||
391 | dprintk(1,"res: get %d\n",bit); | ||
392 | mutex_unlock(&core->lock); | ||
393 | return 1; | ||
394 | } | ||
395 | |||
396 | static | ||
397 | int res_check(struct cx8800_fh *fh, unsigned int bit) | ||
398 | { | ||
399 | return (fh->resources & bit); | ||
400 | } | ||
401 | |||
402 | static | ||
403 | int res_locked(struct cx8800_dev *dev, unsigned int bit) | ||
404 | { | ||
405 | return (dev->resources & bit); | ||
406 | } | ||
407 | |||
408 | static | ||
409 | void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) | ||
410 | { | ||
411 | struct cx88_core *core = dev->core; | ||
412 | BUG_ON((fh->resources & bits) != bits); | ||
413 | |||
414 | mutex_lock(&core->lock); | ||
415 | fh->resources &= ~bits; | ||
416 | dev->resources &= ~bits; | ||
417 | dprintk(1,"res: put %d\n",bits); | ||
418 | mutex_unlock(&core->lock); | ||
419 | } | ||
420 | |||
421 | /* ------------------------------------------------------------------ */ | ||
422 | |||
423 | int cx88_video_mux(struct cx88_core *core, unsigned int input) | ||
424 | { | ||
425 | /* struct cx88_core *core = dev->core; */ | ||
426 | |||
427 | dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", | ||
428 | input, INPUT(input).vmux, | ||
429 | INPUT(input).gpio0,INPUT(input).gpio1, | ||
430 | INPUT(input).gpio2,INPUT(input).gpio3); | ||
431 | core->input = input; | ||
432 | cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); | ||
433 | cx_write(MO_GP3_IO, INPUT(input).gpio3); | ||
434 | cx_write(MO_GP0_IO, INPUT(input).gpio0); | ||
435 | cx_write(MO_GP1_IO, INPUT(input).gpio1); | ||
436 | cx_write(MO_GP2_IO, INPUT(input).gpio2); | ||
437 | |||
438 | switch (INPUT(input).type) { | ||
439 | case CX88_VMUX_SVIDEO: | ||
440 | cx_set(MO_AFECFG_IO, 0x00000001); | ||
441 | cx_set(MO_INPUT_FORMAT, 0x00010010); | ||
442 | cx_set(MO_FILTER_EVEN, 0x00002020); | ||
443 | cx_set(MO_FILTER_ODD, 0x00002020); | ||
444 | break; | ||
445 | default: | ||
446 | cx_clear(MO_AFECFG_IO, 0x00000001); | ||
447 | cx_clear(MO_INPUT_FORMAT, 0x00010010); | ||
448 | cx_clear(MO_FILTER_EVEN, 0x00002020); | ||
449 | cx_clear(MO_FILTER_ODD, 0x00002020); | ||
450 | break; | ||
451 | } | ||
452 | |||
453 | /* if there are audioroutes defined, we have an external | ||
454 | ADC to deal with audio */ | ||
455 | if (INPUT(input).audioroute) { | ||
456 | /* The wm8775 module has the "2" route hardwired into | ||
457 | the initialization. Some boards may use different | ||
458 | routes for different inputs. HVR-1300 surely does */ | ||
459 | if (core->board.audio_chip && | ||
460 | core->board.audio_chip == V4L2_IDENT_WM8775) { | ||
461 | call_all(core, audio, s_routing, | ||
462 | INPUT(input).audioroute, 0, 0); | ||
463 | } | ||
464 | /* cx2388's C-ADC is connected to the tuner only. | ||
465 | When used with S-Video, that ADC is busy dealing with | ||
466 | chroma, so an external must be used for baseband audio */ | ||
467 | if (INPUT(input).type != CX88_VMUX_TELEVISION && | ||
468 | INPUT(input).type != CX88_VMUX_CABLE) { | ||
469 | /* "I2S ADC mode" */ | ||
470 | core->tvaudio = WW_I2SADC; | ||
471 | cx88_set_tvaudio(core); | ||
472 | } else { | ||
473 | /* Normal mode */ | ||
474 | cx_write(AUD_I2SCNTL, 0x0); | ||
475 | cx_clear(AUD_CTL, EN_I2SIN_ENABLE); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | return 0; | ||
480 | } | ||
481 | EXPORT_SYMBOL(cx88_video_mux); | ||
482 | |||
483 | /* ------------------------------------------------------------------ */ | ||
484 | |||
485 | static int start_video_dma(struct cx8800_dev *dev, | ||
486 | struct cx88_dmaqueue *q, | ||
487 | struct cx88_buffer *buf) | ||
488 | { | ||
489 | struct cx88_core *core = dev->core; | ||
490 | |||
491 | /* setup fifo + format */ | ||
492 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], | ||
493 | buf->bpl, buf->risc.dma); | ||
494 | cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field); | ||
495 | cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma); | ||
496 | |||
497 | /* reset counter */ | ||
498 | cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET); | ||
499 | q->count = 1; | ||
500 | |||
501 | /* enable irqs */ | ||
502 | cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); | ||
503 | |||
504 | /* Enables corresponding bits at PCI_INT_STAT: | ||
505 | bits 0 to 4: video, audio, transport stream, VIP, Host | ||
506 | bit 7: timer | ||
507 | bits 8 and 9: DMA complete for: SRC, DST | ||
508 | bits 10 and 11: BERR signal asserted for RISC: RD, WR | ||
509 | bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB | ||
510 | */ | ||
511 | cx_set(MO_VID_INTMSK, 0x0f0011); | ||
512 | |||
513 | /* enable capture */ | ||
514 | cx_set(VID_CAPTURE_CONTROL,0x06); | ||
515 | |||
516 | /* start dma */ | ||
517 | cx_set(MO_DEV_CNTRL2, (1<<5)); | ||
518 | cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | #ifdef CONFIG_PM | ||
524 | static int stop_video_dma(struct cx8800_dev *dev) | ||
525 | { | ||
526 | struct cx88_core *core = dev->core; | ||
527 | |||
528 | /* stop dma */ | ||
529 | cx_clear(MO_VID_DMACNTRL, 0x11); | ||
530 | |||
531 | /* disable capture */ | ||
532 | cx_clear(VID_CAPTURE_CONTROL,0x06); | ||
533 | |||
534 | /* disable irqs */ | ||
535 | cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); | ||
536 | cx_clear(MO_VID_INTMSK, 0x0f0011); | ||
537 | return 0; | ||
538 | } | ||
539 | #endif | ||
540 | |||
541 | static int restart_video_queue(struct cx8800_dev *dev, | ||
542 | struct cx88_dmaqueue *q) | ||
543 | { | ||
544 | struct cx88_core *core = dev->core; | ||
545 | struct cx88_buffer *buf, *prev; | ||
546 | |||
547 | if (!list_empty(&q->active)) { | ||
548 | buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); | ||
549 | dprintk(2,"restart_queue [%p/%d]: restart dma\n", | ||
550 | buf, buf->vb.i); | ||
551 | start_video_dma(dev, q, buf); | ||
552 | list_for_each_entry(buf, &q->active, vb.queue) | ||
553 | buf->count = q->count++; | ||
554 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | prev = NULL; | ||
559 | for (;;) { | ||
560 | if (list_empty(&q->queued)) | ||
561 | return 0; | ||
562 | buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); | ||
563 | if (NULL == prev) { | ||
564 | list_move_tail(&buf->vb.queue, &q->active); | ||
565 | start_video_dma(dev, q, buf); | ||
566 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
567 | buf->count = q->count++; | ||
568 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
569 | dprintk(2,"[%p/%d] restart_queue - first active\n", | ||
570 | buf,buf->vb.i); | ||
571 | |||
572 | } else if (prev->vb.width == buf->vb.width && | ||
573 | prev->vb.height == buf->vb.height && | ||
574 | prev->fmt == buf->fmt) { | ||
575 | list_move_tail(&buf->vb.queue, &q->active); | ||
576 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
577 | buf->count = q->count++; | ||
578 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
579 | dprintk(2,"[%p/%d] restart_queue - move to active\n", | ||
580 | buf,buf->vb.i); | ||
581 | } else { | ||
582 | return 0; | ||
583 | } | ||
584 | prev = buf; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | /* ------------------------------------------------------------------ */ | ||
589 | |||
590 | static int | ||
591 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
592 | { | ||
593 | struct cx8800_fh *fh = q->priv_data; | ||
594 | |||
595 | *size = fh->fmt->depth*fh->width*fh->height >> 3; | ||
596 | if (0 == *count) | ||
597 | *count = 32; | ||
598 | if (*size * *count > vid_limit * 1024 * 1024) | ||
599 | *count = (vid_limit * 1024 * 1024) / *size; | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | static int | ||
604 | buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
605 | enum v4l2_field field) | ||
606 | { | ||
607 | struct cx8800_fh *fh = q->priv_data; | ||
608 | struct cx8800_dev *dev = fh->dev; | ||
609 | struct cx88_core *core = dev->core; | ||
610 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); | ||
611 | struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | ||
612 | int rc, init_buffer = 0; | ||
613 | |||
614 | BUG_ON(NULL == fh->fmt); | ||
615 | if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || | ||
616 | fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) | ||
617 | return -EINVAL; | ||
618 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; | ||
619 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | ||
620 | return -EINVAL; | ||
621 | |||
622 | if (buf->fmt != fh->fmt || | ||
623 | buf->vb.width != fh->width || | ||
624 | buf->vb.height != fh->height || | ||
625 | buf->vb.field != field) { | ||
626 | buf->fmt = fh->fmt; | ||
627 | buf->vb.width = fh->width; | ||
628 | buf->vb.height = fh->height; | ||
629 | buf->vb.field = field; | ||
630 | init_buffer = 1; | ||
631 | } | ||
632 | |||
633 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
634 | init_buffer = 1; | ||
635 | if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) | ||
636 | goto fail; | ||
637 | } | ||
638 | |||
639 | if (init_buffer) { | ||
640 | buf->bpl = buf->vb.width * buf->fmt->depth >> 3; | ||
641 | switch (buf->vb.field) { | ||
642 | case V4L2_FIELD_TOP: | ||
643 | cx88_risc_buffer(dev->pci, &buf->risc, | ||
644 | dma->sglist, 0, UNSET, | ||
645 | buf->bpl, 0, buf->vb.height); | ||
646 | break; | ||
647 | case V4L2_FIELD_BOTTOM: | ||
648 | cx88_risc_buffer(dev->pci, &buf->risc, | ||
649 | dma->sglist, UNSET, 0, | ||
650 | buf->bpl, 0, buf->vb.height); | ||
651 | break; | ||
652 | case V4L2_FIELD_INTERLACED: | ||
653 | cx88_risc_buffer(dev->pci, &buf->risc, | ||
654 | dma->sglist, 0, buf->bpl, | ||
655 | buf->bpl, buf->bpl, | ||
656 | buf->vb.height >> 1); | ||
657 | break; | ||
658 | case V4L2_FIELD_SEQ_TB: | ||
659 | cx88_risc_buffer(dev->pci, &buf->risc, | ||
660 | dma->sglist, | ||
661 | 0, buf->bpl * (buf->vb.height >> 1), | ||
662 | buf->bpl, 0, | ||
663 | buf->vb.height >> 1); | ||
664 | break; | ||
665 | case V4L2_FIELD_SEQ_BT: | ||
666 | cx88_risc_buffer(dev->pci, &buf->risc, | ||
667 | dma->sglist, | ||
668 | buf->bpl * (buf->vb.height >> 1), 0, | ||
669 | buf->bpl, 0, | ||
670 | buf->vb.height >> 1); | ||
671 | break; | ||
672 | default: | ||
673 | BUG(); | ||
674 | } | ||
675 | } | ||
676 | dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", | ||
677 | buf, buf->vb.i, | ||
678 | fh->width, fh->height, fh->fmt->depth, fh->fmt->name, | ||
679 | (unsigned long)buf->risc.dma); | ||
680 | |||
681 | buf->vb.state = VIDEOBUF_PREPARED; | ||
682 | return 0; | ||
683 | |||
684 | fail: | ||
685 | cx88_free_buffer(q,buf); | ||
686 | return rc; | ||
687 | } | ||
688 | |||
689 | static void | ||
690 | buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
691 | { | ||
692 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); | ||
693 | struct cx88_buffer *prev; | ||
694 | struct cx8800_fh *fh = vq->priv_data; | ||
695 | struct cx8800_dev *dev = fh->dev; | ||
696 | struct cx88_core *core = dev->core; | ||
697 | struct cx88_dmaqueue *q = &dev->vidq; | ||
698 | |||
699 | /* add jump to stopper */ | ||
700 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
701 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | ||
702 | |||
703 | if (!list_empty(&q->queued)) { | ||
704 | list_add_tail(&buf->vb.queue,&q->queued); | ||
705 | buf->vb.state = VIDEOBUF_QUEUED; | ||
706 | dprintk(2,"[%p/%d] buffer_queue - append to queued\n", | ||
707 | buf, buf->vb.i); | ||
708 | |||
709 | } else if (list_empty(&q->active)) { | ||
710 | list_add_tail(&buf->vb.queue,&q->active); | ||
711 | start_video_dma(dev, q, buf); | ||
712 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
713 | buf->count = q->count++; | ||
714 | mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); | ||
715 | dprintk(2,"[%p/%d] buffer_queue - first active\n", | ||
716 | buf, buf->vb.i); | ||
717 | |||
718 | } else { | ||
719 | prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); | ||
720 | if (prev->vb.width == buf->vb.width && | ||
721 | prev->vb.height == buf->vb.height && | ||
722 | prev->fmt == buf->fmt) { | ||
723 | list_add_tail(&buf->vb.queue,&q->active); | ||
724 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
725 | buf->count = q->count++; | ||
726 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
727 | dprintk(2,"[%p/%d] buffer_queue - append to active\n", | ||
728 | buf, buf->vb.i); | ||
729 | |||
730 | } else { | ||
731 | list_add_tail(&buf->vb.queue,&q->queued); | ||
732 | buf->vb.state = VIDEOBUF_QUEUED; | ||
733 | dprintk(2,"[%p/%d] buffer_queue - first queued\n", | ||
734 | buf, buf->vb.i); | ||
735 | } | ||
736 | } | ||
737 | } | ||
738 | |||
739 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
740 | { | ||
741 | struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); | ||
742 | |||
743 | cx88_free_buffer(q,buf); | ||
744 | } | ||
745 | |||
746 | static const struct videobuf_queue_ops cx8800_video_qops = { | ||
747 | .buf_setup = buffer_setup, | ||
748 | .buf_prepare = buffer_prepare, | ||
749 | .buf_queue = buffer_queue, | ||
750 | .buf_release = buffer_release, | ||
751 | }; | ||
752 | |||
753 | /* ------------------------------------------------------------------ */ | ||
754 | |||
755 | |||
756 | /* ------------------------------------------------------------------ */ | ||
757 | |||
758 | static struct videobuf_queue* get_queue(struct cx8800_fh *fh) | ||
759 | { | ||
760 | switch (fh->type) { | ||
761 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
762 | return &fh->vidq; | ||
763 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
764 | return &fh->vbiq; | ||
765 | default: | ||
766 | BUG(); | ||
767 | return NULL; | ||
768 | } | ||
769 | } | ||
770 | |||
771 | static int get_ressource(struct cx8800_fh *fh) | ||
772 | { | ||
773 | switch (fh->type) { | ||
774 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
775 | return RESOURCE_VIDEO; | ||
776 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
777 | return RESOURCE_VBI; | ||
778 | default: | ||
779 | BUG(); | ||
780 | return 0; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | static int video_open(struct file *file) | ||
785 | { | ||
786 | struct video_device *vdev = video_devdata(file); | ||
787 | struct cx8800_dev *dev = video_drvdata(file); | ||
788 | struct cx88_core *core = dev->core; | ||
789 | struct cx8800_fh *fh; | ||
790 | enum v4l2_buf_type type = 0; | ||
791 | int radio = 0; | ||
792 | |||
793 | switch (vdev->vfl_type) { | ||
794 | case VFL_TYPE_GRABBER: | ||
795 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
796 | break; | ||
797 | case VFL_TYPE_VBI: | ||
798 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
799 | break; | ||
800 | case VFL_TYPE_RADIO: | ||
801 | radio = 1; | ||
802 | break; | ||
803 | } | ||
804 | |||
805 | dprintk(1, "open dev=%s radio=%d type=%s\n", | ||
806 | video_device_node_name(vdev), radio, v4l2_type_names[type]); | ||
807 | |||
808 | /* allocate + initialize per filehandle data */ | ||
809 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | ||
810 | if (unlikely(!fh)) | ||
811 | return -ENOMEM; | ||
812 | |||
813 | file->private_data = fh; | ||
814 | fh->dev = dev; | ||
815 | fh->radio = radio; | ||
816 | fh->type = type; | ||
817 | fh->width = 320; | ||
818 | fh->height = 240; | ||
819 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); | ||
820 | |||
821 | mutex_lock(&core->lock); | ||
822 | |||
823 | videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops, | ||
824 | &dev->pci->dev, &dev->slock, | ||
825 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
826 | V4L2_FIELD_INTERLACED, | ||
827 | sizeof(struct cx88_buffer), | ||
828 | fh, NULL); | ||
829 | videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops, | ||
830 | &dev->pci->dev, &dev->slock, | ||
831 | V4L2_BUF_TYPE_VBI_CAPTURE, | ||
832 | V4L2_FIELD_SEQ_TB, | ||
833 | sizeof(struct cx88_buffer), | ||
834 | fh, NULL); | ||
835 | |||
836 | if (fh->radio) { | ||
837 | dprintk(1,"video_open: setting radio device\n"); | ||
838 | cx_write(MO_GP3_IO, core->board.radio.gpio3); | ||
839 | cx_write(MO_GP0_IO, core->board.radio.gpio0); | ||
840 | cx_write(MO_GP1_IO, core->board.radio.gpio1); | ||
841 | cx_write(MO_GP2_IO, core->board.radio.gpio2); | ||
842 | if (core->board.radio.audioroute) { | ||
843 | if(core->board.audio_chip && | ||
844 | core->board.audio_chip == V4L2_IDENT_WM8775) { | ||
845 | call_all(core, audio, s_routing, | ||
846 | core->board.radio.audioroute, 0, 0); | ||
847 | } | ||
848 | /* "I2S ADC mode" */ | ||
849 | core->tvaudio = WW_I2SADC; | ||
850 | cx88_set_tvaudio(core); | ||
851 | } else { | ||
852 | /* FM Mode */ | ||
853 | core->tvaudio = WW_FM; | ||
854 | cx88_set_tvaudio(core); | ||
855 | cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); | ||
856 | } | ||
857 | call_all(core, tuner, s_radio); | ||
858 | } | ||
859 | |||
860 | core->users++; | ||
861 | mutex_unlock(&core->lock); | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static ssize_t | ||
867 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
868 | { | ||
869 | struct cx8800_fh *fh = file->private_data; | ||
870 | |||
871 | switch (fh->type) { | ||
872 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
873 | if (res_locked(fh->dev,RESOURCE_VIDEO)) | ||
874 | return -EBUSY; | ||
875 | return videobuf_read_one(&fh->vidq, data, count, ppos, | ||
876 | file->f_flags & O_NONBLOCK); | ||
877 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
878 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) | ||
879 | return -EBUSY; | ||
880 | return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, | ||
881 | file->f_flags & O_NONBLOCK); | ||
882 | default: | ||
883 | BUG(); | ||
884 | return 0; | ||
885 | } | ||
886 | } | ||
887 | |||
888 | static unsigned int | ||
889 | video_poll(struct file *file, struct poll_table_struct *wait) | ||
890 | { | ||
891 | struct cx8800_fh *fh = file->private_data; | ||
892 | struct cx88_buffer *buf; | ||
893 | unsigned int rc = POLLERR; | ||
894 | |||
895 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { | ||
896 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) | ||
897 | return POLLERR; | ||
898 | return videobuf_poll_stream(file, &fh->vbiq, wait); | ||
899 | } | ||
900 | |||
901 | mutex_lock(&fh->vidq.vb_lock); | ||
902 | if (res_check(fh,RESOURCE_VIDEO)) { | ||
903 | /* streaming capture */ | ||
904 | if (list_empty(&fh->vidq.stream)) | ||
905 | goto done; | ||
906 | buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream); | ||
907 | } else { | ||
908 | /* read() capture */ | ||
909 | buf = (struct cx88_buffer*)fh->vidq.read_buf; | ||
910 | if (NULL == buf) | ||
911 | goto done; | ||
912 | } | ||
913 | poll_wait(file, &buf->vb.done, wait); | ||
914 | if (buf->vb.state == VIDEOBUF_DONE || | ||
915 | buf->vb.state == VIDEOBUF_ERROR) | ||
916 | rc = POLLIN|POLLRDNORM; | ||
917 | else | ||
918 | rc = 0; | ||
919 | done: | ||
920 | mutex_unlock(&fh->vidq.vb_lock); | ||
921 | return rc; | ||
922 | } | ||
923 | |||
924 | static int video_release(struct file *file) | ||
925 | { | ||
926 | struct cx8800_fh *fh = file->private_data; | ||
927 | struct cx8800_dev *dev = fh->dev; | ||
928 | |||
929 | /* turn off overlay */ | ||
930 | if (res_check(fh, RESOURCE_OVERLAY)) { | ||
931 | /* FIXME */ | ||
932 | res_free(dev,fh,RESOURCE_OVERLAY); | ||
933 | } | ||
934 | |||
935 | /* stop video capture */ | ||
936 | if (res_check(fh, RESOURCE_VIDEO)) { | ||
937 | videobuf_queue_cancel(&fh->vidq); | ||
938 | res_free(dev,fh,RESOURCE_VIDEO); | ||
939 | } | ||
940 | if (fh->vidq.read_buf) { | ||
941 | buffer_release(&fh->vidq,fh->vidq.read_buf); | ||
942 | kfree(fh->vidq.read_buf); | ||
943 | } | ||
944 | |||
945 | /* stop vbi capture */ | ||
946 | if (res_check(fh, RESOURCE_VBI)) { | ||
947 | videobuf_stop(&fh->vbiq); | ||
948 | res_free(dev,fh,RESOURCE_VBI); | ||
949 | } | ||
950 | |||
951 | videobuf_mmap_free(&fh->vidq); | ||
952 | videobuf_mmap_free(&fh->vbiq); | ||
953 | |||
954 | mutex_lock(&dev->core->lock); | ||
955 | file->private_data = NULL; | ||
956 | kfree(fh); | ||
957 | |||
958 | dev->core->users--; | ||
959 | if (!dev->core->users) | ||
960 | call_all(dev->core, core, s_power, 0); | ||
961 | mutex_unlock(&dev->core->lock); | ||
962 | |||
963 | return 0; | ||
964 | } | ||
965 | |||
966 | static int | ||
967 | video_mmap(struct file *file, struct vm_area_struct * vma) | ||
968 | { | ||
969 | struct cx8800_fh *fh = file->private_data; | ||
970 | |||
971 | return videobuf_mmap_mapper(get_queue(fh), vma); | ||
972 | } | ||
973 | |||
974 | /* ------------------------------------------------------------------ */ | ||
975 | /* VIDEO CTRL IOCTLS */ | ||
976 | |||
977 | int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) | ||
978 | { | ||
979 | const struct cx88_ctrl *c = NULL; | ||
980 | u32 value; | ||
981 | int i; | ||
982 | |||
983 | for (i = 0; i < CX8800_CTLS; i++) | ||
984 | if (cx8800_ctls[i].v.id == ctl->id) | ||
985 | c = &cx8800_ctls[i]; | ||
986 | if (unlikely(NULL == c)) | ||
987 | return -EINVAL; | ||
988 | |||
989 | value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); | ||
990 | switch (ctl->id) { | ||
991 | case V4L2_CID_AUDIO_BALANCE: | ||
992 | ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) | ||
993 | : (0x7f - (value & 0x7f)); | ||
994 | break; | ||
995 | case V4L2_CID_AUDIO_VOLUME: | ||
996 | ctl->value = 0x3f - (value & 0x3f); | ||
997 | break; | ||
998 | case V4L2_CID_SHARPNESS: | ||
999 | ctl->value = ((value & 0x0200) ? (((value & 0x0180) >> 7) + 1) | ||
1000 | : 0); | ||
1001 | break; | ||
1002 | default: | ||
1003 | ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; | ||
1004 | break; | ||
1005 | } | ||
1006 | dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", | ||
1007 | ctl->id, c->v.name, ctl->value, c->reg, | ||
1008 | value,c->mask, c->sreg ? " [shadowed]" : ""); | ||
1009 | return 0; | ||
1010 | } | ||
1011 | EXPORT_SYMBOL(cx88_get_control); | ||
1012 | |||
1013 | int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) | ||
1014 | { | ||
1015 | const struct cx88_ctrl *c = NULL; | ||
1016 | u32 value,mask; | ||
1017 | int i; | ||
1018 | |||
1019 | for (i = 0; i < CX8800_CTLS; i++) { | ||
1020 | if (cx8800_ctls[i].v.id == ctl->id) { | ||
1021 | c = &cx8800_ctls[i]; | ||
1022 | } | ||
1023 | } | ||
1024 | if (unlikely(NULL == c)) | ||
1025 | return -EINVAL; | ||
1026 | |||
1027 | if (ctl->value < c->v.minimum) | ||
1028 | ctl->value = c->v.minimum; | ||
1029 | if (ctl->value > c->v.maximum) | ||
1030 | ctl->value = c->v.maximum; | ||
1031 | |||
1032 | /* Pass changes onto any WM8775 */ | ||
1033 | if (core->board.audio_chip == V4L2_IDENT_WM8775) { | ||
1034 | struct v4l2_control client_ctl; | ||
1035 | memset(&client_ctl, 0, sizeof(client_ctl)); | ||
1036 | client_ctl.id = ctl->id; | ||
1037 | |||
1038 | switch (ctl->id) { | ||
1039 | case V4L2_CID_AUDIO_MUTE: | ||
1040 | client_ctl.value = ctl->value; | ||
1041 | break; | ||
1042 | case V4L2_CID_AUDIO_VOLUME: | ||
1043 | client_ctl.value = (ctl->value) ? | ||
1044 | (0x90 + ctl->value) << 8 : 0; | ||
1045 | break; | ||
1046 | case V4L2_CID_AUDIO_BALANCE: | ||
1047 | client_ctl.value = ctl->value << 9; | ||
1048 | break; | ||
1049 | default: | ||
1050 | client_ctl.id = 0; | ||
1051 | break; | ||
1052 | } | ||
1053 | if (client_ctl.id) | ||
1054 | call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); | ||
1055 | } | ||
1056 | |||
1057 | mask=c->mask; | ||
1058 | switch (ctl->id) { | ||
1059 | case V4L2_CID_AUDIO_BALANCE: | ||
1060 | value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); | ||
1061 | break; | ||
1062 | case V4L2_CID_AUDIO_VOLUME: | ||
1063 | value = 0x3f - (ctl->value & 0x3f); | ||
1064 | break; | ||
1065 | case V4L2_CID_SATURATION: | ||
1066 | /* special v_sat handling */ | ||
1067 | |||
1068 | value = ((ctl->value - c->off) << c->shift) & c->mask; | ||
1069 | |||
1070 | if (core->tvnorm & V4L2_STD_SECAM) { | ||
1071 | /* For SECAM, both U and V sat should be equal */ | ||
1072 | value=value<<8|value; | ||
1073 | } else { | ||
1074 | /* Keeps U Saturation proportional to V Sat */ | ||
1075 | value=(value*0x5a)/0x7f<<8|value; | ||
1076 | } | ||
1077 | mask=0xffff; | ||
1078 | break; | ||
1079 | case V4L2_CID_SHARPNESS: | ||
1080 | /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ | ||
1081 | value = (ctl->value < 1 ? 0 : ((ctl->value + 3) << 7)); | ||
1082 | /* needs to be set for both fields */ | ||
1083 | cx_andor(MO_FILTER_EVEN, mask, value); | ||
1084 | break; | ||
1085 | case V4L2_CID_CHROMA_AGC: | ||
1086 | /* Do not allow chroma AGC to be enabled for SECAM */ | ||
1087 | value = ((ctl->value - c->off) << c->shift) & c->mask; | ||
1088 | if (core->tvnorm & V4L2_STD_SECAM && value) | ||
1089 | return -EINVAL; | ||
1090 | break; | ||
1091 | default: | ||
1092 | value = ((ctl->value - c->off) << c->shift) & c->mask; | ||
1093 | break; | ||
1094 | } | ||
1095 | dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", | ||
1096 | ctl->id, c->v.name, ctl->value, c->reg, value, | ||
1097 | mask, c->sreg ? " [shadowed]" : ""); | ||
1098 | if (c->sreg) { | ||
1099 | cx_sandor(c->sreg, c->reg, mask, value); | ||
1100 | } else { | ||
1101 | cx_andor(c->reg, mask, value); | ||
1102 | } | ||
1103 | return 0; | ||
1104 | } | ||
1105 | EXPORT_SYMBOL(cx88_set_control); | ||
1106 | |||
1107 | static void init_controls(struct cx88_core *core) | ||
1108 | { | ||
1109 | struct v4l2_control ctrl; | ||
1110 | int i; | ||
1111 | |||
1112 | for (i = 0; i < CX8800_CTLS; i++) { | ||
1113 | ctrl.id=cx8800_ctls[i].v.id; | ||
1114 | ctrl.value=cx8800_ctls[i].v.default_value; | ||
1115 | |||
1116 | cx88_set_control(core, &ctrl); | ||
1117 | } | ||
1118 | } | ||
1119 | |||
1120 | /* ------------------------------------------------------------------ */ | ||
1121 | /* VIDEO IOCTLS */ | ||
1122 | |||
1123 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
1124 | struct v4l2_format *f) | ||
1125 | { | ||
1126 | struct cx8800_fh *fh = priv; | ||
1127 | |||
1128 | f->fmt.pix.width = fh->width; | ||
1129 | f->fmt.pix.height = fh->height; | ||
1130 | f->fmt.pix.field = fh->vidq.field; | ||
1131 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | ||
1132 | f->fmt.pix.bytesperline = | ||
1133 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | ||
1134 | f->fmt.pix.sizeimage = | ||
1135 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
1140 | struct v4l2_format *f) | ||
1141 | { | ||
1142 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1143 | const struct cx8800_fmt *fmt; | ||
1144 | enum v4l2_field field; | ||
1145 | unsigned int maxw, maxh; | ||
1146 | |||
1147 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
1148 | if (NULL == fmt) | ||
1149 | return -EINVAL; | ||
1150 | |||
1151 | field = f->fmt.pix.field; | ||
1152 | maxw = norm_maxw(core->tvnorm); | ||
1153 | maxh = norm_maxh(core->tvnorm); | ||
1154 | |||
1155 | if (V4L2_FIELD_ANY == field) { | ||
1156 | field = (f->fmt.pix.height > maxh/2) | ||
1157 | ? V4L2_FIELD_INTERLACED | ||
1158 | : V4L2_FIELD_BOTTOM; | ||
1159 | } | ||
1160 | |||
1161 | switch (field) { | ||
1162 | case V4L2_FIELD_TOP: | ||
1163 | case V4L2_FIELD_BOTTOM: | ||
1164 | maxh = maxh / 2; | ||
1165 | break; | ||
1166 | case V4L2_FIELD_INTERLACED: | ||
1167 | break; | ||
1168 | default: | ||
1169 | return -EINVAL; | ||
1170 | } | ||
1171 | |||
1172 | f->fmt.pix.field = field; | ||
1173 | v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, | ||
1174 | &f->fmt.pix.height, 32, maxh, 0, 0); | ||
1175 | f->fmt.pix.bytesperline = | ||
1176 | (f->fmt.pix.width * fmt->depth) >> 3; | ||
1177 | f->fmt.pix.sizeimage = | ||
1178 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1179 | |||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1183 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
1184 | struct v4l2_format *f) | ||
1185 | { | ||
1186 | struct cx8800_fh *fh = priv; | ||
1187 | int err = vidioc_try_fmt_vid_cap (file,priv,f); | ||
1188 | |||
1189 | if (0 != err) | ||
1190 | return err; | ||
1191 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
1192 | fh->width = f->fmt.pix.width; | ||
1193 | fh->height = f->fmt.pix.height; | ||
1194 | fh->vidq.field = f->fmt.pix.field; | ||
1195 | return 0; | ||
1196 | } | ||
1197 | |||
1198 | static int vidioc_querycap (struct file *file, void *priv, | ||
1199 | struct v4l2_capability *cap) | ||
1200 | { | ||
1201 | struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; | ||
1202 | struct cx88_core *core = dev->core; | ||
1203 | |||
1204 | strcpy(cap->driver, "cx8800"); | ||
1205 | strlcpy(cap->card, core->board.name, sizeof(cap->card)); | ||
1206 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); | ||
1207 | cap->capabilities = | ||
1208 | V4L2_CAP_VIDEO_CAPTURE | | ||
1209 | V4L2_CAP_READWRITE | | ||
1210 | V4L2_CAP_STREAMING | | ||
1211 | V4L2_CAP_VBI_CAPTURE; | ||
1212 | if (UNSET != core->board.tuner_type) | ||
1213 | cap->capabilities |= V4L2_CAP_TUNER; | ||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, | ||
1218 | struct v4l2_fmtdesc *f) | ||
1219 | { | ||
1220 | if (unlikely(f->index >= ARRAY_SIZE(formats))) | ||
1221 | return -EINVAL; | ||
1222 | |||
1223 | strlcpy(f->description,formats[f->index].name,sizeof(f->description)); | ||
1224 | f->pixelformat = formats[f->index].fourcc; | ||
1225 | |||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) | ||
1230 | { | ||
1231 | struct cx8800_fh *fh = priv; | ||
1232 | return (videobuf_reqbufs(get_queue(fh), p)); | ||
1233 | } | ||
1234 | |||
1235 | static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) | ||
1236 | { | ||
1237 | struct cx8800_fh *fh = priv; | ||
1238 | return (videobuf_querybuf(get_queue(fh), p)); | ||
1239 | } | ||
1240 | |||
1241 | static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) | ||
1242 | { | ||
1243 | struct cx8800_fh *fh = priv; | ||
1244 | return (videobuf_qbuf(get_queue(fh), p)); | ||
1245 | } | ||
1246 | |||
1247 | static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) | ||
1248 | { | ||
1249 | struct cx8800_fh *fh = priv; | ||
1250 | return (videobuf_dqbuf(get_queue(fh), p, | ||
1251 | file->f_flags & O_NONBLOCK)); | ||
1252 | } | ||
1253 | |||
1254 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | ||
1255 | { | ||
1256 | struct cx8800_fh *fh = priv; | ||
1257 | struct cx8800_dev *dev = fh->dev; | ||
1258 | |||
1259 | /* We should remember that this driver also supports teletext, */ | ||
1260 | /* so we have to test if the v4l2_buf_type is VBI capture data. */ | ||
1261 | if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
1262 | (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))) | ||
1263 | return -EINVAL; | ||
1264 | |||
1265 | if (unlikely(i != fh->type)) | ||
1266 | return -EINVAL; | ||
1267 | |||
1268 | if (unlikely(!res_get(dev,fh,get_ressource(fh)))) | ||
1269 | return -EBUSY; | ||
1270 | return videobuf_streamon(get_queue(fh)); | ||
1271 | } | ||
1272 | |||
1273 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
1274 | { | ||
1275 | struct cx8800_fh *fh = priv; | ||
1276 | struct cx8800_dev *dev = fh->dev; | ||
1277 | int err, res; | ||
1278 | |||
1279 | if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
1280 | (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
1281 | return -EINVAL; | ||
1282 | |||
1283 | if (i != fh->type) | ||
1284 | return -EINVAL; | ||
1285 | |||
1286 | res = get_ressource(fh); | ||
1287 | err = videobuf_streamoff(get_queue(fh)); | ||
1288 | if (err < 0) | ||
1289 | return err; | ||
1290 | res_free(dev,fh,res); | ||
1291 | return 0; | ||
1292 | } | ||
1293 | |||
1294 | static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms) | ||
1295 | { | ||
1296 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1297 | |||
1298 | mutex_lock(&core->lock); | ||
1299 | cx88_set_tvnorm(core,*tvnorms); | ||
1300 | mutex_unlock(&core->lock); | ||
1301 | |||
1302 | return 0; | ||
1303 | } | ||
1304 | |||
1305 | /* only one input in this sample driver */ | ||
1306 | int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) | ||
1307 | { | ||
1308 | static const char * const iname[] = { | ||
1309 | [ CX88_VMUX_COMPOSITE1 ] = "Composite1", | ||
1310 | [ CX88_VMUX_COMPOSITE2 ] = "Composite2", | ||
1311 | [ CX88_VMUX_COMPOSITE3 ] = "Composite3", | ||
1312 | [ CX88_VMUX_COMPOSITE4 ] = "Composite4", | ||
1313 | [ CX88_VMUX_SVIDEO ] = "S-Video", | ||
1314 | [ CX88_VMUX_TELEVISION ] = "Television", | ||
1315 | [ CX88_VMUX_CABLE ] = "Cable TV", | ||
1316 | [ CX88_VMUX_DVB ] = "DVB", | ||
1317 | [ CX88_VMUX_DEBUG ] = "for debug only", | ||
1318 | }; | ||
1319 | unsigned int n = i->index; | ||
1320 | |||
1321 | if (n >= 4) | ||
1322 | return -EINVAL; | ||
1323 | if (0 == INPUT(n).type) | ||
1324 | return -EINVAL; | ||
1325 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1326 | strcpy(i->name,iname[INPUT(n).type]); | ||
1327 | if ((CX88_VMUX_TELEVISION == INPUT(n).type) || | ||
1328 | (CX88_VMUX_CABLE == INPUT(n).type)) { | ||
1329 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1330 | i->std = CX88_NORMS; | ||
1331 | } | ||
1332 | return 0; | ||
1333 | } | ||
1334 | EXPORT_SYMBOL(cx88_enum_input); | ||
1335 | |||
1336 | static int vidioc_enum_input (struct file *file, void *priv, | ||
1337 | struct v4l2_input *i) | ||
1338 | { | ||
1339 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1340 | return cx88_enum_input (core,i); | ||
1341 | } | ||
1342 | |||
1343 | static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) | ||
1344 | { | ||
1345 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1346 | |||
1347 | *i = core->input; | ||
1348 | return 0; | ||
1349 | } | ||
1350 | |||
1351 | static int vidioc_s_input (struct file *file, void *priv, unsigned int i) | ||
1352 | { | ||
1353 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1354 | |||
1355 | if (i >= 4) | ||
1356 | return -EINVAL; | ||
1357 | |||
1358 | mutex_lock(&core->lock); | ||
1359 | cx88_newstation(core); | ||
1360 | cx88_video_mux(core,i); | ||
1361 | mutex_unlock(&core->lock); | ||
1362 | return 0; | ||
1363 | } | ||
1364 | |||
1365 | |||
1366 | |||
1367 | static int vidioc_queryctrl (struct file *file, void *priv, | ||
1368 | struct v4l2_queryctrl *qctrl) | ||
1369 | { | ||
1370 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1371 | |||
1372 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
1373 | if (unlikely(qctrl->id == 0)) | ||
1374 | return -EINVAL; | ||
1375 | return cx8800_ctrl_query(core, qctrl); | ||
1376 | } | ||
1377 | |||
1378 | static int vidioc_g_ctrl (struct file *file, void *priv, | ||
1379 | struct v4l2_control *ctl) | ||
1380 | { | ||
1381 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1382 | return | ||
1383 | cx88_get_control(core,ctl); | ||
1384 | } | ||
1385 | |||
1386 | static int vidioc_s_ctrl (struct file *file, void *priv, | ||
1387 | struct v4l2_control *ctl) | ||
1388 | { | ||
1389 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1390 | return | ||
1391 | cx88_set_control(core,ctl); | ||
1392 | } | ||
1393 | |||
1394 | static int vidioc_g_tuner (struct file *file, void *priv, | ||
1395 | struct v4l2_tuner *t) | ||
1396 | { | ||
1397 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1398 | u32 reg; | ||
1399 | |||
1400 | if (unlikely(UNSET == core->board.tuner_type)) | ||
1401 | return -EINVAL; | ||
1402 | if (0 != t->index) | ||
1403 | return -EINVAL; | ||
1404 | |||
1405 | strcpy(t->name, "Television"); | ||
1406 | t->type = V4L2_TUNER_ANALOG_TV; | ||
1407 | t->capability = V4L2_TUNER_CAP_NORM; | ||
1408 | t->rangehigh = 0xffffffffUL; | ||
1409 | |||
1410 | cx88_get_stereo(core ,t); | ||
1411 | reg = cx_read(MO_DEVICE_STATUS); | ||
1412 | t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; | ||
1413 | return 0; | ||
1414 | } | ||
1415 | |||
1416 | static int vidioc_s_tuner (struct file *file, void *priv, | ||
1417 | struct v4l2_tuner *t) | ||
1418 | { | ||
1419 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1420 | |||
1421 | if (UNSET == core->board.tuner_type) | ||
1422 | return -EINVAL; | ||
1423 | if (0 != t->index) | ||
1424 | return -EINVAL; | ||
1425 | |||
1426 | cx88_set_stereo(core, t->audmode, 1); | ||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | static int vidioc_g_frequency (struct file *file, void *priv, | ||
1431 | struct v4l2_frequency *f) | ||
1432 | { | ||
1433 | struct cx8800_fh *fh = priv; | ||
1434 | struct cx88_core *core = fh->dev->core; | ||
1435 | |||
1436 | if (unlikely(UNSET == core->board.tuner_type)) | ||
1437 | return -EINVAL; | ||
1438 | |||
1439 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ | ||
1440 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | ||
1441 | f->frequency = core->freq; | ||
1442 | |||
1443 | call_all(core, tuner, g_frequency, f); | ||
1444 | |||
1445 | return 0; | ||
1446 | } | ||
1447 | |||
1448 | int cx88_set_freq (struct cx88_core *core, | ||
1449 | struct v4l2_frequency *f) | ||
1450 | { | ||
1451 | if (unlikely(UNSET == core->board.tuner_type)) | ||
1452 | return -EINVAL; | ||
1453 | if (unlikely(f->tuner != 0)) | ||
1454 | return -EINVAL; | ||
1455 | |||
1456 | mutex_lock(&core->lock); | ||
1457 | core->freq = f->frequency; | ||
1458 | cx88_newstation(core); | ||
1459 | call_all(core, tuner, s_frequency, f); | ||
1460 | |||
1461 | /* When changing channels it is required to reset TVAUDIO */ | ||
1462 | msleep (10); | ||
1463 | cx88_set_tvaudio(core); | ||
1464 | |||
1465 | mutex_unlock(&core->lock); | ||
1466 | |||
1467 | return 0; | ||
1468 | } | ||
1469 | EXPORT_SYMBOL(cx88_set_freq); | ||
1470 | |||
1471 | static int vidioc_s_frequency (struct file *file, void *priv, | ||
1472 | struct v4l2_frequency *f) | ||
1473 | { | ||
1474 | struct cx8800_fh *fh = priv; | ||
1475 | struct cx88_core *core = fh->dev->core; | ||
1476 | |||
1477 | if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) | ||
1478 | return -EINVAL; | ||
1479 | if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) | ||
1480 | return -EINVAL; | ||
1481 | |||
1482 | return | ||
1483 | cx88_set_freq (core,f); | ||
1484 | } | ||
1485 | |||
1486 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1487 | static int vidioc_g_register (struct file *file, void *fh, | ||
1488 | struct v4l2_dbg_register *reg) | ||
1489 | { | ||
1490 | struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; | ||
1491 | |||
1492 | if (!v4l2_chip_match_host(®->match)) | ||
1493 | return -EINVAL; | ||
1494 | /* cx2388x has a 24-bit register space */ | ||
1495 | reg->val = cx_read(reg->reg & 0xffffff); | ||
1496 | reg->size = 4; | ||
1497 | return 0; | ||
1498 | } | ||
1499 | |||
1500 | static int vidioc_s_register (struct file *file, void *fh, | ||
1501 | struct v4l2_dbg_register *reg) | ||
1502 | { | ||
1503 | struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; | ||
1504 | |||
1505 | if (!v4l2_chip_match_host(®->match)) | ||
1506 | return -EINVAL; | ||
1507 | cx_write(reg->reg & 0xffffff, reg->val); | ||
1508 | return 0; | ||
1509 | } | ||
1510 | #endif | ||
1511 | |||
1512 | /* ----------------------------------------------------------- */ | ||
1513 | /* RADIO ESPECIFIC IOCTLS */ | ||
1514 | /* ----------------------------------------------------------- */ | ||
1515 | |||
1516 | static int radio_querycap (struct file *file, void *priv, | ||
1517 | struct v4l2_capability *cap) | ||
1518 | { | ||
1519 | struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; | ||
1520 | struct cx88_core *core = dev->core; | ||
1521 | |||
1522 | strcpy(cap->driver, "cx8800"); | ||
1523 | strlcpy(cap->card, core->board.name, sizeof(cap->card)); | ||
1524 | sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); | ||
1525 | cap->capabilities = V4L2_CAP_TUNER; | ||
1526 | return 0; | ||
1527 | } | ||
1528 | |||
1529 | static int radio_g_tuner (struct file *file, void *priv, | ||
1530 | struct v4l2_tuner *t) | ||
1531 | { | ||
1532 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1533 | |||
1534 | if (unlikely(t->index > 0)) | ||
1535 | return -EINVAL; | ||
1536 | |||
1537 | strcpy(t->name, "Radio"); | ||
1538 | t->type = V4L2_TUNER_RADIO; | ||
1539 | |||
1540 | call_all(core, tuner, g_tuner, t); | ||
1541 | return 0; | ||
1542 | } | ||
1543 | |||
1544 | static int radio_enum_input (struct file *file, void *priv, | ||
1545 | struct v4l2_input *i) | ||
1546 | { | ||
1547 | if (i->index != 0) | ||
1548 | return -EINVAL; | ||
1549 | strcpy(i->name,"Radio"); | ||
1550 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1551 | |||
1552 | return 0; | ||
1553 | } | ||
1554 | |||
1555 | static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a) | ||
1556 | { | ||
1557 | if (unlikely(a->index)) | ||
1558 | return -EINVAL; | ||
1559 | |||
1560 | strcpy(a->name,"Radio"); | ||
1561 | return 0; | ||
1562 | } | ||
1563 | |||
1564 | /* FIXME: Should add a standard for radio */ | ||
1565 | |||
1566 | static int radio_s_tuner (struct file *file, void *priv, | ||
1567 | struct v4l2_tuner *t) | ||
1568 | { | ||
1569 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1570 | |||
1571 | if (0 != t->index) | ||
1572 | return -EINVAL; | ||
1573 | |||
1574 | call_all(core, tuner, s_tuner, t); | ||
1575 | |||
1576 | return 0; | ||
1577 | } | ||
1578 | |||
1579 | static int radio_s_audio (struct file *file, void *fh, | ||
1580 | struct v4l2_audio *a) | ||
1581 | { | ||
1582 | return 0; | ||
1583 | } | ||
1584 | |||
1585 | static int radio_s_input (struct file *file, void *fh, unsigned int i) | ||
1586 | { | ||
1587 | return 0; | ||
1588 | } | ||
1589 | |||
1590 | static int radio_queryctrl (struct file *file, void *priv, | ||
1591 | struct v4l2_queryctrl *c) | ||
1592 | { | ||
1593 | int i; | ||
1594 | |||
1595 | if (c->id < V4L2_CID_BASE || | ||
1596 | c->id >= V4L2_CID_LASTP1) | ||
1597 | return -EINVAL; | ||
1598 | if (c->id == V4L2_CID_AUDIO_MUTE || | ||
1599 | c->id == V4L2_CID_AUDIO_VOLUME || | ||
1600 | c->id == V4L2_CID_AUDIO_BALANCE) { | ||
1601 | for (i = 0; i < CX8800_CTLS; i++) { | ||
1602 | if (cx8800_ctls[i].v.id == c->id) | ||
1603 | break; | ||
1604 | } | ||
1605 | if (i == CX8800_CTLS) | ||
1606 | return -EINVAL; | ||
1607 | *c = cx8800_ctls[i].v; | ||
1608 | } else | ||
1609 | *c = no_ctl; | ||
1610 | return 0; | ||
1611 | } | ||
1612 | |||
1613 | /* ----------------------------------------------------------- */ | ||
1614 | |||
1615 | static void cx8800_vid_timeout(unsigned long data) | ||
1616 | { | ||
1617 | struct cx8800_dev *dev = (struct cx8800_dev*)data; | ||
1618 | struct cx88_core *core = dev->core; | ||
1619 | struct cx88_dmaqueue *q = &dev->vidq; | ||
1620 | struct cx88_buffer *buf; | ||
1621 | unsigned long flags; | ||
1622 | |||
1623 | cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); | ||
1624 | |||
1625 | cx_clear(MO_VID_DMACNTRL, 0x11); | ||
1626 | cx_clear(VID_CAPTURE_CONTROL, 0x06); | ||
1627 | |||
1628 | spin_lock_irqsave(&dev->slock,flags); | ||
1629 | while (!list_empty(&q->active)) { | ||
1630 | buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); | ||
1631 | list_del(&buf->vb.queue); | ||
1632 | buf->vb.state = VIDEOBUF_ERROR; | ||
1633 | wake_up(&buf->vb.done); | ||
1634 | printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, | ||
1635 | buf, buf->vb.i, (unsigned long)buf->risc.dma); | ||
1636 | } | ||
1637 | restart_video_queue(dev,q); | ||
1638 | spin_unlock_irqrestore(&dev->slock,flags); | ||
1639 | } | ||
1640 | |||
1641 | static const char *cx88_vid_irqs[32] = { | ||
1642 | "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", | ||
1643 | "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", | ||
1644 | "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", | ||
1645 | "y_sync", "u_sync", "v_sync", "vbi_sync", | ||
1646 | "opc_err", "par_err", "rip_err", "pci_abort", | ||
1647 | }; | ||
1648 | |||
1649 | static void cx8800_vid_irq(struct cx8800_dev *dev) | ||
1650 | { | ||
1651 | struct cx88_core *core = dev->core; | ||
1652 | u32 status, mask, count; | ||
1653 | |||
1654 | status = cx_read(MO_VID_INTSTAT); | ||
1655 | mask = cx_read(MO_VID_INTMSK); | ||
1656 | if (0 == (status & mask)) | ||
1657 | return; | ||
1658 | cx_write(MO_VID_INTSTAT, status); | ||
1659 | if (irq_debug || (status & mask & ~0xff)) | ||
1660 | cx88_print_irqbits(core->name, "irq vid", | ||
1661 | cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), | ||
1662 | status, mask); | ||
1663 | |||
1664 | /* risc op code error */ | ||
1665 | if (status & (1 << 16)) { | ||
1666 | printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); | ||
1667 | cx_clear(MO_VID_DMACNTRL, 0x11); | ||
1668 | cx_clear(VID_CAPTURE_CONTROL, 0x06); | ||
1669 | cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); | ||
1670 | } | ||
1671 | |||
1672 | /* risc1 y */ | ||
1673 | if (status & 0x01) { | ||
1674 | spin_lock(&dev->slock); | ||
1675 | count = cx_read(MO_VIDY_GPCNT); | ||
1676 | cx88_wakeup(core, &dev->vidq, count); | ||
1677 | spin_unlock(&dev->slock); | ||
1678 | } | ||
1679 | |||
1680 | /* risc1 vbi */ | ||
1681 | if (status & 0x08) { | ||
1682 | spin_lock(&dev->slock); | ||
1683 | count = cx_read(MO_VBI_GPCNT); | ||
1684 | cx88_wakeup(core, &dev->vbiq, count); | ||
1685 | spin_unlock(&dev->slock); | ||
1686 | } | ||
1687 | |||
1688 | /* risc2 y */ | ||
1689 | if (status & 0x10) { | ||
1690 | dprintk(2,"stopper video\n"); | ||
1691 | spin_lock(&dev->slock); | ||
1692 | restart_video_queue(dev,&dev->vidq); | ||
1693 | spin_unlock(&dev->slock); | ||
1694 | } | ||
1695 | |||
1696 | /* risc2 vbi */ | ||
1697 | if (status & 0x80) { | ||
1698 | dprintk(2,"stopper vbi\n"); | ||
1699 | spin_lock(&dev->slock); | ||
1700 | cx8800_restart_vbi_queue(dev,&dev->vbiq); | ||
1701 | spin_unlock(&dev->slock); | ||
1702 | } | ||
1703 | } | ||
1704 | |||
1705 | static irqreturn_t cx8800_irq(int irq, void *dev_id) | ||
1706 | { | ||
1707 | struct cx8800_dev *dev = dev_id; | ||
1708 | struct cx88_core *core = dev->core; | ||
1709 | u32 status; | ||
1710 | int loop, handled = 0; | ||
1711 | |||
1712 | for (loop = 0; loop < 10; loop++) { | ||
1713 | status = cx_read(MO_PCI_INTSTAT) & | ||
1714 | (core->pci_irqmask | PCI_INT_VIDINT); | ||
1715 | if (0 == status) | ||
1716 | goto out; | ||
1717 | cx_write(MO_PCI_INTSTAT, status); | ||
1718 | handled = 1; | ||
1719 | |||
1720 | if (status & core->pci_irqmask) | ||
1721 | cx88_core_irq(core,status); | ||
1722 | if (status & PCI_INT_VIDINT) | ||
1723 | cx8800_vid_irq(dev); | ||
1724 | }; | ||
1725 | if (10 == loop) { | ||
1726 | printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", | ||
1727 | core->name); | ||
1728 | cx_write(MO_PCI_INTMSK,0); | ||
1729 | } | ||
1730 | |||
1731 | out: | ||
1732 | return IRQ_RETVAL(handled); | ||
1733 | } | ||
1734 | |||
1735 | /* ----------------------------------------------------------- */ | ||
1736 | /* exported stuff */ | ||
1737 | |||
1738 | static const struct v4l2_file_operations video_fops = | ||
1739 | { | ||
1740 | .owner = THIS_MODULE, | ||
1741 | .open = video_open, | ||
1742 | .release = video_release, | ||
1743 | .read = video_read, | ||
1744 | .poll = video_poll, | ||
1745 | .mmap = video_mmap, | ||
1746 | .unlocked_ioctl = video_ioctl2, | ||
1747 | }; | ||
1748 | |||
1749 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | ||
1750 | .vidioc_querycap = vidioc_querycap, | ||
1751 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1752 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1753 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1754 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1755 | .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, | ||
1756 | .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, | ||
1757 | .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, | ||
1758 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1759 | .vidioc_querybuf = vidioc_querybuf, | ||
1760 | .vidioc_qbuf = vidioc_qbuf, | ||
1761 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1762 | .vidioc_s_std = vidioc_s_std, | ||
1763 | .vidioc_enum_input = vidioc_enum_input, | ||
1764 | .vidioc_g_input = vidioc_g_input, | ||
1765 | .vidioc_s_input = vidioc_s_input, | ||
1766 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1767 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1768 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1769 | .vidioc_streamon = vidioc_streamon, | ||
1770 | .vidioc_streamoff = vidioc_streamoff, | ||
1771 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1772 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1773 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1774 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1775 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1776 | .vidioc_g_register = vidioc_g_register, | ||
1777 | .vidioc_s_register = vidioc_s_register, | ||
1778 | #endif | ||
1779 | }; | ||
1780 | |||
1781 | static struct video_device cx8800_vbi_template; | ||
1782 | |||
1783 | static const struct video_device cx8800_video_template = { | ||
1784 | .name = "cx8800-video", | ||
1785 | .fops = &video_fops, | ||
1786 | .ioctl_ops = &video_ioctl_ops, | ||
1787 | .tvnorms = CX88_NORMS, | ||
1788 | .current_norm = V4L2_STD_NTSC_M, | ||
1789 | }; | ||
1790 | |||
1791 | static const struct v4l2_file_operations radio_fops = | ||
1792 | { | ||
1793 | .owner = THIS_MODULE, | ||
1794 | .open = video_open, | ||
1795 | .release = video_release, | ||
1796 | .unlocked_ioctl = video_ioctl2, | ||
1797 | }; | ||
1798 | |||
1799 | static const struct v4l2_ioctl_ops radio_ioctl_ops = { | ||
1800 | .vidioc_querycap = radio_querycap, | ||
1801 | .vidioc_g_tuner = radio_g_tuner, | ||
1802 | .vidioc_enum_input = radio_enum_input, | ||
1803 | .vidioc_g_audio = radio_g_audio, | ||
1804 | .vidioc_s_tuner = radio_s_tuner, | ||
1805 | .vidioc_s_audio = radio_s_audio, | ||
1806 | .vidioc_s_input = radio_s_input, | ||
1807 | .vidioc_queryctrl = radio_queryctrl, | ||
1808 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1809 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1810 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1811 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1812 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1813 | .vidioc_g_register = vidioc_g_register, | ||
1814 | .vidioc_s_register = vidioc_s_register, | ||
1815 | #endif | ||
1816 | }; | ||
1817 | |||
1818 | static const struct video_device cx8800_radio_template = { | ||
1819 | .name = "cx8800-radio", | ||
1820 | .fops = &radio_fops, | ||
1821 | .ioctl_ops = &radio_ioctl_ops, | ||
1822 | }; | ||
1823 | |||
1824 | /* ----------------------------------------------------------- */ | ||
1825 | |||
1826 | static void cx8800_unregister_video(struct cx8800_dev *dev) | ||
1827 | { | ||
1828 | if (dev->radio_dev) { | ||
1829 | if (video_is_registered(dev->radio_dev)) | ||
1830 | video_unregister_device(dev->radio_dev); | ||
1831 | else | ||
1832 | video_device_release(dev->radio_dev); | ||
1833 | dev->radio_dev = NULL; | ||
1834 | } | ||
1835 | if (dev->vbi_dev) { | ||
1836 | if (video_is_registered(dev->vbi_dev)) | ||
1837 | video_unregister_device(dev->vbi_dev); | ||
1838 | else | ||
1839 | video_device_release(dev->vbi_dev); | ||
1840 | dev->vbi_dev = NULL; | ||
1841 | } | ||
1842 | if (dev->video_dev) { | ||
1843 | if (video_is_registered(dev->video_dev)) | ||
1844 | video_unregister_device(dev->video_dev); | ||
1845 | else | ||
1846 | video_device_release(dev->video_dev); | ||
1847 | dev->video_dev = NULL; | ||
1848 | } | ||
1849 | } | ||
1850 | |||
1851 | static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | ||
1852 | const struct pci_device_id *pci_id) | ||
1853 | { | ||
1854 | struct cx8800_dev *dev; | ||
1855 | struct cx88_core *core; | ||
1856 | |||
1857 | int err; | ||
1858 | |||
1859 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); | ||
1860 | if (NULL == dev) | ||
1861 | return -ENOMEM; | ||
1862 | |||
1863 | /* pci init */ | ||
1864 | dev->pci = pci_dev; | ||
1865 | if (pci_enable_device(pci_dev)) { | ||
1866 | err = -EIO; | ||
1867 | goto fail_free; | ||
1868 | } | ||
1869 | core = cx88_core_get(dev->pci); | ||
1870 | if (NULL == core) { | ||
1871 | err = -EINVAL; | ||
1872 | goto fail_free; | ||
1873 | } | ||
1874 | dev->core = core; | ||
1875 | |||
1876 | /* print pci info */ | ||
1877 | dev->pci_rev = pci_dev->revision; | ||
1878 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | ||
1879 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " | ||
1880 | "latency: %d, mmio: 0x%llx\n", core->name, | ||
1881 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, | ||
1882 | dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); | ||
1883 | |||
1884 | pci_set_master(pci_dev); | ||
1885 | if (!pci_dma_supported(pci_dev,DMA_BIT_MASK(32))) { | ||
1886 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); | ||
1887 | err = -EIO; | ||
1888 | goto fail_core; | ||
1889 | } | ||
1890 | |||
1891 | /* Initialize VBI template */ | ||
1892 | memcpy( &cx8800_vbi_template, &cx8800_video_template, | ||
1893 | sizeof(cx8800_vbi_template) ); | ||
1894 | strcpy(cx8800_vbi_template.name,"cx8800-vbi"); | ||
1895 | |||
1896 | /* initialize driver struct */ | ||
1897 | spin_lock_init(&dev->slock); | ||
1898 | core->tvnorm = cx8800_video_template.current_norm; | ||
1899 | |||
1900 | /* init video dma queues */ | ||
1901 | INIT_LIST_HEAD(&dev->vidq.active); | ||
1902 | INIT_LIST_HEAD(&dev->vidq.queued); | ||
1903 | dev->vidq.timeout.function = cx8800_vid_timeout; | ||
1904 | dev->vidq.timeout.data = (unsigned long)dev; | ||
1905 | init_timer(&dev->vidq.timeout); | ||
1906 | cx88_risc_stopper(dev->pci,&dev->vidq.stopper, | ||
1907 | MO_VID_DMACNTRL,0x11,0x00); | ||
1908 | |||
1909 | /* init vbi dma queues */ | ||
1910 | INIT_LIST_HEAD(&dev->vbiq.active); | ||
1911 | INIT_LIST_HEAD(&dev->vbiq.queued); | ||
1912 | dev->vbiq.timeout.function = cx8800_vbi_timeout; | ||
1913 | dev->vbiq.timeout.data = (unsigned long)dev; | ||
1914 | init_timer(&dev->vbiq.timeout); | ||
1915 | cx88_risc_stopper(dev->pci,&dev->vbiq.stopper, | ||
1916 | MO_VID_DMACNTRL,0x88,0x00); | ||
1917 | |||
1918 | /* get irq */ | ||
1919 | err = request_irq(pci_dev->irq, cx8800_irq, | ||
1920 | IRQF_SHARED | IRQF_DISABLED, core->name, dev); | ||
1921 | if (err < 0) { | ||
1922 | printk(KERN_ERR "%s/0: can't get IRQ %d\n", | ||
1923 | core->name,pci_dev->irq); | ||
1924 | goto fail_core; | ||
1925 | } | ||
1926 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); | ||
1927 | |||
1928 | /* load and configure helper modules */ | ||
1929 | |||
1930 | if (core->board.audio_chip == V4L2_IDENT_WM8775) { | ||
1931 | struct i2c_board_info wm8775_info = { | ||
1932 | .type = "wm8775", | ||
1933 | .addr = 0x36 >> 1, | ||
1934 | .platform_data = &core->wm8775_data, | ||
1935 | }; | ||
1936 | struct v4l2_subdev *sd; | ||
1937 | |||
1938 | if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1) | ||
1939 | core->wm8775_data.is_nova_s = true; | ||
1940 | else | ||
1941 | core->wm8775_data.is_nova_s = false; | ||
1942 | |||
1943 | sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap, | ||
1944 | &wm8775_info, NULL); | ||
1945 | if (sd != NULL) | ||
1946 | sd->grp_id = WM8775_GID; | ||
1947 | } | ||
1948 | |||
1949 | if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { | ||
1950 | /* This probes for a tda9874 as is used on some | ||
1951 | Pixelview Ultra boards. */ | ||
1952 | v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, | ||
1953 | "tvaudio", 0, I2C_ADDRS(0xb0 >> 1)); | ||
1954 | } | ||
1955 | |||
1956 | switch (core->boardnr) { | ||
1957 | case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: | ||
1958 | case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: { | ||
1959 | static const struct i2c_board_info rtc_info = { | ||
1960 | I2C_BOARD_INFO("isl1208", 0x6f) | ||
1961 | }; | ||
1962 | |||
1963 | request_module("rtc-isl1208"); | ||
1964 | core->i2c_rtc = i2c_new_device(&core->i2c_adap, &rtc_info); | ||
1965 | } | ||
1966 | /* break intentionally omitted */ | ||
1967 | case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: | ||
1968 | request_module("ir-kbd-i2c"); | ||
1969 | } | ||
1970 | |||
1971 | /* Sets device info at pci_dev */ | ||
1972 | pci_set_drvdata(pci_dev, dev); | ||
1973 | |||
1974 | /* initial device configuration */ | ||
1975 | mutex_lock(&core->lock); | ||
1976 | cx88_set_tvnorm(core, core->tvnorm); | ||
1977 | init_controls(core); | ||
1978 | cx88_video_mux(core, 0); | ||
1979 | |||
1980 | /* register v4l devices */ | ||
1981 | dev->video_dev = cx88_vdev_init(core,dev->pci, | ||
1982 | &cx8800_video_template,"video"); | ||
1983 | video_set_drvdata(dev->video_dev, dev); | ||
1984 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, | ||
1985 | video_nr[core->nr]); | ||
1986 | if (err < 0) { | ||
1987 | printk(KERN_ERR "%s/0: can't register video device\n", | ||
1988 | core->name); | ||
1989 | goto fail_unreg; | ||
1990 | } | ||
1991 | printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", | ||
1992 | core->name, video_device_node_name(dev->video_dev)); | ||
1993 | |||
1994 | dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); | ||
1995 | video_set_drvdata(dev->vbi_dev, dev); | ||
1996 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, | ||
1997 | vbi_nr[core->nr]); | ||
1998 | if (err < 0) { | ||
1999 | printk(KERN_ERR "%s/0: can't register vbi device\n", | ||
2000 | core->name); | ||
2001 | goto fail_unreg; | ||
2002 | } | ||
2003 | printk(KERN_INFO "%s/0: registered device %s\n", | ||
2004 | core->name, video_device_node_name(dev->vbi_dev)); | ||
2005 | |||
2006 | if (core->board.radio.type == CX88_RADIO) { | ||
2007 | dev->radio_dev = cx88_vdev_init(core,dev->pci, | ||
2008 | &cx8800_radio_template,"radio"); | ||
2009 | video_set_drvdata(dev->radio_dev, dev); | ||
2010 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, | ||
2011 | radio_nr[core->nr]); | ||
2012 | if (err < 0) { | ||
2013 | printk(KERN_ERR "%s/0: can't register radio device\n", | ||
2014 | core->name); | ||
2015 | goto fail_unreg; | ||
2016 | } | ||
2017 | printk(KERN_INFO "%s/0: registered device %s\n", | ||
2018 | core->name, video_device_node_name(dev->radio_dev)); | ||
2019 | } | ||
2020 | |||
2021 | /* start tvaudio thread */ | ||
2022 | if (core->board.tuner_type != TUNER_ABSENT) { | ||
2023 | core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); | ||
2024 | if (IS_ERR(core->kthread)) { | ||
2025 | err = PTR_ERR(core->kthread); | ||
2026 | printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", | ||
2027 | core->name, err); | ||
2028 | } | ||
2029 | } | ||
2030 | mutex_unlock(&core->lock); | ||
2031 | |||
2032 | return 0; | ||
2033 | |||
2034 | fail_unreg: | ||
2035 | cx8800_unregister_video(dev); | ||
2036 | free_irq(pci_dev->irq, dev); | ||
2037 | mutex_unlock(&core->lock); | ||
2038 | fail_core: | ||
2039 | cx88_core_put(core,dev->pci); | ||
2040 | fail_free: | ||
2041 | kfree(dev); | ||
2042 | return err; | ||
2043 | } | ||
2044 | |||
2045 | static void __devexit cx8800_finidev(struct pci_dev *pci_dev) | ||
2046 | { | ||
2047 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | ||
2048 | struct cx88_core *core = dev->core; | ||
2049 | |||
2050 | /* stop thread */ | ||
2051 | if (core->kthread) { | ||
2052 | kthread_stop(core->kthread); | ||
2053 | core->kthread = NULL; | ||
2054 | } | ||
2055 | |||
2056 | if (core->ir) | ||
2057 | cx88_ir_stop(core); | ||
2058 | |||
2059 | cx88_shutdown(core); /* FIXME */ | ||
2060 | pci_disable_device(pci_dev); | ||
2061 | |||
2062 | /* unregister stuff */ | ||
2063 | |||
2064 | free_irq(pci_dev->irq, dev); | ||
2065 | cx8800_unregister_video(dev); | ||
2066 | pci_set_drvdata(pci_dev, NULL); | ||
2067 | |||
2068 | /* free memory */ | ||
2069 | btcx_riscmem_free(dev->pci,&dev->vidq.stopper); | ||
2070 | cx88_core_put(core,dev->pci); | ||
2071 | kfree(dev); | ||
2072 | } | ||
2073 | |||
2074 | #ifdef CONFIG_PM | ||
2075 | static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) | ||
2076 | { | ||
2077 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | ||
2078 | struct cx88_core *core = dev->core; | ||
2079 | |||
2080 | /* stop video+vbi capture */ | ||
2081 | spin_lock(&dev->slock); | ||
2082 | if (!list_empty(&dev->vidq.active)) { | ||
2083 | printk("%s/0: suspend video\n", core->name); | ||
2084 | stop_video_dma(dev); | ||
2085 | del_timer(&dev->vidq.timeout); | ||
2086 | } | ||
2087 | if (!list_empty(&dev->vbiq.active)) { | ||
2088 | printk("%s/0: suspend vbi\n", core->name); | ||
2089 | cx8800_stop_vbi_dma(dev); | ||
2090 | del_timer(&dev->vbiq.timeout); | ||
2091 | } | ||
2092 | spin_unlock(&dev->slock); | ||
2093 | |||
2094 | if (core->ir) | ||
2095 | cx88_ir_stop(core); | ||
2096 | /* FIXME -- shutdown device */ | ||
2097 | cx88_shutdown(core); | ||
2098 | |||
2099 | pci_save_state(pci_dev); | ||
2100 | if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { | ||
2101 | pci_disable_device(pci_dev); | ||
2102 | dev->state.disabled = 1; | ||
2103 | } | ||
2104 | return 0; | ||
2105 | } | ||
2106 | |||
2107 | static int cx8800_resume(struct pci_dev *pci_dev) | ||
2108 | { | ||
2109 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | ||
2110 | struct cx88_core *core = dev->core; | ||
2111 | int err; | ||
2112 | |||
2113 | if (dev->state.disabled) { | ||
2114 | err=pci_enable_device(pci_dev); | ||
2115 | if (err) { | ||
2116 | printk(KERN_ERR "%s/0: can't enable device\n", | ||
2117 | core->name); | ||
2118 | return err; | ||
2119 | } | ||
2120 | |||
2121 | dev->state.disabled = 0; | ||
2122 | } | ||
2123 | err= pci_set_power_state(pci_dev, PCI_D0); | ||
2124 | if (err) { | ||
2125 | printk(KERN_ERR "%s/0: can't set power state\n", core->name); | ||
2126 | pci_disable_device(pci_dev); | ||
2127 | dev->state.disabled = 1; | ||
2128 | |||
2129 | return err; | ||
2130 | } | ||
2131 | pci_restore_state(pci_dev); | ||
2132 | |||
2133 | /* FIXME: re-initialize hardware */ | ||
2134 | cx88_reset(core); | ||
2135 | if (core->ir) | ||
2136 | cx88_ir_start(core); | ||
2137 | |||
2138 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); | ||
2139 | |||
2140 | /* restart video+vbi capture */ | ||
2141 | spin_lock(&dev->slock); | ||
2142 | if (!list_empty(&dev->vidq.active)) { | ||
2143 | printk("%s/0: resume video\n", core->name); | ||
2144 | restart_video_queue(dev,&dev->vidq); | ||
2145 | } | ||
2146 | if (!list_empty(&dev->vbiq.active)) { | ||
2147 | printk("%s/0: resume vbi\n", core->name); | ||
2148 | cx8800_restart_vbi_queue(dev,&dev->vbiq); | ||
2149 | } | ||
2150 | spin_unlock(&dev->slock); | ||
2151 | |||
2152 | return 0; | ||
2153 | } | ||
2154 | #endif | ||
2155 | |||
2156 | /* ----------------------------------------------------------- */ | ||
2157 | |||
2158 | static const struct pci_device_id cx8800_pci_tbl[] = { | ||
2159 | { | ||
2160 | .vendor = 0x14f1, | ||
2161 | .device = 0x8800, | ||
2162 | .subvendor = PCI_ANY_ID, | ||
2163 | .subdevice = PCI_ANY_ID, | ||
2164 | },{ | ||
2165 | /* --- end of list --- */ | ||
2166 | } | ||
2167 | }; | ||
2168 | MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl); | ||
2169 | |||
2170 | static struct pci_driver cx8800_pci_driver = { | ||
2171 | .name = "cx8800", | ||
2172 | .id_table = cx8800_pci_tbl, | ||
2173 | .probe = cx8800_initdev, | ||
2174 | .remove = __devexit_p(cx8800_finidev), | ||
2175 | #ifdef CONFIG_PM | ||
2176 | .suspend = cx8800_suspend, | ||
2177 | .resume = cx8800_resume, | ||
2178 | #endif | ||
2179 | }; | ||
2180 | |||
2181 | static int __init cx8800_init(void) | ||
2182 | { | ||
2183 | printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %s loaded\n", | ||
2184 | CX88_VERSION); | ||
2185 | return pci_register_driver(&cx8800_pci_driver); | ||
2186 | } | ||
2187 | |||
2188 | static void __exit cx8800_fini(void) | ||
2189 | { | ||
2190 | pci_unregister_driver(&cx8800_pci_driver); | ||
2191 | } | ||
2192 | |||
2193 | module_init(cx8800_init); | ||
2194 | module_exit(cx8800_fini); | ||