1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // DVB USB compliant linux driver for Conexant USB reference design - |
4 | // (analog part). |
5 | // |
6 | // Copyright (C) 2011, 2017, 2018 |
7 | // Maciej S. Szmigiero (mail@maciej.szmigiero.name) |
8 | // |
9 | // In case there are new analog / DVB-T hybrid devices released in the market |
10 | // using the same general design as Medion MD95700: a CX25840 video decoder |
11 | // outputting a BT.656 stream to a USB bridge chip which then forwards it to |
12 | // the host in isochronous USB packets this code should be made generic, with |
13 | // board specific bits implemented via separate card structures. |
14 | // |
15 | // This is, however, unlikely as the Medion model was released |
16 | // years ago (in 2005). |
17 | // |
18 | // TODO: |
19 | // * audio support, |
20 | // * finish radio support (requires audio of course), |
21 | // * VBI support, |
22 | // * controls support |
23 | |
24 | #include <linux/bitops.h> |
25 | #include <linux/device.h> |
26 | #include <linux/slab.h> |
27 | #include <linux/string.h> |
28 | #include <linux/ktime.h> |
29 | #include <linux/vmalloc.h> |
30 | #include <media/drv-intf/cx25840.h> |
31 | #include <media/tuner.h> |
32 | #include <media/v4l2-fh.h> |
33 | #include <media/v4l2-ioctl.h> |
34 | #include <media/v4l2-subdev.h> |
35 | #include <media/videobuf2-vmalloc.h> |
36 | |
37 | #include "cxusb.h" |
38 | |
39 | static int cxusb_medion_v_queue_setup(struct vb2_queue *q, |
40 | unsigned int *num_buffers, |
41 | unsigned int *num_planes, |
42 | unsigned int sizes[], |
43 | struct device *alloc_devs[]) |
44 | { |
45 | struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); |
46 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
47 | unsigned int size = cxdev->width * cxdev->height * 2; |
48 | |
49 | if (*num_planes > 0) { |
50 | if (*num_planes != 1) |
51 | return -EINVAL; |
52 | |
53 | if (sizes[0] < size) |
54 | return -EINVAL; |
55 | } else { |
56 | *num_planes = 1; |
57 | sizes[0] = size; |
58 | } |
59 | |
60 | return 0; |
61 | } |
62 | |
63 | static int cxusb_medion_v_buf_init(struct vb2_buffer *vb) |
64 | { |
65 | struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q: vb->vb2_queue); |
66 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
67 | |
68 | cxusb_vprintk(dvbdev, OPS, "buffer init\n" ); |
69 | |
70 | if (vb2_plane_size(vb, plane_no: 0) < cxdev->width * cxdev->height * 2) |
71 | return -ENOMEM; |
72 | |
73 | cxusb_vprintk(dvbdev, OPS, "buffer OK\n" ); |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | static void cxusb_auxbuf_init(struct dvb_usb_device *dvbdev, |
79 | struct cxusb_medion_auxbuf *auxbuf, |
80 | u8 *buf, unsigned int len) |
81 | { |
82 | cxusb_vprintk(dvbdev, AUXB, "initializing auxbuf of len %u\n" , len); |
83 | |
84 | auxbuf->buf = buf; |
85 | auxbuf->len = len; |
86 | auxbuf->paylen = 0; |
87 | } |
88 | |
89 | static void cxusb_auxbuf_head_trim(struct dvb_usb_device *dvbdev, |
90 | struct cxusb_medion_auxbuf *auxbuf, |
91 | unsigned int pos) |
92 | { |
93 | if (pos == 0) |
94 | return; |
95 | |
96 | if (WARN_ON(pos > auxbuf->paylen)) |
97 | return; |
98 | |
99 | cxusb_vprintk(dvbdev, AUXB, |
100 | "trimming auxbuf len by %u to %u\n" , |
101 | pos, auxbuf->paylen - pos); |
102 | |
103 | memmove(auxbuf->buf, auxbuf->buf + pos, auxbuf->paylen - pos); |
104 | auxbuf->paylen -= pos; |
105 | } |
106 | |
107 | static unsigned int cxusb_auxbuf_paylen(struct cxusb_medion_auxbuf *auxbuf) |
108 | { |
109 | return auxbuf->paylen; |
110 | } |
111 | |
112 | static bool cxusb_auxbuf_make_space(struct dvb_usb_device *dvbdev, |
113 | struct cxusb_medion_auxbuf *auxbuf, |
114 | unsigned int howmuch) |
115 | { |
116 | unsigned int freespace; |
117 | |
118 | if (WARN_ON(howmuch >= auxbuf->len)) |
119 | howmuch = auxbuf->len - 1; |
120 | |
121 | freespace = auxbuf->len - cxusb_auxbuf_paylen(auxbuf); |
122 | |
123 | cxusb_vprintk(dvbdev, AUXB, "freespace is %u\n" , freespace); |
124 | |
125 | if (freespace >= howmuch) |
126 | return true; |
127 | |
128 | howmuch -= freespace; |
129 | |
130 | cxusb_vprintk(dvbdev, AUXB, "will overwrite %u bytes of buffer\n" , |
131 | howmuch); |
132 | |
133 | cxusb_auxbuf_head_trim(dvbdev, auxbuf, pos: howmuch); |
134 | |
135 | return false; |
136 | } |
137 | |
138 | /* returns false if some data was overwritten */ |
139 | static bool cxusb_auxbuf_append_urb(struct dvb_usb_device *dvbdev, |
140 | struct cxusb_medion_auxbuf *auxbuf, |
141 | struct urb *urb) |
142 | { |
143 | unsigned long len; |
144 | int i; |
145 | bool ret; |
146 | |
147 | for (i = 0, len = 0; i < urb->number_of_packets; i++) |
148 | len += urb->iso_frame_desc[i].actual_length; |
149 | |
150 | ret = cxusb_auxbuf_make_space(dvbdev, auxbuf, howmuch: len); |
151 | |
152 | for (i = 0; i < urb->number_of_packets; i++) { |
153 | unsigned int to_copy; |
154 | |
155 | to_copy = urb->iso_frame_desc[i].actual_length; |
156 | |
157 | memcpy(auxbuf->buf + auxbuf->paylen, urb->transfer_buffer + |
158 | urb->iso_frame_desc[i].offset, to_copy); |
159 | |
160 | auxbuf->paylen += to_copy; |
161 | } |
162 | |
163 | return ret; |
164 | } |
165 | |
166 | static bool cxusb_auxbuf_copy(struct cxusb_medion_auxbuf *auxbuf, |
167 | unsigned int pos, unsigned char *dest, |
168 | unsigned int len) |
169 | { |
170 | if (pos + len > auxbuf->paylen) |
171 | return false; |
172 | |
173 | memcpy(dest, auxbuf->buf + pos, len); |
174 | |
175 | return true; |
176 | } |
177 | |
178 | static bool cxusb_medion_cf_refc_fld_chg(struct dvb_usb_device *dvbdev, |
179 | struct cxusb_bt656_params *bt656, |
180 | bool firstfield, |
181 | unsigned int maxlines, |
182 | unsigned int maxlinesamples, |
183 | unsigned char buf[4]) |
184 | { |
185 | bool firstfield_code = (buf[3] & CXUSB_BT656_FIELD_MASK) == |
186 | CXUSB_BT656_FIELD_1; |
187 | unsigned int remlines; |
188 | |
189 | if (bt656->line == 0 || firstfield == firstfield_code) |
190 | return false; |
191 | |
192 | if (bt656->fmode == LINE_SAMPLES) { |
193 | unsigned int remsamples = maxlinesamples - |
194 | bt656->linesamples; |
195 | |
196 | cxusb_vprintk(dvbdev, BT656, |
197 | "field %c after line %u field change\n" , |
198 | firstfield ? '1' : '2', bt656->line); |
199 | |
200 | if (bt656->buf && remsamples > 0) { |
201 | memset(bt656->buf, 0, remsamples); |
202 | bt656->buf += remsamples; |
203 | |
204 | cxusb_vprintk(dvbdev, BT656, |
205 | "field %c line %u %u samples still remaining (of %u)\n" , |
206 | firstfield ? '1' : '2', |
207 | bt656->line, remsamples, |
208 | maxlinesamples); |
209 | } |
210 | |
211 | bt656->line++; |
212 | } |
213 | |
214 | remlines = maxlines - bt656->line; |
215 | if (bt656->buf && remlines > 0) { |
216 | memset(bt656->buf, 0, remlines * maxlinesamples); |
217 | bt656->buf += remlines * maxlinesamples; |
218 | |
219 | cxusb_vprintk(dvbdev, BT656, |
220 | "field %c %u lines still remaining (of %u)\n" , |
221 | firstfield ? '1' : '2', remlines, |
222 | maxlines); |
223 | } |
224 | |
225 | return true; |
226 | } |
227 | |
228 | static void cxusb_medion_cf_refc_start_sch(struct dvb_usb_device *dvbdev, |
229 | struct cxusb_bt656_params *bt656, |
230 | bool firstfield, |
231 | unsigned char buf[4]) |
232 | { |
233 | bool firstfield_code = (buf[3] & CXUSB_BT656_FIELD_MASK) == |
234 | CXUSB_BT656_FIELD_1; |
235 | bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == |
236 | CXUSB_BT656_SEAV_SAV; |
237 | bool vbi_code = (buf[3] & CXUSB_BT656_VBI_MASK) == |
238 | CXUSB_BT656_VBI_ON; |
239 | |
240 | if (!sav_code || firstfield != firstfield_code) |
241 | return; |
242 | |
243 | if (!vbi_code) { |
244 | cxusb_vprintk(dvbdev, BT656, "line start @ pos %u\n" , |
245 | bt656->pos); |
246 | |
247 | bt656->linesamples = 0; |
248 | bt656->fmode = LINE_SAMPLES; |
249 | } else { |
250 | cxusb_vprintk(dvbdev, BT656, "VBI start @ pos %u\n" , |
251 | bt656->pos); |
252 | |
253 | bt656->fmode = VBI_SAMPLES; |
254 | } |
255 | } |
256 | |
257 | static void cxusb_medion_cf_refc_line_smpl(struct dvb_usb_device *dvbdev, |
258 | struct cxusb_bt656_params *bt656, |
259 | bool firstfield, |
260 | unsigned int maxlinesamples, |
261 | unsigned char buf[4]) |
262 | { |
263 | bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == |
264 | CXUSB_BT656_SEAV_SAV; |
265 | unsigned int remsamples; |
266 | |
267 | if (sav_code) |
268 | cxusb_vprintk(dvbdev, BT656, |
269 | "SAV in line samples @ line %u, pos %u\n" , |
270 | bt656->line, bt656->pos); |
271 | |
272 | remsamples = maxlinesamples - bt656->linesamples; |
273 | if (bt656->buf && remsamples > 0) { |
274 | memset(bt656->buf, 0, remsamples); |
275 | bt656->buf += remsamples; |
276 | |
277 | cxusb_vprintk(dvbdev, BT656, |
278 | "field %c line %u %u samples still remaining (of %u)\n" , |
279 | firstfield ? '1' : '2', bt656->line, remsamples, |
280 | maxlinesamples); |
281 | } |
282 | |
283 | bt656->fmode = START_SEARCH; |
284 | bt656->line++; |
285 | } |
286 | |
287 | static void cxusb_medion_cf_refc_vbi_smpl(struct dvb_usb_device *dvbdev, |
288 | struct cxusb_bt656_params *bt656, |
289 | unsigned char buf[4]) |
290 | { |
291 | bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == |
292 | CXUSB_BT656_SEAV_SAV; |
293 | |
294 | if (sav_code) |
295 | cxusb_vprintk(dvbdev, BT656, "SAV in VBI samples @ pos %u\n" , |
296 | bt656->pos); |
297 | |
298 | bt656->fmode = START_SEARCH; |
299 | } |
300 | |
301 | /* returns whether the whole 4-byte code should be skipped in the buffer */ |
302 | static bool cxusb_medion_cf_ref_code(struct dvb_usb_device *dvbdev, |
303 | struct cxusb_bt656_params *bt656, |
304 | bool firstfield, |
305 | unsigned int maxlines, |
306 | unsigned int maxlinesamples, |
307 | unsigned char buf[4]) |
308 | { |
309 | if (bt656->fmode == START_SEARCH) { |
310 | cxusb_medion_cf_refc_start_sch(dvbdev, bt656, firstfield, buf); |
311 | } else if (bt656->fmode == LINE_SAMPLES) { |
312 | cxusb_medion_cf_refc_line_smpl(dvbdev, bt656, firstfield, |
313 | maxlinesamples, buf); |
314 | return false; |
315 | } else if (bt656->fmode == VBI_SAMPLES) { |
316 | cxusb_medion_cf_refc_vbi_smpl(dvbdev, bt656, buf); |
317 | return false; |
318 | } |
319 | |
320 | return true; |
321 | } |
322 | |
323 | static bool cxusb_medion_cs_start_sch(struct dvb_usb_device *dvbdev, |
324 | struct cxusb_medion_auxbuf *auxbuf, |
325 | struct cxusb_bt656_params *bt656, |
326 | unsigned int maxlinesamples) |
327 | { |
328 | unsigned char buf[64]; |
329 | unsigned int idx; |
330 | unsigned int tocheck = clamp_t(size_t, maxlinesamples / 4, 3, |
331 | sizeof(buf)); |
332 | |
333 | if (!cxusb_auxbuf_copy(auxbuf, pos: bt656->pos + 1, dest: buf, len: tocheck)) |
334 | return false; |
335 | |
336 | for (idx = 0; idx <= tocheck - 3; idx++) |
337 | if (memcmp(p: buf + idx, CXUSB_BT656_PREAMBLE, size: 3) == 0) { |
338 | bt656->pos += (1 + idx); |
339 | return true; |
340 | } |
341 | |
342 | cxusb_vprintk(dvbdev, BT656, "line %u early start, pos %u\n" , |
343 | bt656->line, bt656->pos); |
344 | |
345 | bt656->linesamples = 0; |
346 | bt656->fmode = LINE_SAMPLES; |
347 | |
348 | return true; |
349 | } |
350 | |
351 | static void cxusb_medion_cs_line_smpl(struct cxusb_bt656_params *bt656, |
352 | unsigned int maxlinesamples, |
353 | unsigned char val) |
354 | { |
355 | if (bt656->buf) |
356 | *(bt656->buf++) = val; |
357 | |
358 | bt656->linesamples++; |
359 | bt656->pos++; |
360 | |
361 | if (bt656->linesamples >= maxlinesamples) { |
362 | bt656->fmode = START_SEARCH; |
363 | bt656->line++; |
364 | } |
365 | } |
366 | |
367 | static bool cxusb_medion_copy_samples(struct dvb_usb_device *dvbdev, |
368 | struct cxusb_medion_auxbuf *auxbuf, |
369 | struct cxusb_bt656_params *bt656, |
370 | unsigned int maxlinesamples, |
371 | unsigned char val) |
372 | { |
373 | if (bt656->fmode == START_SEARCH && bt656->line > 0) |
374 | return cxusb_medion_cs_start_sch(dvbdev, auxbuf, bt656, |
375 | maxlinesamples); |
376 | else if (bt656->fmode == LINE_SAMPLES) |
377 | cxusb_medion_cs_line_smpl(bt656, maxlinesamples, val); |
378 | else /* TODO: copy VBI samples */ |
379 | bt656->pos++; |
380 | |
381 | return true; |
382 | } |
383 | |
384 | static bool cxusb_medion_copy_field(struct dvb_usb_device *dvbdev, |
385 | struct cxusb_medion_auxbuf *auxbuf, |
386 | struct cxusb_bt656_params *bt656, |
387 | bool firstfield, |
388 | unsigned int maxlines, |
389 | unsigned int maxlinesmpls) |
390 | { |
391 | while (bt656->line < maxlines) { |
392 | unsigned char val; |
393 | |
394 | if (!cxusb_auxbuf_copy(auxbuf, pos: bt656->pos, dest: &val, len: 1)) |
395 | break; |
396 | |
397 | if (val == CXUSB_BT656_PREAMBLE[0]) { |
398 | unsigned char buf[4]; |
399 | |
400 | buf[0] = val; |
401 | if (!cxusb_auxbuf_copy(auxbuf, pos: bt656->pos + 1, |
402 | dest: buf + 1, len: 3)) |
403 | break; |
404 | |
405 | if (buf[1] == CXUSB_BT656_PREAMBLE[1] && |
406 | buf[2] == CXUSB_BT656_PREAMBLE[2]) { |
407 | /* |
408 | * is this a field change? |
409 | * if so, terminate copying the current field |
410 | */ |
411 | if (cxusb_medion_cf_refc_fld_chg(dvbdev, |
412 | bt656, |
413 | firstfield, |
414 | maxlines, |
415 | maxlinesamples: maxlinesmpls, |
416 | buf)) |
417 | return true; |
418 | |
419 | if (cxusb_medion_cf_ref_code(dvbdev, bt656, |
420 | firstfield, |
421 | maxlines, |
422 | maxlinesamples: maxlinesmpls, |
423 | buf)) |
424 | bt656->pos += 4; |
425 | |
426 | continue; |
427 | } |
428 | } |
429 | |
430 | if (!cxusb_medion_copy_samples(dvbdev, auxbuf, bt656, |
431 | maxlinesamples: maxlinesmpls, val)) |
432 | break; |
433 | } |
434 | |
435 | if (bt656->line < maxlines) { |
436 | cxusb_vprintk(dvbdev, BT656, |
437 | "end of buffer pos = %u, line = %u\n" , |
438 | bt656->pos, bt656->line); |
439 | return false; |
440 | } |
441 | |
442 | return true; |
443 | } |
444 | |
445 | static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev, |
446 | bool reset) |
447 | { |
448 | struct dvb_usb_device *dvbdev = cxdev->dvbdev; |
449 | struct cxusb_bt656_params *bt656 = &cxdev->bt656; |
450 | |
451 | /* |
452 | * if this is a new frame |
453 | * fetch a buffer from list |
454 | */ |
455 | if (bt656->mode == NEW_FRAME) { |
456 | if (!list_empty(head: &cxdev->buflist)) { |
457 | cxdev->vbuf = |
458 | list_first_entry(&cxdev->buflist, |
459 | struct cxusb_medion_vbuffer, |
460 | list); |
461 | list_del(entry: &cxdev->vbuf->list); |
462 | } else { |
463 | dev_warn(&dvbdev->udev->dev, "no free buffers\n" ); |
464 | } |
465 | } |
466 | |
467 | if (bt656->mode == NEW_FRAME || reset) { |
468 | cxusb_vprintk(dvbdev, URB, "will copy field 1\n" ); |
469 | bt656->pos = 0; |
470 | bt656->mode = FIRST_FIELD; |
471 | bt656->fmode = START_SEARCH; |
472 | bt656->line = 0; |
473 | |
474 | if (cxdev->vbuf) { |
475 | cxdev->vbuf->vb2.vb2_buf.timestamp = ktime_get_ns(); |
476 | bt656->buf = vb2_plane_vaddr(vb: &cxdev->vbuf->vb2.vb2_buf, |
477 | plane_no: 0); |
478 | } |
479 | } |
480 | |
481 | if (bt656->mode == FIRST_FIELD) { |
482 | if (!cxusb_medion_copy_field(dvbdev, auxbuf: &cxdev->auxbuf, bt656, |
483 | firstfield: true, maxlines: cxdev->height / 2, |
484 | maxlinesmpls: cxdev->width * 2)) |
485 | return false; |
486 | |
487 | /* |
488 | * do not trim buffer there in case |
489 | * we need to reset the search later |
490 | */ |
491 | |
492 | cxusb_vprintk(dvbdev, URB, "will copy field 2\n" ); |
493 | bt656->mode = SECOND_FIELD; |
494 | bt656->fmode = START_SEARCH; |
495 | bt656->line = 0; |
496 | } |
497 | |
498 | if (bt656->mode == SECOND_FIELD) { |
499 | if (!cxusb_medion_copy_field(dvbdev, auxbuf: &cxdev->auxbuf, bt656, |
500 | firstfield: false, maxlines: cxdev->height / 2, |
501 | maxlinesmpls: cxdev->width * 2)) |
502 | return false; |
503 | |
504 | cxusb_auxbuf_head_trim(dvbdev, auxbuf: &cxdev->auxbuf, pos: bt656->pos); |
505 | |
506 | bt656->mode = NEW_FRAME; |
507 | |
508 | if (cxdev->vbuf) { |
509 | vb2_set_plane_payload(vb: &cxdev->vbuf->vb2.vb2_buf, plane_no: 0, |
510 | size: cxdev->width * cxdev->height * 2); |
511 | |
512 | cxdev->vbuf->vb2.field = cxdev->field_order; |
513 | cxdev->vbuf->vb2.sequence = cxdev->vbuf_sequence++; |
514 | |
515 | vb2_buffer_done(vb: &cxdev->vbuf->vb2.vb2_buf, |
516 | state: VB2_BUF_STATE_DONE); |
517 | |
518 | cxdev->vbuf = NULL; |
519 | cxdev->bt656.buf = NULL; |
520 | |
521 | cxusb_vprintk(dvbdev, URB, "frame done\n" ); |
522 | } else { |
523 | cxusb_vprintk(dvbdev, URB, "frame skipped\n" ); |
524 | cxdev->vbuf_sequence++; |
525 | } |
526 | } |
527 | |
528 | return true; |
529 | } |
530 | |
531 | static bool cxusb_medion_v_complete_handle_urb(struct cxusb_medion_dev *cxdev, |
532 | bool *auxbuf_reset) |
533 | { |
534 | struct dvb_usb_device *dvbdev = cxdev->dvbdev; |
535 | unsigned int urbn; |
536 | struct urb *urb; |
537 | int ret; |
538 | |
539 | *auxbuf_reset = false; |
540 | |
541 | urbn = cxdev->nexturb; |
542 | if (!test_bit(urbn, &cxdev->urbcomplete)) |
543 | return false; |
544 | |
545 | clear_bit(nr: urbn, addr: &cxdev->urbcomplete); |
546 | |
547 | do { |
548 | cxdev->nexturb++; |
549 | cxdev->nexturb %= CXUSB_VIDEO_URBS; |
550 | urb = cxdev->streamurbs[cxdev->nexturb]; |
551 | } while (!urb); |
552 | |
553 | urb = cxdev->streamurbs[urbn]; |
554 | cxusb_vprintk(dvbdev, URB, "URB %u status = %d\n" , urbn, urb->status); |
555 | |
556 | if (urb->status == 0 || urb->status == -EXDEV) { |
557 | int i; |
558 | unsigned long len; |
559 | |
560 | for (i = 0, len = 0; i < urb->number_of_packets; i++) |
561 | len += urb->iso_frame_desc[i].actual_length; |
562 | |
563 | cxusb_vprintk(dvbdev, URB, "URB %u data len = %lu\n" , urbn, |
564 | len); |
565 | |
566 | if (len > 0) { |
567 | cxusb_vprintk(dvbdev, URB, "appending URB\n" ); |
568 | |
569 | /* |
570 | * append new data to auxbuf while |
571 | * overwriting old data if necessary |
572 | * |
573 | * if any overwrite happens then we can no |
574 | * longer rely on consistency of the whole |
575 | * data so let's start again the current |
576 | * auxbuf frame assembling process from |
577 | * the beginning |
578 | */ |
579 | *auxbuf_reset = |
580 | !cxusb_auxbuf_append_urb(dvbdev, |
581 | auxbuf: &cxdev->auxbuf, |
582 | urb); |
583 | } |
584 | } |
585 | |
586 | cxusb_vprintk(dvbdev, URB, "URB %u resubmit\n" , urbn); |
587 | |
588 | ret = usb_submit_urb(urb, GFP_KERNEL); |
589 | if (ret != 0) |
590 | dev_err(&dvbdev->udev->dev, |
591 | "unable to resubmit URB %u (%d), you'll have to restart streaming\n" , |
592 | urbn, ret); |
593 | |
594 | /* next URB is complete already? reschedule us then to handle it */ |
595 | return test_bit(cxdev->nexturb, &cxdev->urbcomplete); |
596 | } |
597 | |
598 | static void cxusb_medion_v_complete_work(struct work_struct *work) |
599 | { |
600 | struct cxusb_medion_dev *cxdev = container_of(work, |
601 | struct cxusb_medion_dev, |
602 | urbwork); |
603 | struct dvb_usb_device *dvbdev = cxdev->dvbdev; |
604 | bool auxbuf_reset; |
605 | bool reschedule; |
606 | |
607 | mutex_lock(cxdev->videodev->lock); |
608 | |
609 | cxusb_vprintk(dvbdev, URB, "worker called, stop_streaming = %d\n" , |
610 | (int)cxdev->stop_streaming); |
611 | |
612 | if (cxdev->stop_streaming) |
613 | goto unlock; |
614 | |
615 | reschedule = cxusb_medion_v_complete_handle_urb(cxdev, auxbuf_reset: &auxbuf_reset); |
616 | |
617 | if (cxusb_medion_v_process_auxbuf(cxdev, reset: auxbuf_reset)) |
618 | /* reschedule us until auxbuf no longer can produce any frame */ |
619 | reschedule = true; |
620 | |
621 | if (reschedule) { |
622 | cxusb_vprintk(dvbdev, URB, "rescheduling worker\n" ); |
623 | schedule_work(work: &cxdev->urbwork); |
624 | } |
625 | |
626 | unlock: |
627 | mutex_unlock(lock: cxdev->videodev->lock); |
628 | } |
629 | |
630 | static void cxusb_medion_v_complete(struct urb *u) |
631 | { |
632 | struct dvb_usb_device *dvbdev = u->context; |
633 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
634 | unsigned int i; |
635 | |
636 | for (i = 0; i < CXUSB_VIDEO_URBS; i++) |
637 | if (cxdev->streamurbs[i] == u) |
638 | break; |
639 | |
640 | if (i >= CXUSB_VIDEO_URBS) { |
641 | dev_err(&dvbdev->udev->dev, |
642 | "complete on unknown URB\n" ); |
643 | return; |
644 | } |
645 | |
646 | cxusb_vprintk(dvbdev, URB, "URB %u complete\n" , i); |
647 | |
648 | set_bit(nr: i, addr: &cxdev->urbcomplete); |
649 | schedule_work(work: &cxdev->urbwork); |
650 | } |
651 | |
652 | static void cxusb_medion_urbs_free(struct cxusb_medion_dev *cxdev) |
653 | { |
654 | unsigned int i; |
655 | |
656 | for (i = 0; i < CXUSB_VIDEO_URBS; i++) |
657 | if (cxdev->streamurbs[i]) { |
658 | kfree(objp: cxdev->streamurbs[i]->transfer_buffer); |
659 | usb_free_urb(urb: cxdev->streamurbs[i]); |
660 | cxdev->streamurbs[i] = NULL; |
661 | } |
662 | } |
663 | |
664 | static void cxusb_medion_return_buffers(struct cxusb_medion_dev *cxdev, |
665 | bool requeue) |
666 | { |
667 | struct cxusb_medion_vbuffer *vbuf, *vbuf_tmp; |
668 | |
669 | list_for_each_entry_safe(vbuf, vbuf_tmp, &cxdev->buflist, |
670 | list) { |
671 | list_del(entry: &vbuf->list); |
672 | vb2_buffer_done(vb: &vbuf->vb2.vb2_buf, |
673 | state: requeue ? VB2_BUF_STATE_QUEUED : |
674 | VB2_BUF_STATE_ERROR); |
675 | } |
676 | |
677 | if (cxdev->vbuf) { |
678 | vb2_buffer_done(vb: &cxdev->vbuf->vb2.vb2_buf, |
679 | state: requeue ? VB2_BUF_STATE_QUEUED : |
680 | VB2_BUF_STATE_ERROR); |
681 | |
682 | cxdev->vbuf = NULL; |
683 | cxdev->bt656.buf = NULL; |
684 | } |
685 | } |
686 | |
687 | static int cxusb_medion_v_ss_auxbuf_alloc(struct cxusb_medion_dev *cxdev, |
688 | int *npackets) |
689 | { |
690 | struct dvb_usb_device *dvbdev = cxdev->dvbdev; |
691 | u8 *buf; |
692 | unsigned int framelen, urblen, auxbuflen; |
693 | |
694 | framelen = (cxdev->width * 2 + 4 + 4) * |
695 | (cxdev->height + 50 /* VBI lines */); |
696 | |
697 | /* |
698 | * try to fit a whole frame into each URB, as long as doing so |
699 | * does not require very high order memory allocations |
700 | */ |
701 | BUILD_BUG_ON(CXUSB_VIDEO_URB_MAX_SIZE / CXUSB_VIDEO_PKT_SIZE > |
702 | CXUSB_VIDEO_MAX_FRAME_PKTS); |
703 | *npackets = min_t(int, (framelen + CXUSB_VIDEO_PKT_SIZE - 1) / |
704 | CXUSB_VIDEO_PKT_SIZE, |
705 | CXUSB_VIDEO_URB_MAX_SIZE / CXUSB_VIDEO_PKT_SIZE); |
706 | urblen = *npackets * CXUSB_VIDEO_PKT_SIZE; |
707 | |
708 | cxusb_vprintk(dvbdev, URB, |
709 | "each URB will have %d packets for total of %u bytes (%u x %u @ %u)\n" , |
710 | *npackets, urblen, (unsigned int)cxdev->width, |
711 | (unsigned int)cxdev->height, framelen); |
712 | |
713 | auxbuflen = framelen + urblen; |
714 | |
715 | buf = vmalloc(size: auxbuflen); |
716 | if (!buf) |
717 | return -ENOMEM; |
718 | |
719 | cxusb_auxbuf_init(dvbdev, auxbuf: &cxdev->auxbuf, buf, len: auxbuflen); |
720 | |
721 | return 0; |
722 | } |
723 | |
724 | static u32 cxusb_medion_norm2field_order(v4l2_std_id norm) |
725 | { |
726 | bool is625 = norm & V4L2_STD_625_50; |
727 | bool is525 = norm & V4L2_STD_525_60; |
728 | |
729 | if (!is625 && !is525) |
730 | return V4L2_FIELD_NONE; |
731 | |
732 | if (is625 && is525) |
733 | return V4L2_FIELD_NONE; |
734 | |
735 | if (is625) |
736 | return V4L2_FIELD_SEQ_TB; |
737 | else /* is525 */ |
738 | return V4L2_FIELD_SEQ_BT; |
739 | } |
740 | |
741 | static u32 cxusb_medion_field_order(struct cxusb_medion_dev *cxdev) |
742 | { |
743 | struct dvb_usb_device *dvbdev = cxdev->dvbdev; |
744 | u32 field; |
745 | int ret; |
746 | v4l2_std_id norm; |
747 | |
748 | /* TV tuner is PAL-only so it is always TB */ |
749 | if (cxdev->input == 0) |
750 | return V4L2_FIELD_SEQ_TB; |
751 | |
752 | field = cxusb_medion_norm2field_order(norm: cxdev->norm); |
753 | if (field != V4L2_FIELD_NONE) |
754 | return field; |
755 | |
756 | ret = v4l2_subdev_call(cxdev->cx25840, video, g_std, &norm); |
757 | if (ret != 0) { |
758 | cxusb_vprintk(dvbdev, OPS, |
759 | "cannot get current standard for input %u\n" , |
760 | (unsigned int)cxdev->input); |
761 | } else { |
762 | field = cxusb_medion_norm2field_order(norm); |
763 | if (field != V4L2_FIELD_NONE) |
764 | return field; |
765 | } |
766 | |
767 | dev_warn(&dvbdev->udev->dev, |
768 | "cannot determine field order for the current standard setup and received signal, using TB\n" ); |
769 | return V4L2_FIELD_SEQ_TB; |
770 | } |
771 | |
772 | static int cxusb_medion_v_start_streaming(struct vb2_queue *q, |
773 | unsigned int count) |
774 | { |
775 | struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); |
776 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
777 | u8 streamon_params[2] = { 0x03, 0x00 }; |
778 | int npackets, i; |
779 | int ret; |
780 | |
781 | cxusb_vprintk(dvbdev, OPS, "should start streaming\n" ); |
782 | |
783 | if (cxdev->stop_streaming) { |
784 | /* stream is being stopped */ |
785 | ret = -EBUSY; |
786 | goto ret_retbufs; |
787 | } |
788 | |
789 | cxdev->field_order = cxusb_medion_field_order(cxdev); |
790 | |
791 | ret = v4l2_subdev_call(cxdev->cx25840, video, s_stream, 1); |
792 | if (ret != 0) { |
793 | dev_err(&dvbdev->udev->dev, |
794 | "unable to start stream (%d)\n" , ret); |
795 | goto ret_retbufs; |
796 | } |
797 | |
798 | ret = cxusb_ctrl_msg(d: dvbdev, CMD_STREAMING_ON, wbuf: streamon_params, wlen: 2, |
799 | NULL, rlen: 0); |
800 | if (ret != 0) { |
801 | dev_err(&dvbdev->udev->dev, |
802 | "unable to start streaming (%d)\n" , ret); |
803 | goto ret_unstream_cx; |
804 | } |
805 | |
806 | ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, npackets: &npackets); |
807 | if (ret != 0) |
808 | goto ret_unstream_md; |
809 | |
810 | for (i = 0; i < CXUSB_VIDEO_URBS; i++) { |
811 | int framen; |
812 | u8 *streambuf; |
813 | struct urb *surb; |
814 | |
815 | /* |
816 | * TODO: change this to an array of single pages to avoid |
817 | * doing a large continuous allocation when (if) |
818 | * s-g isochronous USB transfers are supported |
819 | */ |
820 | streambuf = kmalloc(size: npackets * CXUSB_VIDEO_PKT_SIZE, |
821 | GFP_KERNEL); |
822 | if (!streambuf) { |
823 | if (i < 2) { |
824 | ret = -ENOMEM; |
825 | goto ret_freeab; |
826 | } |
827 | break; |
828 | } |
829 | |
830 | surb = usb_alloc_urb(iso_packets: npackets, GFP_KERNEL); |
831 | if (!surb) { |
832 | kfree(objp: streambuf); |
833 | ret = -ENOMEM; |
834 | goto ret_freeu; |
835 | } |
836 | |
837 | cxdev->streamurbs[i] = surb; |
838 | surb->dev = dvbdev->udev; |
839 | surb->context = dvbdev; |
840 | surb->pipe = usb_rcvisocpipe(dvbdev->udev, 2); |
841 | |
842 | surb->interval = 1; |
843 | surb->transfer_flags = URB_ISO_ASAP; |
844 | |
845 | surb->transfer_buffer = streambuf; |
846 | |
847 | surb->complete = cxusb_medion_v_complete; |
848 | surb->number_of_packets = npackets; |
849 | surb->transfer_buffer_length = npackets * CXUSB_VIDEO_PKT_SIZE; |
850 | |
851 | for (framen = 0; framen < npackets; framen++) { |
852 | surb->iso_frame_desc[framen].offset = |
853 | CXUSB_VIDEO_PKT_SIZE * framen; |
854 | |
855 | surb->iso_frame_desc[framen].length = |
856 | CXUSB_VIDEO_PKT_SIZE; |
857 | } |
858 | } |
859 | |
860 | cxdev->urbcomplete = 0; |
861 | cxdev->nexturb = 0; |
862 | cxdev->vbuf_sequence = 0; |
863 | |
864 | cxdev->vbuf = NULL; |
865 | cxdev->bt656.mode = NEW_FRAME; |
866 | cxdev->bt656.buf = NULL; |
867 | |
868 | for (i = 0; i < CXUSB_VIDEO_URBS; i++) |
869 | if (cxdev->streamurbs[i]) { |
870 | ret = usb_submit_urb(urb: cxdev->streamurbs[i], |
871 | GFP_KERNEL); |
872 | if (ret != 0) |
873 | dev_err(&dvbdev->udev->dev, |
874 | "URB %d submission failed (%d)\n" , i, |
875 | ret); |
876 | } |
877 | |
878 | return 0; |
879 | |
880 | ret_freeu: |
881 | cxusb_medion_urbs_free(cxdev); |
882 | |
883 | ret_freeab: |
884 | vfree(addr: cxdev->auxbuf.buf); |
885 | |
886 | ret_unstream_md: |
887 | cxusb_ctrl_msg(d: dvbdev, CMD_STREAMING_OFF, NULL, wlen: 0, NULL, rlen: 0); |
888 | |
889 | ret_unstream_cx: |
890 | v4l2_subdev_call(cxdev->cx25840, video, s_stream, 0); |
891 | |
892 | ret_retbufs: |
893 | cxusb_medion_return_buffers(cxdev, requeue: true); |
894 | |
895 | return ret; |
896 | } |
897 | |
898 | static void cxusb_medion_v_stop_streaming(struct vb2_queue *q) |
899 | { |
900 | struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); |
901 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
902 | int ret; |
903 | unsigned int i; |
904 | |
905 | cxusb_vprintk(dvbdev, OPS, "should stop streaming\n" ); |
906 | |
907 | if (WARN_ON(cxdev->stop_streaming)) |
908 | return; |
909 | |
910 | cxdev->stop_streaming = true; |
911 | |
912 | cxusb_ctrl_msg(d: dvbdev, CMD_STREAMING_OFF, NULL, wlen: 0, NULL, rlen: 0); |
913 | |
914 | ret = v4l2_subdev_call(cxdev->cx25840, video, s_stream, 0); |
915 | if (ret != 0) |
916 | dev_err(&dvbdev->udev->dev, "unable to stop stream (%d)\n" , |
917 | ret); |
918 | |
919 | /* let URB completion run */ |
920 | mutex_unlock(lock: cxdev->videodev->lock); |
921 | |
922 | for (i = 0; i < CXUSB_VIDEO_URBS; i++) |
923 | if (cxdev->streamurbs[i]) |
924 | usb_kill_urb(urb: cxdev->streamurbs[i]); |
925 | |
926 | flush_work(work: &cxdev->urbwork); |
927 | |
928 | mutex_lock(cxdev->videodev->lock); |
929 | |
930 | /* free transfer buffer and URB */ |
931 | vfree(addr: cxdev->auxbuf.buf); |
932 | |
933 | cxusb_medion_urbs_free(cxdev); |
934 | |
935 | cxusb_medion_return_buffers(cxdev, requeue: false); |
936 | |
937 | cxdev->stop_streaming = false; |
938 | } |
939 | |
940 | static void cxusub_medion_v_buf_queue(struct vb2_buffer *vb) |
941 | { |
942 | struct vb2_v4l2_buffer *v4l2buf = to_vb2_v4l2_buffer(vb); |
943 | struct cxusb_medion_vbuffer *vbuf = |
944 | container_of(v4l2buf, struct cxusb_medion_vbuffer, vb2); |
945 | struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q: vb->vb2_queue); |
946 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
947 | |
948 | /* cxusb_vprintk(dvbdev, OPS, "mmmm.. a fresh buffer...\n"); */ |
949 | |
950 | list_add_tail(new: &vbuf->list, head: &cxdev->buflist); |
951 | } |
952 | |
953 | static const struct vb2_ops cxdev_video_qops = { |
954 | .queue_setup = cxusb_medion_v_queue_setup, |
955 | .buf_init = cxusb_medion_v_buf_init, |
956 | .start_streaming = cxusb_medion_v_start_streaming, |
957 | .stop_streaming = cxusb_medion_v_stop_streaming, |
958 | .buf_queue = cxusub_medion_v_buf_queue, |
959 | .wait_prepare = vb2_ops_wait_prepare, |
960 | .wait_finish = vb2_ops_wait_finish |
961 | }; |
962 | |
963 | static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | |
964 | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; |
965 | static const __u32 radiocaps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; |
966 | |
967 | static int cxusb_medion_v_querycap(struct file *file, void *fh, |
968 | struct v4l2_capability *cap) |
969 | { |
970 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
971 | |
972 | strscpy(cap->driver, dvbdev->udev->dev.driver->name, |
973 | sizeof(cap->driver)); |
974 | strscpy(cap->card, "Medion 95700" , sizeof(cap->card)); |
975 | usb_make_path(dev: dvbdev->udev, buf: cap->bus_info, size: sizeof(cap->bus_info)); |
976 | |
977 | cap->capabilities = videocaps | radiocaps | V4L2_CAP_DEVICE_CAPS; |
978 | |
979 | return 0; |
980 | } |
981 | |
982 | static int cxusb_medion_v_enum_fmt_vid_cap(struct file *file, void *fh, |
983 | struct v4l2_fmtdesc *f) |
984 | { |
985 | if (f->index != 0) |
986 | return -EINVAL; |
987 | |
988 | f->pixelformat = V4L2_PIX_FMT_UYVY; |
989 | |
990 | return 0; |
991 | } |
992 | |
993 | static int cxusb_medion_g_fmt_vid_cap(struct file *file, void *fh, |
994 | struct v4l2_format *f) |
995 | { |
996 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
997 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
998 | |
999 | f->fmt.pix.width = cxdev->width; |
1000 | f->fmt.pix.height = cxdev->height; |
1001 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; |
1002 | f->fmt.pix.field = vb2_start_streaming_called(q: &cxdev->videoqueue) ? |
1003 | cxdev->field_order : cxusb_medion_field_order(cxdev); |
1004 | f->fmt.pix.bytesperline = cxdev->width * 2; |
1005 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
1006 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; |
1007 | |
1008 | return 0; |
1009 | } |
1010 | |
1011 | static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, |
1012 | struct v4l2_format *f, |
1013 | bool isset) |
1014 | { |
1015 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1016 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1017 | struct v4l2_subdev_format subfmt = { |
1018 | .which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE : |
1019 | V4L2_SUBDEV_FORMAT_TRY, |
1020 | }; |
1021 | u32 field; |
1022 | int ret; |
1023 | |
1024 | if (isset && vb2_is_busy(q: &cxdev->videoqueue)) |
1025 | return -EBUSY; |
1026 | |
1027 | field = vb2_start_streaming_called(q: &cxdev->videoqueue) ? |
1028 | cxdev->field_order : cxusb_medion_field_order(cxdev); |
1029 | |
1030 | subfmt.format.width = f->fmt.pix.width & ~1; |
1031 | subfmt.format.height = f->fmt.pix.height & ~1; |
1032 | subfmt.format.code = MEDIA_BUS_FMT_FIXED; |
1033 | subfmt.format.field = field; |
1034 | subfmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M; |
1035 | |
1036 | ret = v4l2_subdev_call(cxdev->cx25840, pad, set_fmt, NULL, &subfmt); |
1037 | if (ret != 0) |
1038 | return ret; |
1039 | |
1040 | f->fmt.pix.width = subfmt.format.width; |
1041 | f->fmt.pix.height = subfmt.format.height; |
1042 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; |
1043 | f->fmt.pix.field = field; |
1044 | f->fmt.pix.bytesperline = f->fmt.pix.width * 2; |
1045 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; |
1046 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
1047 | |
1048 | if (isset) { |
1049 | cxdev->width = f->fmt.pix.width; |
1050 | cxdev->height = f->fmt.pix.height; |
1051 | } |
1052 | |
1053 | return 0; |
1054 | } |
1055 | |
1056 | static int cxusb_medion_try_fmt_vid_cap(struct file *file, void *fh, |
1057 | struct v4l2_format *f) |
1058 | { |
1059 | return cxusb_medion_try_s_fmt_vid_cap(file, f, isset: false); |
1060 | } |
1061 | |
1062 | static int cxusb_medion_s_fmt_vid_cap(struct file *file, void *fh, |
1063 | struct v4l2_format *f) |
1064 | { |
1065 | return cxusb_medion_try_s_fmt_vid_cap(file, f, isset: true); |
1066 | } |
1067 | |
1068 | static const struct { |
1069 | struct v4l2_input input; |
1070 | u32 inputcfg; |
1071 | } cxusb_medion_inputs[] = { |
1072 | { .input = { .name = "TV tuner" , .type = V4L2_INPUT_TYPE_TUNER, |
1073 | .tuner = 0, .std = V4L2_STD_PAL }, |
1074 | .inputcfg = CX25840_COMPOSITE2, }, |
1075 | |
1076 | { .input = { .name = "Composite" , .type = V4L2_INPUT_TYPE_CAMERA, |
1077 | .std = V4L2_STD_ALL }, |
1078 | .inputcfg = CX25840_COMPOSITE1, }, |
1079 | |
1080 | { .input = { .name = "S-Video" , .type = V4L2_INPUT_TYPE_CAMERA, |
1081 | .std = V4L2_STD_ALL }, |
1082 | .inputcfg = CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 } |
1083 | }; |
1084 | |
1085 | #define CXUSB_INPUT_CNT ARRAY_SIZE(cxusb_medion_inputs) |
1086 | |
1087 | static int cxusb_medion_enum_input(struct file *file, void *fh, |
1088 | struct v4l2_input *inp) |
1089 | { |
1090 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1091 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1092 | u32 index = inp->index; |
1093 | |
1094 | if (index >= CXUSB_INPUT_CNT) |
1095 | return -EINVAL; |
1096 | |
1097 | *inp = cxusb_medion_inputs[index].input; |
1098 | inp->index = index; |
1099 | inp->capabilities |= V4L2_IN_CAP_STD; |
1100 | |
1101 | if (index == cxdev->input) { |
1102 | int ret; |
1103 | u32 status = 0; |
1104 | |
1105 | ret = v4l2_subdev_call(cxdev->cx25840, video, g_input_status, |
1106 | &status); |
1107 | if (ret != 0) |
1108 | dev_warn(&dvbdev->udev->dev, |
1109 | "cx25840 input status query failed (%d)\n" , |
1110 | ret); |
1111 | else |
1112 | inp->status = status; |
1113 | } |
1114 | |
1115 | return 0; |
1116 | } |
1117 | |
1118 | static int cxusb_medion_g_input(struct file *file, void *fh, |
1119 | unsigned int *i) |
1120 | { |
1121 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1122 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1123 | |
1124 | *i = cxdev->input; |
1125 | |
1126 | return 0; |
1127 | } |
1128 | |
1129 | static int cxusb_medion_set_norm(struct cxusb_medion_dev *cxdev, |
1130 | v4l2_std_id norm) |
1131 | { |
1132 | struct dvb_usb_device *dvbdev = cxdev->dvbdev; |
1133 | int ret; |
1134 | |
1135 | cxusb_vprintk(dvbdev, OPS, |
1136 | "trying to set standard for input %u to %lx\n" , |
1137 | (unsigned int)cxdev->input, |
1138 | (unsigned long)norm); |
1139 | |
1140 | /* no autodetection support */ |
1141 | if (norm == V4L2_STD_UNKNOWN) |
1142 | return -EINVAL; |
1143 | |
1144 | /* on composite or S-Video any std is acceptable */ |
1145 | if (cxdev->input != 0) { |
1146 | ret = v4l2_subdev_call(cxdev->cx25840, video, s_std, norm); |
1147 | if (ret) |
1148 | return ret; |
1149 | |
1150 | goto ret_savenorm; |
1151 | } |
1152 | |
1153 | /* TV tuner is only able to demodulate PAL */ |
1154 | if ((norm & ~V4L2_STD_PAL) != 0) |
1155 | return -EINVAL; |
1156 | |
1157 | ret = v4l2_subdev_call(cxdev->tda9887, video, s_std, norm); |
1158 | if (ret != 0) { |
1159 | dev_err(&dvbdev->udev->dev, |
1160 | "tda9887 norm setup failed (%d)\n" , |
1161 | ret); |
1162 | return ret; |
1163 | } |
1164 | |
1165 | ret = v4l2_subdev_call(cxdev->tuner, video, s_std, norm); |
1166 | if (ret != 0) { |
1167 | dev_err(&dvbdev->udev->dev, |
1168 | "tuner norm setup failed (%d)\n" , |
1169 | ret); |
1170 | return ret; |
1171 | } |
1172 | |
1173 | ret = v4l2_subdev_call(cxdev->cx25840, video, s_std, norm); |
1174 | if (ret != 0) { |
1175 | dev_err(&dvbdev->udev->dev, |
1176 | "cx25840 norm setup failed (%d)\n" , |
1177 | ret); |
1178 | return ret; |
1179 | } |
1180 | |
1181 | ret_savenorm: |
1182 | cxdev->norm = norm; |
1183 | |
1184 | return 0; |
1185 | } |
1186 | |
1187 | static int cxusb_medion_s_input(struct file *file, void *fh, |
1188 | unsigned int i) |
1189 | { |
1190 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1191 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1192 | int ret; |
1193 | v4l2_std_id norm; |
1194 | |
1195 | if (i >= CXUSB_INPUT_CNT) |
1196 | return -EINVAL; |
1197 | |
1198 | ret = v4l2_subdev_call(cxdev->cx25840, video, s_routing, |
1199 | cxusb_medion_inputs[i].inputcfg, 0, 0); |
1200 | if (ret != 0) |
1201 | return ret; |
1202 | |
1203 | cxdev->input = i; |
1204 | cxdev->videodev->tvnorms = cxusb_medion_inputs[i].input.std; |
1205 | |
1206 | norm = cxdev->norm & cxusb_medion_inputs[i].input.std; |
1207 | if (norm == 0) |
1208 | norm = cxusb_medion_inputs[i].input.std; |
1209 | |
1210 | cxusb_medion_set_norm(cxdev, norm); |
1211 | |
1212 | return 0; |
1213 | } |
1214 | |
1215 | static int cxusb_medion_g_tuner(struct file *file, void *fh, |
1216 | struct v4l2_tuner *tuner) |
1217 | { |
1218 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1219 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1220 | struct video_device *vdev = video_devdata(file); |
1221 | int ret; |
1222 | |
1223 | if (tuner->index != 0) |
1224 | return -EINVAL; |
1225 | |
1226 | if (vdev->vfl_type == VFL_TYPE_VIDEO) |
1227 | tuner->type = V4L2_TUNER_ANALOG_TV; |
1228 | else |
1229 | tuner->type = V4L2_TUNER_RADIO; |
1230 | |
1231 | tuner->capability = 0; |
1232 | tuner->afc = 0; |
1233 | |
1234 | /* |
1235 | * fills: |
1236 | * always: capability (static), rangelow (static), rangehigh (static) |
1237 | * radio mode: afc (may fail silently), rxsubchans (static), audmode |
1238 | */ |
1239 | ret = v4l2_subdev_call(cxdev->tda9887, tuner, g_tuner, tuner); |
1240 | if (ret != 0) |
1241 | return ret; |
1242 | |
1243 | /* |
1244 | * fills: |
1245 | * always: capability (static), rangelow (static), rangehigh (static) |
1246 | * radio mode: rxsubchans (always stereo), audmode, |
1247 | * signal (might be wrong) |
1248 | */ |
1249 | ret = v4l2_subdev_call(cxdev->tuner, tuner, g_tuner, tuner); |
1250 | if (ret != 0) |
1251 | return ret; |
1252 | |
1253 | tuner->signal = 0; |
1254 | |
1255 | /* |
1256 | * fills: TV mode: capability, rxsubchans, audmode, signal |
1257 | */ |
1258 | ret = v4l2_subdev_call(cxdev->cx25840, tuner, g_tuner, tuner); |
1259 | if (ret != 0) |
1260 | return ret; |
1261 | |
1262 | if (vdev->vfl_type == VFL_TYPE_VIDEO) |
1263 | strscpy(tuner->name, "TV tuner" , sizeof(tuner->name)); |
1264 | else |
1265 | strscpy(tuner->name, "Radio tuner" , sizeof(tuner->name)); |
1266 | |
1267 | memset(tuner->reserved, 0, sizeof(tuner->reserved)); |
1268 | |
1269 | return 0; |
1270 | } |
1271 | |
1272 | static int cxusb_medion_s_tuner(struct file *file, void *fh, |
1273 | const struct v4l2_tuner *tuner) |
1274 | { |
1275 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1276 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1277 | struct video_device *vdev = video_devdata(file); |
1278 | int ret; |
1279 | |
1280 | if (tuner->index != 0) |
1281 | return -EINVAL; |
1282 | |
1283 | ret = v4l2_subdev_call(cxdev->tda9887, tuner, s_tuner, tuner); |
1284 | if (ret != 0) |
1285 | return ret; |
1286 | |
1287 | ret = v4l2_subdev_call(cxdev->tuner, tuner, s_tuner, tuner); |
1288 | if (ret != 0) |
1289 | return ret; |
1290 | |
1291 | /* |
1292 | * make sure that cx25840 is in a correct TV / radio mode, |
1293 | * since calls above may have changed it for tuner / IF demod |
1294 | */ |
1295 | if (vdev->vfl_type == VFL_TYPE_VIDEO) |
1296 | v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); |
1297 | else |
1298 | v4l2_subdev_call(cxdev->cx25840, tuner, s_radio); |
1299 | |
1300 | return v4l2_subdev_call(cxdev->cx25840, tuner, s_tuner, tuner); |
1301 | } |
1302 | |
1303 | static int cxusb_medion_g_frequency(struct file *file, void *fh, |
1304 | struct v4l2_frequency *freq) |
1305 | { |
1306 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1307 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1308 | |
1309 | if (freq->tuner != 0) |
1310 | return -EINVAL; |
1311 | |
1312 | return v4l2_subdev_call(cxdev->tuner, tuner, g_frequency, freq); |
1313 | } |
1314 | |
1315 | static int cxusb_medion_s_frequency(struct file *file, void *fh, |
1316 | const struct v4l2_frequency *freq) |
1317 | { |
1318 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1319 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1320 | struct video_device *vdev = video_devdata(file); |
1321 | int ret; |
1322 | |
1323 | if (freq->tuner != 0) |
1324 | return -EINVAL; |
1325 | |
1326 | ret = v4l2_subdev_call(cxdev->tda9887, tuner, s_frequency, freq); |
1327 | if (ret != 0) |
1328 | return ret; |
1329 | |
1330 | ret = v4l2_subdev_call(cxdev->tuner, tuner, s_frequency, freq); |
1331 | if (ret != 0) |
1332 | return ret; |
1333 | |
1334 | /* |
1335 | * make sure that cx25840 is in a correct TV / radio mode, |
1336 | * since calls above may have changed it for tuner / IF demod |
1337 | */ |
1338 | if (vdev->vfl_type == VFL_TYPE_VIDEO) |
1339 | v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); |
1340 | else |
1341 | v4l2_subdev_call(cxdev->cx25840, tuner, s_radio); |
1342 | |
1343 | return v4l2_subdev_call(cxdev->cx25840, tuner, s_frequency, freq); |
1344 | } |
1345 | |
1346 | static int cxusb_medion_g_std(struct file *file, void *fh, |
1347 | v4l2_std_id *norm) |
1348 | { |
1349 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1350 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1351 | |
1352 | *norm = cxdev->norm; |
1353 | |
1354 | if (*norm == V4L2_STD_UNKNOWN) |
1355 | return -ENODATA; |
1356 | |
1357 | return 0; |
1358 | } |
1359 | |
1360 | static int cxusb_medion_s_std(struct file *file, void *fh, |
1361 | v4l2_std_id norm) |
1362 | { |
1363 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1364 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1365 | |
1366 | return cxusb_medion_set_norm(cxdev, norm); |
1367 | } |
1368 | |
1369 | static int cxusb_medion_querystd(struct file *file, void *fh, |
1370 | v4l2_std_id *norm) |
1371 | { |
1372 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1373 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1374 | v4l2_std_id norm_mask; |
1375 | int ret; |
1376 | |
1377 | /* |
1378 | * make sure we don't have improper std bits set for the TV tuner |
1379 | * (could happen when no signal was present yet after reset) |
1380 | */ |
1381 | if (cxdev->input == 0) |
1382 | norm_mask = V4L2_STD_PAL; |
1383 | else |
1384 | norm_mask = V4L2_STD_ALL; |
1385 | |
1386 | ret = v4l2_subdev_call(cxdev->cx25840, video, querystd, norm); |
1387 | if (ret != 0) { |
1388 | cxusb_vprintk(dvbdev, OPS, |
1389 | "cannot get detected standard for input %u\n" , |
1390 | (unsigned int)cxdev->input); |
1391 | return ret; |
1392 | } |
1393 | |
1394 | cxusb_vprintk(dvbdev, OPS, "input %u detected standard is %lx\n" , |
1395 | (unsigned int)cxdev->input, (unsigned long)*norm); |
1396 | *norm &= norm_mask; |
1397 | |
1398 | return 0; |
1399 | } |
1400 | |
1401 | static int cxusb_medion_log_status(struct file *file, void *fh) |
1402 | { |
1403 | struct dvb_usb_device *dvbdev = video_drvdata(file); |
1404 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1405 | |
1406 | v4l2_device_call_all(&cxdev->v4l2dev, 0, core, log_status); |
1407 | |
1408 | return 0; |
1409 | } |
1410 | |
1411 | static const struct v4l2_ioctl_ops cxusb_video_ioctl = { |
1412 | .vidioc_querycap = cxusb_medion_v_querycap, |
1413 | .vidioc_enum_fmt_vid_cap = cxusb_medion_v_enum_fmt_vid_cap, |
1414 | .vidioc_g_fmt_vid_cap = cxusb_medion_g_fmt_vid_cap, |
1415 | .vidioc_s_fmt_vid_cap = cxusb_medion_s_fmt_vid_cap, |
1416 | .vidioc_try_fmt_vid_cap = cxusb_medion_try_fmt_vid_cap, |
1417 | .vidioc_enum_input = cxusb_medion_enum_input, |
1418 | .vidioc_g_input = cxusb_medion_g_input, |
1419 | .vidioc_s_input = cxusb_medion_s_input, |
1420 | .vidioc_g_tuner = cxusb_medion_g_tuner, |
1421 | .vidioc_s_tuner = cxusb_medion_s_tuner, |
1422 | .vidioc_g_frequency = cxusb_medion_g_frequency, |
1423 | .vidioc_s_frequency = cxusb_medion_s_frequency, |
1424 | .vidioc_g_std = cxusb_medion_g_std, |
1425 | .vidioc_s_std = cxusb_medion_s_std, |
1426 | .vidioc_querystd = cxusb_medion_querystd, |
1427 | .vidioc_log_status = cxusb_medion_log_status, |
1428 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
1429 | .vidioc_querybuf = vb2_ioctl_querybuf, |
1430 | .vidioc_qbuf = vb2_ioctl_qbuf, |
1431 | .vidioc_dqbuf = vb2_ioctl_dqbuf, |
1432 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
1433 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, |
1434 | .vidioc_streamon = vb2_ioctl_streamon, |
1435 | .vidioc_streamoff = vb2_ioctl_streamoff |
1436 | }; |
1437 | |
1438 | static const struct v4l2_ioctl_ops cxusb_radio_ioctl = { |
1439 | .vidioc_querycap = cxusb_medion_v_querycap, |
1440 | .vidioc_g_tuner = cxusb_medion_g_tuner, |
1441 | .vidioc_s_tuner = cxusb_medion_s_tuner, |
1442 | .vidioc_g_frequency = cxusb_medion_g_frequency, |
1443 | .vidioc_s_frequency = cxusb_medion_s_frequency, |
1444 | .vidioc_log_status = cxusb_medion_log_status |
1445 | }; |
1446 | |
1447 | /* |
1448 | * in principle, this should be const, but s_io_pin_config is declared |
1449 | * to take non-const, and gcc complains |
1450 | */ |
1451 | static struct v4l2_subdev_io_pin_config cxusub_medion_pin_config[] = { |
1452 | { .pin = CX25840_PIN_DVALID_PRGM0, .function = CX25840_PAD_DEFAULT, |
1453 | .strength = CX25840_PIN_DRIVE_MEDIUM }, |
1454 | { .pin = CX25840_PIN_PLL_CLK_PRGM7, .function = CX25840_PAD_AUX_PLL }, |
1455 | { .pin = CX25840_PIN_HRESET_PRGM2, .function = CX25840_PAD_ACTIVE, |
1456 | .strength = CX25840_PIN_DRIVE_MEDIUM } |
1457 | }; |
1458 | |
1459 | int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) |
1460 | { |
1461 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1462 | u8 tuner_analog_msg_data[] = { 0x9c, 0x60, 0x85, 0x54 }; |
1463 | struct i2c_msg tuner_analog_msg = { .addr = 0x61, .flags = 0, |
1464 | .buf = tuner_analog_msg_data, |
1465 | .len = |
1466 | sizeof(tuner_analog_msg_data) }; |
1467 | struct v4l2_subdev_format subfmt = { |
1468 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
1469 | }; |
1470 | int ret; |
1471 | |
1472 | /* switch tuner to analog mode so IF demod will become accessible */ |
1473 | ret = i2c_transfer(adap: &dvbdev->i2c_adap, msgs: &tuner_analog_msg, num: 1); |
1474 | if (ret != 1) |
1475 | dev_warn(&dvbdev->udev->dev, |
1476 | "tuner analog switch failed (%d)\n" , ret); |
1477 | |
1478 | /* |
1479 | * cx25840 might have lost power during mode switching so we need |
1480 | * to set it again |
1481 | */ |
1482 | ret = v4l2_subdev_call(cxdev->cx25840, core, reset, 0); |
1483 | if (ret != 0) |
1484 | dev_warn(&dvbdev->udev->dev, |
1485 | "cx25840 reset failed (%d)\n" , ret); |
1486 | |
1487 | ret = v4l2_subdev_call(cxdev->cx25840, video, s_routing, |
1488 | CX25840_COMPOSITE1, 0, 0); |
1489 | if (ret != 0) |
1490 | dev_warn(&dvbdev->udev->dev, |
1491 | "cx25840 initial input setting failed (%d)\n" , ret); |
1492 | |
1493 | /* composite */ |
1494 | cxdev->input = 1; |
1495 | cxdev->videodev->tvnorms = V4L2_STD_ALL; |
1496 | cxdev->norm = V4L2_STD_PAL; |
1497 | |
1498 | /* TODO: setup audio samples insertion */ |
1499 | |
1500 | ret = v4l2_subdev_call(cxdev->cx25840, core, s_io_pin_config, |
1501 | ARRAY_SIZE(cxusub_medion_pin_config), |
1502 | cxusub_medion_pin_config); |
1503 | if (ret != 0) |
1504 | dev_warn(&dvbdev->udev->dev, |
1505 | "cx25840 pin config failed (%d)\n" , ret); |
1506 | |
1507 | /* make sure that we aren't in radio mode */ |
1508 | v4l2_subdev_call(cxdev->tda9887, video, s_std, cxdev->norm); |
1509 | v4l2_subdev_call(cxdev->tuner, video, s_std, cxdev->norm); |
1510 | v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); |
1511 | |
1512 | subfmt.format.width = cxdev->width; |
1513 | subfmt.format.height = cxdev->height; |
1514 | subfmt.format.code = MEDIA_BUS_FMT_FIXED; |
1515 | subfmt.format.field = V4L2_FIELD_SEQ_TB; |
1516 | subfmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M; |
1517 | |
1518 | ret = v4l2_subdev_call(cxdev->cx25840, pad, set_fmt, NULL, &subfmt); |
1519 | if (ret != 0) |
1520 | dev_warn(&dvbdev->udev->dev, |
1521 | "cx25840 format set failed (%d)\n" , ret); |
1522 | |
1523 | if (ret == 0) { |
1524 | cxdev->width = subfmt.format.width; |
1525 | cxdev->height = subfmt.format.height; |
1526 | } |
1527 | |
1528 | return 0; |
1529 | } |
1530 | |
1531 | static int cxusb_videoradio_open(struct file *f) |
1532 | { |
1533 | struct dvb_usb_device *dvbdev = video_drvdata(file: f); |
1534 | int ret; |
1535 | |
1536 | /* |
1537 | * no locking needed since this call only modifies analog |
1538 | * state if there are no other analog handles currenly |
1539 | * opened so ops done via them cannot create a conflict |
1540 | */ |
1541 | ret = cxusb_medion_get(dvbdev, open_type: CXUSB_OPEN_ANALOG); |
1542 | if (ret != 0) |
1543 | return ret; |
1544 | |
1545 | ret = v4l2_fh_open(filp: f); |
1546 | if (ret != 0) |
1547 | goto ret_release; |
1548 | |
1549 | cxusb_vprintk(dvbdev, OPS, "got open\n" ); |
1550 | |
1551 | return 0; |
1552 | |
1553 | ret_release: |
1554 | cxusb_medion_put(dvbdev); |
1555 | |
1556 | return ret; |
1557 | } |
1558 | |
1559 | static int cxusb_videoradio_release(struct file *f) |
1560 | { |
1561 | struct video_device *vdev = video_devdata(file: f); |
1562 | struct dvb_usb_device *dvbdev = video_drvdata(file: f); |
1563 | int ret; |
1564 | |
1565 | cxusb_vprintk(dvbdev, OPS, "got release\n" ); |
1566 | |
1567 | if (vdev->vfl_type == VFL_TYPE_VIDEO) |
1568 | ret = vb2_fop_release(file: f); |
1569 | else |
1570 | ret = v4l2_fh_release(filp: f); |
1571 | |
1572 | cxusb_medion_put(dvbdev); |
1573 | |
1574 | return ret; |
1575 | } |
1576 | |
1577 | static const struct v4l2_file_operations cxusb_video_fops = { |
1578 | .owner = THIS_MODULE, |
1579 | .read = vb2_fop_read, |
1580 | .poll = vb2_fop_poll, |
1581 | .unlocked_ioctl = video_ioctl2, |
1582 | .mmap = vb2_fop_mmap, |
1583 | .open = cxusb_videoradio_open, |
1584 | .release = cxusb_videoradio_release |
1585 | }; |
1586 | |
1587 | static const struct v4l2_file_operations cxusb_radio_fops = { |
1588 | .owner = THIS_MODULE, |
1589 | .unlocked_ioctl = video_ioctl2, |
1590 | .open = cxusb_videoradio_open, |
1591 | .release = cxusb_videoradio_release |
1592 | }; |
1593 | |
1594 | static void cxusb_medion_v4l2_release(struct v4l2_device *v4l2_dev) |
1595 | { |
1596 | struct cxusb_medion_dev *cxdev = |
1597 | container_of(v4l2_dev, struct cxusb_medion_dev, v4l2dev); |
1598 | struct dvb_usb_device *dvbdev = cxdev->dvbdev; |
1599 | |
1600 | cxusb_vprintk(dvbdev, OPS, "v4l2 device release\n" ); |
1601 | |
1602 | v4l2_device_unregister(v4l2_dev: &cxdev->v4l2dev); |
1603 | |
1604 | mutex_destroy(lock: &cxdev->dev_lock); |
1605 | |
1606 | while (completion_done(x: &cxdev->v4l2_release)) |
1607 | schedule(); |
1608 | |
1609 | complete(&cxdev->v4l2_release); |
1610 | } |
1611 | |
1612 | static void cxusb_medion_videodev_release(struct video_device *vdev) |
1613 | { |
1614 | struct dvb_usb_device *dvbdev = video_get_drvdata(vdev); |
1615 | |
1616 | cxusb_vprintk(dvbdev, OPS, "video device release\n" ); |
1617 | |
1618 | video_device_release(vdev); |
1619 | } |
1620 | |
1621 | static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev) |
1622 | { |
1623 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1624 | int ret; |
1625 | |
1626 | cxdev->videoqueue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1627 | cxdev->videoqueue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | |
1628 | VB2_DMABUF; |
1629 | cxdev->videoqueue.ops = &cxdev_video_qops; |
1630 | cxdev->videoqueue.mem_ops = &vb2_vmalloc_memops; |
1631 | cxdev->videoqueue.drv_priv = dvbdev; |
1632 | cxdev->videoqueue.buf_struct_size = |
1633 | sizeof(struct cxusb_medion_vbuffer); |
1634 | cxdev->videoqueue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1635 | cxdev->videoqueue.min_queued_buffers = 6; |
1636 | cxdev->videoqueue.lock = &cxdev->dev_lock; |
1637 | |
1638 | ret = vb2_queue_init(q: &cxdev->videoqueue); |
1639 | if (ret) { |
1640 | dev_err(&dvbdev->udev->dev, |
1641 | "video queue init failed, ret = %d\n" , ret); |
1642 | return ret; |
1643 | } |
1644 | |
1645 | cxdev->videodev = video_device_alloc(); |
1646 | if (!cxdev->videodev) { |
1647 | dev_err(&dvbdev->udev->dev, "video device alloc failed\n" ); |
1648 | return -ENOMEM; |
1649 | } |
1650 | |
1651 | cxdev->videodev->device_caps = videocaps; |
1652 | cxdev->videodev->fops = &cxusb_video_fops; |
1653 | cxdev->videodev->v4l2_dev = &cxdev->v4l2dev; |
1654 | cxdev->videodev->queue = &cxdev->videoqueue; |
1655 | strscpy(cxdev->videodev->name, "cxusb" , sizeof(cxdev->videodev->name)); |
1656 | cxdev->videodev->vfl_dir = VFL_DIR_RX; |
1657 | cxdev->videodev->ioctl_ops = &cxusb_video_ioctl; |
1658 | cxdev->videodev->tvnorms = V4L2_STD_ALL; |
1659 | cxdev->videodev->release = cxusb_medion_videodev_release; |
1660 | cxdev->videodev->lock = &cxdev->dev_lock; |
1661 | video_set_drvdata(vdev: cxdev->videodev, data: dvbdev); |
1662 | |
1663 | ret = video_register_device(vdev: cxdev->videodev, type: VFL_TYPE_VIDEO, nr: -1); |
1664 | if (ret) { |
1665 | dev_err(&dvbdev->udev->dev, |
1666 | "video device register failed, ret = %d\n" , ret); |
1667 | goto ret_vrelease; |
1668 | } |
1669 | |
1670 | return 0; |
1671 | |
1672 | ret_vrelease: |
1673 | video_device_release(vdev: cxdev->videodev); |
1674 | return ret; |
1675 | } |
1676 | |
1677 | static int cxusb_medion_register_analog_radio(struct dvb_usb_device *dvbdev) |
1678 | { |
1679 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1680 | int ret; |
1681 | |
1682 | cxdev->radiodev = video_device_alloc(); |
1683 | if (!cxdev->radiodev) { |
1684 | dev_err(&dvbdev->udev->dev, "radio device alloc failed\n" ); |
1685 | return -ENOMEM; |
1686 | } |
1687 | |
1688 | cxdev->radiodev->device_caps = radiocaps; |
1689 | cxdev->radiodev->fops = &cxusb_radio_fops; |
1690 | cxdev->radiodev->v4l2_dev = &cxdev->v4l2dev; |
1691 | strscpy(cxdev->radiodev->name, "cxusb" , sizeof(cxdev->radiodev->name)); |
1692 | cxdev->radiodev->vfl_dir = VFL_DIR_RX; |
1693 | cxdev->radiodev->ioctl_ops = &cxusb_radio_ioctl; |
1694 | cxdev->radiodev->release = video_device_release; |
1695 | cxdev->radiodev->lock = &cxdev->dev_lock; |
1696 | video_set_drvdata(vdev: cxdev->radiodev, data: dvbdev); |
1697 | |
1698 | ret = video_register_device(vdev: cxdev->radiodev, type: VFL_TYPE_RADIO, nr: -1); |
1699 | if (ret) { |
1700 | dev_err(&dvbdev->udev->dev, |
1701 | "radio device register failed, ret = %d\n" , ret); |
1702 | video_device_release(vdev: cxdev->radiodev); |
1703 | return ret; |
1704 | } |
1705 | |
1706 | return 0; |
1707 | } |
1708 | |
1709 | static int cxusb_medion_register_analog_subdevs(struct dvb_usb_device *dvbdev) |
1710 | { |
1711 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1712 | int ret; |
1713 | struct tuner_setup tun_setup; |
1714 | |
1715 | /* attach cx25840 capture chip */ |
1716 | cxdev->cx25840 = v4l2_i2c_new_subdev(v4l2_dev: &cxdev->v4l2dev, |
1717 | adapter: &dvbdev->i2c_adap, |
1718 | client_type: "cx25840" , addr: 0x44, NULL); |
1719 | if (!cxdev->cx25840) { |
1720 | dev_err(&dvbdev->udev->dev, "cx25840 not found\n" ); |
1721 | return -ENODEV; |
1722 | } |
1723 | |
1724 | /* |
1725 | * Initialize cx25840 chip by calling its subdevice init core op. |
1726 | * |
1727 | * This switches it into the generic mode that disables some of |
1728 | * ivtv-related hacks in the cx25840 driver while allowing setting |
1729 | * of the chip video output configuration (passed in the call below |
1730 | * as the last argument). |
1731 | */ |
1732 | ret = v4l2_subdev_call(cxdev->cx25840, core, init, |
1733 | CX25840_VCONFIG_FMT_BT656 | |
1734 | CX25840_VCONFIG_RES_8BIT | |
1735 | CX25840_VCONFIG_VBIRAW_DISABLED | |
1736 | CX25840_VCONFIG_ANCDATA_DISABLED | |
1737 | CX25840_VCONFIG_ACTIVE_COMPOSITE | |
1738 | CX25840_VCONFIG_VALID_ANDACTIVE | |
1739 | CX25840_VCONFIG_HRESETW_NORMAL | |
1740 | CX25840_VCONFIG_CLKGATE_NONE | |
1741 | CX25840_VCONFIG_DCMODE_DWORDS); |
1742 | if (ret != 0) { |
1743 | dev_err(&dvbdev->udev->dev, |
1744 | "cx25840 init failed (%d)\n" , ret); |
1745 | return ret; |
1746 | } |
1747 | |
1748 | /* attach analog tuner */ |
1749 | cxdev->tuner = v4l2_i2c_new_subdev(v4l2_dev: &cxdev->v4l2dev, |
1750 | adapter: &dvbdev->i2c_adap, |
1751 | client_type: "tuner" , addr: 0x61, NULL); |
1752 | if (!cxdev->tuner) { |
1753 | dev_err(&dvbdev->udev->dev, "tuner not found\n" ); |
1754 | return -ENODEV; |
1755 | } |
1756 | |
1757 | /* configure it */ |
1758 | memset(&tun_setup, 0, sizeof(tun_setup)); |
1759 | tun_setup.addr = 0x61; |
1760 | tun_setup.type = TUNER_PHILIPS_FMD1216ME_MK3; |
1761 | tun_setup.mode_mask = T_RADIO | T_ANALOG_TV; |
1762 | v4l2_subdev_call(cxdev->tuner, tuner, s_type_addr, &tun_setup); |
1763 | |
1764 | /* attach IF demod */ |
1765 | cxdev->tda9887 = v4l2_i2c_new_subdev(v4l2_dev: &cxdev->v4l2dev, |
1766 | adapter: &dvbdev->i2c_adap, |
1767 | client_type: "tuner" , addr: 0x43, NULL); |
1768 | if (!cxdev->tda9887) { |
1769 | dev_err(&dvbdev->udev->dev, "tda9887 not found\n" ); |
1770 | return -ENODEV; |
1771 | } |
1772 | |
1773 | return 0; |
1774 | } |
1775 | |
1776 | int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev) |
1777 | { |
1778 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1779 | int ret; |
1780 | |
1781 | mutex_init(&cxdev->dev_lock); |
1782 | |
1783 | init_completion(x: &cxdev->v4l2_release); |
1784 | |
1785 | cxdev->v4l2dev.release = cxusb_medion_v4l2_release; |
1786 | |
1787 | ret = v4l2_device_register(dev: &dvbdev->udev->dev, v4l2_dev: &cxdev->v4l2dev); |
1788 | if (ret != 0) { |
1789 | dev_err(&dvbdev->udev->dev, |
1790 | "V4L2 device registration failed, ret = %d\n" , ret); |
1791 | mutex_destroy(lock: &cxdev->dev_lock); |
1792 | return ret; |
1793 | } |
1794 | |
1795 | ret = cxusb_medion_register_analog_subdevs(dvbdev); |
1796 | if (ret) |
1797 | goto ret_unregister; |
1798 | |
1799 | INIT_WORK(&cxdev->urbwork, cxusb_medion_v_complete_work); |
1800 | INIT_LIST_HEAD(list: &cxdev->buflist); |
1801 | |
1802 | cxdev->width = 320; |
1803 | cxdev->height = 240; |
1804 | |
1805 | ret = cxusb_medion_register_analog_video(dvbdev); |
1806 | if (ret) |
1807 | goto ret_unregister; |
1808 | |
1809 | ret = cxusb_medion_register_analog_radio(dvbdev); |
1810 | if (ret) |
1811 | goto ret_vunreg; |
1812 | |
1813 | return 0; |
1814 | |
1815 | ret_vunreg: |
1816 | vb2_video_unregister_device(vdev: cxdev->videodev); |
1817 | |
1818 | ret_unregister: |
1819 | v4l2_device_put(v4l2_dev: &cxdev->v4l2dev); |
1820 | wait_for_completion(&cxdev->v4l2_release); |
1821 | |
1822 | return ret; |
1823 | } |
1824 | |
1825 | void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev) |
1826 | { |
1827 | struct cxusb_medion_dev *cxdev = dvbdev->priv; |
1828 | |
1829 | cxusb_vprintk(dvbdev, OPS, "unregistering analog\n" ); |
1830 | |
1831 | video_unregister_device(vdev: cxdev->radiodev); |
1832 | vb2_video_unregister_device(vdev: cxdev->videodev); |
1833 | |
1834 | v4l2_device_put(v4l2_dev: &cxdev->v4l2dev); |
1835 | wait_for_completion(&cxdev->v4l2_release); |
1836 | |
1837 | cxusb_vprintk(dvbdev, OPS, "analog unregistered\n" ); |
1838 | } |
1839 | |