Commit e281db5862743dbe1dab7f8fb423e699537036ee
Committed by
Mauro Carvalho Chehab
1 parent
1e55126666
Exists in
master
and in
4 other branches
V4L/DVB (8639): saa6752hs: cleanup and add AC-3 support
Cleaned up the saa6752hs i2c driver. Add AC-3 support. Add VIDIOC_CHIP_IDENT support. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Showing 4 changed files with 194 additions and 103 deletions Side-by-side Diff
drivers/media/video/saa7134/saa6752hs.c
1 | + /* | |
2 | + saa6752hs - i2c-driver for the saa6752hs by Philips | |
3 | + | |
4 | + Copyright (C) 2004 Andrew de Quincey | |
5 | + | |
6 | + AC-3 support: | |
7 | + | |
8 | + Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> | |
9 | + | |
10 | + This program is free software; you can redistribute it and/or modify | |
11 | + it under the terms of the GNU General Public License vs published by | |
12 | + the Free Software Foundation; either version 2 of the License, or | |
13 | + (at your option) any later version. | |
14 | + | |
15 | + This program is distributed in the hope that it will be useful, | |
16 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + GNU General Public License for more details. | |
19 | + | |
20 | + You should have received a copy of the GNU General Public License | |
21 | + along with this program; if not, write to the Free Software | |
22 | + Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA. | |
23 | + */ | |
24 | + | |
1 | 25 | #include <linux/module.h> |
2 | 26 | #include <linux/kernel.h> |
3 | 27 | #include <linux/string.h> |
... | ... | @@ -10,6 +34,8 @@ |
10 | 34 | #include <linux/types.h> |
11 | 35 | #include <linux/videodev2.h> |
12 | 36 | #include <media/v4l2-common.h> |
37 | +#include <media/v4l2-chip-ident.h> | |
38 | +#include <media/v4l2-i2c-drv-legacy.h> | |
13 | 39 | #include <linux/init.h> |
14 | 40 | #include <linux/crc32.h> |
15 | 41 | |
... | ... | @@ -27,9 +53,6 @@ |
27 | 53 | MODULE_AUTHOR("Andrew de Quincey"); |
28 | 54 | MODULE_LICENSE("GPL"); |
29 | 55 | |
30 | -static struct i2c_driver driver; | |
31 | -static struct i2c_client client_template; | |
32 | - | |
33 | 56 | enum saa6752hs_videoformat { |
34 | 57 | SAA6752HS_VF_D1 = 0, /* standard D1 video format: 720x576 */ |
35 | 58 | SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */ |
... | ... | @@ -46,7 +69,9 @@ |
46 | 69 | __u16 ts_pid_pcr; |
47 | 70 | |
48 | 71 | /* audio */ |
49 | - enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate; | |
72 | + enum v4l2_mpeg_audio_encoding au_encoding; | |
73 | + enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate; | |
74 | + enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate; | |
50 | 75 | |
51 | 76 | /* video */ |
52 | 77 | enum v4l2_mpeg_video_aspect vi_aspect; |
... | ... | @@ -70,7 +95,9 @@ |
70 | 95 | }; |
71 | 96 | |
72 | 97 | struct saa6752hs_state { |
73 | - struct i2c_client client; | |
98 | + int chip; | |
99 | + u32 revision; | |
100 | + int has_ac3; | |
74 | 101 | struct saa6752hs_mpeg_params params; |
75 | 102 | enum saa6752hs_videoformat video_format; |
76 | 103 | v4l2_std_id standard; |
77 | 104 | |
... | ... | @@ -157,7 +184,9 @@ |
157 | 184 | .vi_bitrate_peak = 6000, |
158 | 185 | .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, |
159 | 186 | |
187 | + .au_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, | |
160 | 188 | .au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K, |
189 | + .au_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_384K, | |
161 | 190 | }; |
162 | 191 | |
163 | 192 | /* ---------------------------------------------------------------------- */ |
164 | 193 | |
... | ... | @@ -230,8 +259,9 @@ |
230 | 259 | |
231 | 260 | |
232 | 261 | static int saa6752hs_set_bitrate(struct i2c_client* client, |
233 | - struct saa6752hs_mpeg_params* params) | |
262 | + struct saa6752hs_state *h) | |
234 | 263 | { |
264 | + struct saa6752hs_mpeg_params *params = &h->params; | |
235 | 265 | u8 buf[3]; |
236 | 266 | int tot_bitrate; |
237 | 267 | |
238 | 268 | |
239 | 269 | |
... | ... | @@ -263,11 +293,22 @@ |
263 | 293 | tot_bitrate = params->vi_bitrate; |
264 | 294 | } |
265 | 295 | |
296 | + /* set the audio encoding */ | |
297 | + buf[0] = 0x93; | |
298 | + if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) | |
299 | + buf[1] = 1; | |
300 | + else | |
301 | + buf[1] = 0; | |
302 | + i2c_master_send(client, buf, 2); | |
303 | + | |
266 | 304 | /* set the audio bitrate */ |
267 | 305 | buf[0] = 0x94; |
268 | - buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1; | |
306 | + if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) | |
307 | + buf[1] = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate; | |
308 | + else | |
309 | + buf[1] = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate; | |
310 | + tot_bitrate += buf[1] ? 384 : 256; | |
269 | 311 | i2c_master_send(client, buf, 2); |
270 | - tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384; | |
271 | 312 | |
272 | 313 | /* Note: the total max bitrate is determined by adding the video and audio |
273 | 314 | bitrates together and also adding an extra 768kbit/s to stay on the |
... | ... | @@ -332,7 +373,7 @@ |
332 | 373 | } |
333 | 374 | |
334 | 375 | |
335 | -static int handle_ctrl(struct saa6752hs_mpeg_params *params, | |
376 | +static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params, | |
336 | 377 | struct v4l2_ext_control *ctrl, unsigned int cmd) |
337 | 378 | { |
338 | 379 | int old = 0, new; |
... | ... | @@ -379,8 +420,9 @@ |
379 | 420 | params->ts_pid_pcr = new; |
380 | 421 | break; |
381 | 422 | case V4L2_CID_MPEG_AUDIO_ENCODING: |
382 | - old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2; | |
383 | - if (set && new != old) | |
423 | + old = params->au_encoding; | |
424 | + if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && | |
425 | + (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3)) | |
384 | 426 | return -ERANGE; |
385 | 427 | new = old; |
386 | 428 | break; |
... | ... | @@ -395,6 +437,19 @@ |
395 | 437 | new = V4L2_MPEG_AUDIO_L2_BITRATE_384K; |
396 | 438 | params->au_l2_bitrate = new; |
397 | 439 | break; |
440 | + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: | |
441 | + if (!has_ac3) | |
442 | + return -EINVAL; | |
443 | + old = params->au_ac3_bitrate; | |
444 | + if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K && | |
445 | + new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K) | |
446 | + return -ERANGE; | |
447 | + if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K) | |
448 | + new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K; | |
449 | + else | |
450 | + new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K; | |
451 | + params->au_ac3_bitrate = new; | |
452 | + break; | |
398 | 453 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: |
399 | 454 | old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; |
400 | 455 | if (set && new != old) |
401 | 456 | |
402 | 457 | |
... | ... | @@ -448,17 +503,19 @@ |
448 | 503 | return 0; |
449 | 504 | } |
450 | 505 | |
451 | -static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params, | |
506 | +static int saa6752hs_qctrl(struct saa6752hs_state *h, | |
452 | 507 | struct v4l2_queryctrl *qctrl) |
453 | 508 | { |
509 | + struct saa6752hs_mpeg_params *params = &h->params; | |
454 | 510 | int err; |
455 | 511 | |
456 | 512 | switch (qctrl->id) { |
457 | 513 | case V4L2_CID_MPEG_AUDIO_ENCODING: |
458 | 514 | return v4l2_ctrl_query_fill(qctrl, |
459 | 515 | V4L2_MPEG_AUDIO_ENCODING_LAYER_2, |
460 | - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, | |
461 | - V4L2_MPEG_AUDIO_ENCODING_LAYER_2); | |
516 | + h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : | |
517 | + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, | |
518 | + 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2); | |
462 | 519 | |
463 | 520 | case V4L2_CID_MPEG_AUDIO_L2_BITRATE: |
464 | 521 | return v4l2_ctrl_query_fill(qctrl, |
... | ... | @@ -466,6 +523,14 @@ |
466 | 523 | V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, |
467 | 524 | V4L2_MPEG_AUDIO_L2_BITRATE_256K); |
468 | 525 | |
526 | + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: | |
527 | + if (!h->has_ac3) | |
528 | + return -EINVAL; | |
529 | + return v4l2_ctrl_query_fill(qctrl, | |
530 | + V4L2_MPEG_AUDIO_AC3_BITRATE_256K, | |
531 | + V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1, | |
532 | + V4L2_MPEG_AUDIO_AC3_BITRATE_256K); | |
533 | + | |
469 | 534 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: |
470 | 535 | return v4l2_ctrl_query_fill(qctrl, |
471 | 536 | V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, |
472 | 537 | |
473 | 538 | |
474 | 539 | |
475 | 540 | |
476 | 541 | |
... | ... | @@ -512,38 +577,50 @@ |
512 | 577 | return -EINVAL; |
513 | 578 | } |
514 | 579 | |
515 | -static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params, | |
580 | +static int saa6752hs_qmenu(struct saa6752hs_state *h, | |
516 | 581 | struct v4l2_querymenu *qmenu) |
517 | 582 | { |
518 | - static const char *mpeg_audio_l2_bitrate[] = { | |
519 | - "", | |
520 | - "", | |
521 | - "", | |
522 | - "", | |
523 | - "", | |
524 | - "", | |
525 | - "", | |
526 | - "", | |
527 | - "", | |
528 | - "", | |
529 | - "", | |
530 | - "256 kbps", | |
531 | - "", | |
532 | - "384 kbps", | |
533 | - NULL | |
583 | + static const u32 mpeg_audio_encoding[] = { | |
584 | + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, | |
585 | + V4L2_CTRL_MENU_IDS_END | |
534 | 586 | }; |
587 | + static const u32 mpeg_audio_ac3_encoding[] = { | |
588 | + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, | |
589 | + V4L2_MPEG_AUDIO_ENCODING_AC3, | |
590 | + V4L2_CTRL_MENU_IDS_END | |
591 | + }; | |
592 | + static u32 mpeg_audio_l2_bitrate[] = { | |
593 | + V4L2_MPEG_AUDIO_L2_BITRATE_256K, | |
594 | + V4L2_MPEG_AUDIO_L2_BITRATE_384K, | |
595 | + V4L2_CTRL_MENU_IDS_END | |
596 | + }; | |
597 | + static u32 mpeg_audio_ac3_bitrate[] = { | |
598 | + V4L2_MPEG_AUDIO_AC3_BITRATE_256K, | |
599 | + V4L2_MPEG_AUDIO_AC3_BITRATE_384K, | |
600 | + V4L2_CTRL_MENU_IDS_END | |
601 | + }; | |
535 | 602 | struct v4l2_queryctrl qctrl; |
536 | 603 | int err; |
537 | 604 | |
538 | 605 | qctrl.id = qmenu->id; |
539 | - err = saa6752hs_qctrl(params, &qctrl); | |
606 | + err = saa6752hs_qctrl(h, &qctrl); | |
540 | 607 | if (err) |
541 | 608 | return err; |
542 | - if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE) | |
543 | - return v4l2_ctrl_query_menu(qmenu, &qctrl, | |
609 | + switch (qmenu->id) { | |
610 | + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: | |
611 | + return v4l2_ctrl_query_menu_valid_items(qmenu, | |
544 | 612 | mpeg_audio_l2_bitrate); |
545 | - return v4l2_ctrl_query_menu(qmenu, &qctrl, | |
546 | - v4l2_ctrl_get_menu(qmenu->id)); | |
613 | + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: | |
614 | + if (!h->has_ac3) | |
615 | + return -EINVAL; | |
616 | + return v4l2_ctrl_query_menu_valid_items(qmenu, | |
617 | + mpeg_audio_ac3_bitrate); | |
618 | + case V4L2_CID_MPEG_AUDIO_ENCODING: | |
619 | + return v4l2_ctrl_query_menu_valid_items(qmenu, | |
620 | + h->has_ac3 ? mpeg_audio_ac3_encoding : | |
621 | + mpeg_audio_encoding); | |
622 | + } | |
623 | + return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); | |
547 | 624 | } |
548 | 625 | |
549 | 626 | static int saa6752hs_init(struct i2c_client* client) |
... | ... | @@ -569,7 +646,7 @@ |
569 | 646 | i2c_master_send(client, buf, 2); |
570 | 647 | |
571 | 648 | /* set bitrate */ |
572 | - saa6752hs_set_bitrate(client, &h->params); | |
649 | + saa6752hs_set_bitrate(client, h); | |
573 | 650 | |
574 | 651 | /* Set GOP structure {3, 13} */ |
575 | 652 | buf[0] = 0x72; |
... | ... | @@ -688,45 +765,6 @@ |
688 | 765 | return 0; |
689 | 766 | } |
690 | 767 | |
691 | -static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) | |
692 | -{ | |
693 | - struct saa6752hs_state *h; | |
694 | - | |
695 | - | |
696 | - if (NULL == (h = kzalloc(sizeof(*h), GFP_KERNEL))) | |
697 | - return -ENOMEM; | |
698 | - h->client = client_template; | |
699 | - h->params = param_defaults; | |
700 | - h->client.adapter = adap; | |
701 | - h->client.addr = addr; | |
702 | - | |
703 | - /* Assume 625 input lines */ | |
704 | - h->standard = 0; | |
705 | - | |
706 | - i2c_set_clientdata(&h->client, h); | |
707 | - i2c_attach_client(&h->client); | |
708 | - | |
709 | - v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1); | |
710 | - return 0; | |
711 | -} | |
712 | - | |
713 | -static int saa6752hs_probe(struct i2c_adapter *adap) | |
714 | -{ | |
715 | - if (adap->class & I2C_CLASS_TV_ANALOG) | |
716 | - return i2c_probe(adap, &addr_data, saa6752hs_attach); | |
717 | - return 0; | |
718 | -} | |
719 | - | |
720 | -static int saa6752hs_detach(struct i2c_client *client) | |
721 | -{ | |
722 | - struct saa6752hs_state *h; | |
723 | - | |
724 | - h = i2c_get_clientdata(client); | |
725 | - i2c_detach_client(client); | |
726 | - kfree(h); | |
727 | - return 0; | |
728 | -} | |
729 | - | |
730 | 768 | static int |
731 | 769 | saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) |
732 | 770 | { |
... | ... | @@ -752,7 +790,8 @@ |
752 | 790 | return -EINVAL; |
753 | 791 | params = h->params; |
754 | 792 | for (i = 0; i < ctrls->count; i++) { |
755 | - if ((err = handle_ctrl(¶ms, ctrls->controls + i, cmd))) { | |
793 | + err = handle_ctrl(h->has_ac3, ¶ms, ctrls->controls + i, cmd); | |
794 | + if (err) { | |
756 | 795 | ctrls->error_idx = i; |
757 | 796 | return err; |
758 | 797 | } |
759 | 798 | |
... | ... | @@ -760,9 +799,9 @@ |
760 | 799 | h->params = params; |
761 | 800 | break; |
762 | 801 | case VIDIOC_QUERYCTRL: |
763 | - return saa6752hs_qctrl(&h->params, arg); | |
802 | + return saa6752hs_qctrl(h, arg); | |
764 | 803 | case VIDIOC_QUERYMENU: |
765 | - return saa6752hs_qmenu(&h->params, arg); | |
804 | + return saa6752hs_qmenu(h, arg); | |
766 | 805 | case VIDIOC_G_FMT: |
767 | 806 | { |
768 | 807 | struct v4l2_format *f = arg; |
... | ... | @@ -785,6 +824,11 @@ |
785 | 824 | case VIDIOC_S_STD: |
786 | 825 | h->standard = *((v4l2_std_id *) arg); |
787 | 826 | break; |
827 | + | |
828 | + case VIDIOC_G_CHIP_IDENT: | |
829 | + return v4l2_chip_ident_i2c_client(client, | |
830 | + arg, h->chip, h->revision); | |
831 | + | |
788 | 832 | default: |
789 | 833 | /* nothing */ |
790 | 834 | break; |
791 | 835 | |
792 | 836 | |
793 | 837 | |
794 | 838 | |
795 | 839 | |
796 | 840 | |
... | ... | @@ -793,36 +837,55 @@ |
793 | 837 | return err; |
794 | 838 | } |
795 | 839 | |
796 | -/* ----------------------------------------------------------------------- */ | |
840 | +static int saa6752hs_probe(struct i2c_client *client, | |
841 | + const struct i2c_device_id *id) | |
842 | +{ | |
843 | + struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL); | |
844 | + u8 addr = 0x13; | |
845 | + u8 data[12]; | |
797 | 846 | |
798 | -static struct i2c_driver driver = { | |
799 | - .driver = { | |
800 | - .name = "saa6752hs", | |
801 | - }, | |
802 | - .id = I2C_DRIVERID_SAA6752HS, | |
803 | - .attach_adapter = saa6752hs_probe, | |
804 | - .detach_client = saa6752hs_detach, | |
805 | - .command = saa6752hs_command, | |
806 | -}; | |
847 | + v4l_info(client, "chip found @ 0x%x (%s)\n", | |
848 | + client->addr << 1, client->adapter->name); | |
849 | + if (h == NULL) | |
850 | + return -ENOMEM; | |
807 | 851 | |
808 | -static struct i2c_client client_template = | |
809 | -{ | |
810 | - .name = "saa6752hs", | |
811 | - .driver = &driver, | |
812 | -}; | |
852 | + i2c_master_send(client, &addr, 1); | |
853 | + i2c_master_recv(client, data, sizeof(data)); | |
854 | + h->chip = V4L2_IDENT_SAA6752HS; | |
855 | + h->revision = (data[8] << 8) | data[9]; | |
856 | + h->has_ac3 = 0; | |
857 | + if (h->revision == 0x0206) { | |
858 | + h->chip = V4L2_IDENT_SAA6752HS_AC3; | |
859 | + h->has_ac3 = 1; | |
860 | + v4l_info(client, "support AC-3\n"); | |
861 | + } | |
862 | + h->params = param_defaults; | |
863 | + h->standard = 0; /* Assume 625 input lines */ | |
813 | 864 | |
814 | -static int __init saa6752hs_init_module(void) | |
815 | -{ | |
816 | - return i2c_add_driver(&driver); | |
865 | + i2c_set_clientdata(client, h); | |
866 | + return 0; | |
817 | 867 | } |
818 | 868 | |
819 | -static void __exit saa6752hs_cleanup_module(void) | |
869 | +static int saa6752hs_remove(struct i2c_client *client) | |
820 | 870 | { |
821 | - i2c_del_driver(&driver); | |
871 | + kfree(i2c_get_clientdata(client)); | |
872 | + return 0; | |
822 | 873 | } |
823 | 874 | |
824 | -module_init(saa6752hs_init_module); | |
825 | -module_exit(saa6752hs_cleanup_module); | |
875 | +static const struct i2c_device_id saa6752hs_id[] = { | |
876 | + { "saa6752hs", 0 }, | |
877 | + { } | |
878 | +}; | |
879 | +MODULE_DEVICE_TABLE(i2c, saa6752hs_id); | |
880 | + | |
881 | +static struct v4l2_i2c_driver_data v4l2_i2c_data = { | |
882 | + .name = "saa6752hs", | |
883 | + .driverid = I2C_DRIVERID_SAA6752HS, | |
884 | + .command = saa6752hs_command, | |
885 | + .probe = saa6752hs_probe, | |
886 | + .remove = saa6752hs_remove, | |
887 | + .id_table = saa6752hs_id, | |
888 | +}; | |
826 | 889 | |
827 | 890 | /* |
828 | 891 | * Overrides for Emacs so that we follow Linus's tabbing style. |
drivers/media/video/saa7134/saa7134-empress.c
... | ... | @@ -29,6 +29,7 @@ |
29 | 29 | |
30 | 30 | #include <media/saa6752hs.h> |
31 | 31 | #include <media/v4l2-common.h> |
32 | +#include <media/v4l2-chip-ident.h> | |
32 | 33 | |
33 | 34 | /* ------------------------------------------------------------------ */ |
34 | 35 | |
... | ... | @@ -403,6 +404,25 @@ |
403 | 404 | return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c); |
404 | 405 | } |
405 | 406 | |
407 | +static int empress_g_chip_ident(struct file *file, void *fh, | |
408 | + struct v4l2_chip_ident *chip) | |
409 | +{ | |
410 | + struct saa7134_dev *dev = file->private_data; | |
411 | + | |
412 | + chip->ident = V4L2_IDENT_NONE; | |
413 | + chip->revision = 0; | |
414 | + if (dev->mpeg_i2c_client == NULL) | |
415 | + return -EINVAL; | |
416 | + if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER && | |
417 | + chip->match_chip == I2C_DRIVERID_SAA6752HS) | |
418 | + return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip); | |
419 | + if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR && | |
420 | + chip->match_chip == dev->mpeg_i2c_client->addr) | |
421 | + return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip); | |
422 | + return -EINVAL; | |
423 | +} | |
424 | + | |
425 | + | |
406 | 426 | static const struct file_operations ts_fops = |
407 | 427 | { |
408 | 428 | .owner = THIS_MODULE, |
409 | 429 | |
... | ... | @@ -431,11 +451,11 @@ |
431 | 451 | .vidioc_enum_input = empress_enum_input, |
432 | 452 | .vidioc_g_input = empress_g_input, |
433 | 453 | .vidioc_s_input = empress_s_input, |
434 | - | |
435 | 454 | .vidioc_queryctrl = empress_queryctrl, |
436 | 455 | .vidioc_querymenu = empress_querymenu, |
437 | 456 | .vidioc_g_ctrl = empress_g_ctrl, |
438 | 457 | .vidioc_s_ctrl = empress_s_ctrl, |
458 | + .vidioc_g_chip_ident = empress_g_chip_ident, | |
439 | 459 | }; |
440 | 460 | |
441 | 461 | /* ----------------------------------------------------------- */ |
drivers/media/video/v4l2-common.c
... | ... | @@ -637,13 +637,17 @@ |
637 | 637 | EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); |
638 | 638 | |
639 | 639 | /* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and |
640 | - the menu. The qctrl pointer may be NULL, in which case it is ignored. */ | |
640 | + the menu. The qctrl pointer may be NULL, in which case it is ignored. | |
641 | + If menu_items is NULL, then the menu items are retrieved using | |
642 | + v4l2_ctrl_get_menu. */ | |
641 | 643 | int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl, |
642 | 644 | const char **menu_items) |
643 | 645 | { |
644 | 646 | int i; |
645 | 647 | |
646 | 648 | qmenu->reserved = 0; |
649 | + if (menu_items == NULL) | |
650 | + menu_items = v4l2_ctrl_get_menu(qmenu->id); | |
647 | 651 | if (menu_items == NULL || |
648 | 652 | (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum))) |
649 | 653 | return -EINVAL; |
include/media/v4l2-chip-ident.h
... | ... | @@ -72,6 +72,10 @@ |
72 | 72 | /* module cs5345: just ident 5345 */ |
73 | 73 | V4L2_IDENT_CS5345 = 5345, |
74 | 74 | |
75 | + /* module saa6752hs: reserved range 6750-6759 */ | |
76 | + V4L2_IDENT_SAA6752HS = 6752, | |
77 | + V4L2_IDENT_SAA6752HS_AC3 = 6753, | |
78 | + | |
75 | 79 | /* module wm8739: just ident 8739 */ |
76 | 80 | V4L2_IDENT_WM8739 = 8739, |
77 | 81 |