aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Bugge <marbugge@cisco.com>2014-12-19 07:14:21 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-01-27 07:18:50 -0500
commit2c676f378edb16cb68f7815581c8119fc43a4b85 (patch)
tree310e66ff7eb4de75e8b2bdbafd513e004b29c11a
parent05c80d75f10ad7d3f95444b65788d6a0bbb4380d (diff)
[media] hdmi: added unpack and logging functions for InfoFrames
When receiving video it is very useful to be able to unpack the InfoFrames. Logging is useful as well, both for transmitters and receivers. Especially when implementing the VIDIOC_LOG_STATUS ioctl (supported by many V4L2 drivers) for a receiver it is important to be able to easily log what the InfoFrame contains. This greatly simplifies debugging. Signed-off-by: Martin Bugge <marbugge@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r--drivers/video/hdmi.c822
-rw-r--r--include/linux/hdmi.h4
2 files changed, 819 insertions, 7 deletions
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 9e758a8f890d..a7c6ae4e10e5 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -27,10 +27,12 @@
27#include <linux/export.h> 27#include <linux/export.h>
28#include <linux/hdmi.h> 28#include <linux/hdmi.h>
29#include <linux/string.h> 29#include <linux/string.h>
30#include <linux/device.h>
30 31
31static void hdmi_infoframe_checksum(void *buffer, size_t size) 32#define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
33
34static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
32{ 35{
33 u8 *ptr = buffer;
34 u8 csum = 0; 36 u8 csum = 0;
35 size_t i; 37 size_t i;
36 38
@@ -38,7 +40,14 @@ static void hdmi_infoframe_checksum(void *buffer, size_t size)
38 for (i = 0; i < size; i++) 40 for (i = 0; i < size; i++)
39 csum += ptr[i]; 41 csum += ptr[i];
40 42
41 ptr[3] = 256 - csum; 43 return 256 - csum;
44}
45
46static void hdmi_infoframe_set_checksum(void *buffer, size_t size)
47{
48 u8 *ptr = buffer;
49
50 ptr[3] = hdmi_infoframe_checksum(buffer, size);
42} 51}
43 52
44/** 53/**
@@ -136,7 +145,7 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
136 ptr[11] = frame->right_bar & 0xff; 145 ptr[11] = frame->right_bar & 0xff;
137 ptr[12] = (frame->right_bar >> 8) & 0xff; 146 ptr[12] = (frame->right_bar >> 8) & 0xff;
138 147
139 hdmi_infoframe_checksum(buffer, length); 148 hdmi_infoframe_set_checksum(buffer, length);
140 149
141 return length; 150 return length;
142} 151}
@@ -206,7 +215,7 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
206 215
207 ptr[24] = frame->sdi; 216 ptr[24] = frame->sdi;
208 217
209 hdmi_infoframe_checksum(buffer, length); 218 hdmi_infoframe_set_checksum(buffer, length);
210 219
211 return length; 220 return length;
212} 221}
@@ -281,7 +290,7 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
281 if (frame->downmix_inhibit) 290 if (frame->downmix_inhibit)
282 ptr[4] |= BIT(7); 291 ptr[4] |= BIT(7);
283 292
284 hdmi_infoframe_checksum(buffer, length); 293 hdmi_infoframe_set_checksum(buffer, length);
285 294
286 return length; 295 return length;
287} 296}
@@ -373,7 +382,7 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
373 ptr[9] = (frame->s3d_ext_data & 0xf) << 4; 382 ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
374 } 383 }
375 384
376 hdmi_infoframe_checksum(buffer, length); 385 hdmi_infoframe_set_checksum(buffer, length);
377 386
378 return length; 387 return length;
379} 388}
@@ -434,3 +443,802 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
434 return length; 443 return length;
435} 444}
436EXPORT_SYMBOL(hdmi_infoframe_pack); 445EXPORT_SYMBOL(hdmi_infoframe_pack);
446
447static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
448{
449 if (type < 0x80 || type > 0x9f)
450 return "Invalid";
451 switch (type) {
452 case HDMI_INFOFRAME_TYPE_VENDOR:
453 return "Vendor";
454 case HDMI_INFOFRAME_TYPE_AVI:
455 return "Auxiliary Video Information (AVI)";
456 case HDMI_INFOFRAME_TYPE_SPD:
457 return "Source Product Description (SPD)";
458 case HDMI_INFOFRAME_TYPE_AUDIO:
459 return "Audio";
460 }
461 return "Reserved";
462}
463
464static void hdmi_infoframe_log_header(const char *level,
465 struct device *dev,
466 struct hdmi_any_infoframe *frame)
467{
468 hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
469 hdmi_infoframe_type_get_name(frame->type),
470 frame->version, frame->length);
471}
472
473static const char *hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)
474{
475 switch (colorspace) {
476 case HDMI_COLORSPACE_RGB:
477 return "RGB";
478 case HDMI_COLORSPACE_YUV422:
479 return "YCbCr 4:2:2";
480 case HDMI_COLORSPACE_YUV444:
481 return "YCbCr 4:4:4";
482 case HDMI_COLORSPACE_YUV420:
483 return "YCbCr 4:2:0";
484 case HDMI_COLORSPACE_RESERVED4:
485 return "Reserved (4)";
486 case HDMI_COLORSPACE_RESERVED5:
487 return "Reserved (5)";
488 case HDMI_COLORSPACE_RESERVED6:
489 return "Reserved (6)";
490 case HDMI_COLORSPACE_IDO_DEFINED:
491 return "IDO Defined";
492 }
493 return "Invalid";
494}
495
496static const char *hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)
497{
498 switch (scan_mode) {
499 case HDMI_SCAN_MODE_NONE:
500 return "No Data";
501 case HDMI_SCAN_MODE_OVERSCAN:
502 return "Overscan";
503 case HDMI_SCAN_MODE_UNDERSCAN:
504 return "Underscan";
505 case HDMI_SCAN_MODE_RESERVED:
506 return "Reserved";
507 }
508 return "Invalid";
509}
510
511static const char *hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)
512{
513 switch (colorimetry) {
514 case HDMI_COLORIMETRY_NONE:
515 return "No Data";
516 case HDMI_COLORIMETRY_ITU_601:
517 return "ITU601";
518 case HDMI_COLORIMETRY_ITU_709:
519 return "ITU709";
520 case HDMI_COLORIMETRY_EXTENDED:
521 return "Extended";
522 }
523 return "Invalid";
524}
525
526static const char *
527hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
528{
529 switch (picture_aspect) {
530 case HDMI_PICTURE_ASPECT_NONE:
531 return "No Data";
532 case HDMI_PICTURE_ASPECT_4_3:
533 return "4:3";
534 case HDMI_PICTURE_ASPECT_16_9:
535 return "16:9";
536 case HDMI_PICTURE_ASPECT_RESERVED:
537 return "Reserved";
538 }
539 return "Invalid";
540}
541
542static const char *
543hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)
544{
545 if (active_aspect < 0 || active_aspect > 0xf)
546 return "Invalid";
547
548 switch (active_aspect) {
549 case HDMI_ACTIVE_ASPECT_16_9_TOP:
550 return "16:9 Top";
551 case HDMI_ACTIVE_ASPECT_14_9_TOP:
552 return "14:9 Top";
553 case HDMI_ACTIVE_ASPECT_16_9_CENTER:
554 return "16:9 Center";
555 case HDMI_ACTIVE_ASPECT_PICTURE:
556 return "Same as Picture";
557 case HDMI_ACTIVE_ASPECT_4_3:
558 return "4:3";
559 case HDMI_ACTIVE_ASPECT_16_9:
560 return "16:9";
561 case HDMI_ACTIVE_ASPECT_14_9:
562 return "14:9";
563 case HDMI_ACTIVE_ASPECT_4_3_SP_14_9:
564 return "4:3 SP 14:9";
565 case HDMI_ACTIVE_ASPECT_16_9_SP_14_9:
566 return "16:9 SP 14:9";
567 case HDMI_ACTIVE_ASPECT_16_9_SP_4_3:
568 return "16:9 SP 4:3";
569 }
570 return "Reserved";
571}
572
573static const char *
574hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)
575{
576 switch (ext_col) {
577 case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601:
578 return "xvYCC 601";
579 case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709:
580 return "xvYCC 709";
581 case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
582 return "sYCC 601";
583 case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601:
584 return "Adobe YCC 601";
585 case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB:
586 return "Adobe RGB";
587 case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
588 return "BT.2020 Constant Luminance";
589 case HDMI_EXTENDED_COLORIMETRY_BT2020:
590 return "BT.2020";
591 case HDMI_EXTENDED_COLORIMETRY_RESERVED:
592 return "Reserved";
593 }
594 return "Invalid";
595}
596
597static const char *
598hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)
599{
600 switch (qrange) {
601 case HDMI_QUANTIZATION_RANGE_DEFAULT:
602 return "Default";
603 case HDMI_QUANTIZATION_RANGE_LIMITED:
604 return "Limited";
605 case HDMI_QUANTIZATION_RANGE_FULL:
606 return "Full";
607 case HDMI_QUANTIZATION_RANGE_RESERVED:
608 return "Reserved";
609 }
610 return "Invalid";
611}
612
613static const char *hdmi_nups_get_name(enum hdmi_nups nups)
614{
615 switch (nups) {
616 case HDMI_NUPS_UNKNOWN:
617 return "Unknown Non-uniform Scaling";
618 case HDMI_NUPS_HORIZONTAL:
619 return "Horizontally Scaled";
620 case HDMI_NUPS_VERTICAL:
621 return "Vertically Scaled";
622 case HDMI_NUPS_BOTH:
623 return "Horizontally and Vertically Scaled";
624 }
625 return "Invalid";
626}
627
628static const char *
629hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)
630{
631 switch (qrange) {
632 case HDMI_YCC_QUANTIZATION_RANGE_LIMITED:
633 return "Limited";
634 case HDMI_YCC_QUANTIZATION_RANGE_FULL:
635 return "Full";
636 }
637 return "Invalid";
638}
639
640static const char *
641hdmi_content_type_get_name(enum hdmi_content_type content_type)
642{
643 switch (content_type) {
644 case HDMI_CONTENT_TYPE_GRAPHICS:
645 return "Graphics";
646 case HDMI_CONTENT_TYPE_PHOTO:
647 return "Photo";
648 case HDMI_CONTENT_TYPE_CINEMA:
649 return "Cinema";
650 case HDMI_CONTENT_TYPE_GAME:
651 return "Game";
652 }
653 return "Invalid";
654}
655
656/**
657 * hdmi_avi_infoframe_log() - log info of HDMI AVI infoframe
658 * @level: logging level
659 * @dev: device
660 * @frame: HDMI AVI infoframe
661 */
662static void hdmi_avi_infoframe_log(const char *level,
663 struct device *dev,
664 struct hdmi_avi_infoframe *frame)
665{
666 hdmi_infoframe_log_header(level, dev,
667 (struct hdmi_any_infoframe *)frame);
668
669 hdmi_log(" colorspace: %s\n",
670 hdmi_colorspace_get_name(frame->colorspace));
671 hdmi_log(" scan mode: %s\n",
672 hdmi_scan_mode_get_name(frame->scan_mode));
673 hdmi_log(" colorimetry: %s\n",
674 hdmi_colorimetry_get_name(frame->colorimetry));
675 hdmi_log(" picture aspect: %s\n",
676 hdmi_picture_aspect_get_name(frame->picture_aspect));
677 hdmi_log(" active aspect: %s\n",
678 hdmi_active_aspect_get_name(frame->active_aspect));
679 hdmi_log(" itc: %s\n", frame->itc ? "IT Content" : "No Data");
680 hdmi_log(" extended colorimetry: %s\n",
681 hdmi_extended_colorimetry_get_name(frame->extended_colorimetry));
682 hdmi_log(" quantization range: %s\n",
683 hdmi_quantization_range_get_name(frame->quantization_range));
684 hdmi_log(" nups: %s\n", hdmi_nups_get_name(frame->nups));
685 hdmi_log(" video code: %u\n", frame->video_code);
686 hdmi_log(" ycc quantization range: %s\n",
687 hdmi_ycc_quantization_range_get_name(frame->ycc_quantization_range));
688 hdmi_log(" hdmi content type: %s\n",
689 hdmi_content_type_get_name(frame->content_type));
690 hdmi_log(" pixel repeat: %u\n", frame->pixel_repeat);
691 hdmi_log(" bar top %u, bottom %u, left %u, right %u\n",
692 frame->top_bar, frame->bottom_bar,
693 frame->left_bar, frame->right_bar);
694}
695
696static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
697{
698 if (sdi < 0 || sdi > 0xff)
699 return "Invalid";
700 switch (sdi) {
701 case HDMI_SPD_SDI_UNKNOWN:
702 return "Unknown";
703 case HDMI_SPD_SDI_DSTB:
704 return "Digital STB";
705 case HDMI_SPD_SDI_DVDP:
706 return "DVD Player";
707 case HDMI_SPD_SDI_DVHS:
708 return "D-VHS";
709 case HDMI_SPD_SDI_HDDVR:
710 return "HDD Videorecorder";
711 case HDMI_SPD_SDI_DVC:
712 return "DVC";
713 case HDMI_SPD_SDI_DSC:
714 return "DSC";
715 case HDMI_SPD_SDI_VCD:
716 return "Video CD";
717 case HDMI_SPD_SDI_GAME:
718 return "Game";
719 case HDMI_SPD_SDI_PC:
720 return "PC General";
721 case HDMI_SPD_SDI_BD:
722 return "Blu-Ray Disc (BD)";
723 case HDMI_SPD_SDI_SACD:
724 return "Super Audio CD";
725 case HDMI_SPD_SDI_HDDVD:
726 return "HD DVD";
727 case HDMI_SPD_SDI_PMP:
728 return "PMP";
729 }
730 return "Reserved";
731}
732
733/**
734 * hdmi_spd_infoframe_log() - log info of HDMI SPD infoframe
735 * @level: logging level
736 * @dev: device
737 * @frame: HDMI SPD infoframe
738 */
739static void hdmi_spd_infoframe_log(const char *level,
740 struct device *dev,
741 struct hdmi_spd_infoframe *frame)
742{
743 u8 buf[17];
744
745 hdmi_infoframe_log_header(level, dev,
746 (struct hdmi_any_infoframe *)frame);
747
748 memset(buf, 0, sizeof(buf));
749
750 strncpy(buf, frame->vendor, 8);
751 hdmi_log(" vendor: %s\n", buf);
752 strncpy(buf, frame->product, 16);
753 hdmi_log(" product: %s\n", buf);
754 hdmi_log(" source device information: %s (0x%x)\n",
755 hdmi_spd_sdi_get_name(frame->sdi), frame->sdi);
756}
757
758static const char *
759hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)
760{
761 switch (coding_type) {
762 case HDMI_AUDIO_CODING_TYPE_STREAM:
763 return "Refer to Stream Header";
764 case HDMI_AUDIO_CODING_TYPE_PCM:
765 return "PCM";
766 case HDMI_AUDIO_CODING_TYPE_AC3:
767 return "AC-3";
768 case HDMI_AUDIO_CODING_TYPE_MPEG1:
769 return "MPEG1";
770 case HDMI_AUDIO_CODING_TYPE_MP3:
771 return "MP3";
772 case HDMI_AUDIO_CODING_TYPE_MPEG2:
773 return "MPEG2";
774 case HDMI_AUDIO_CODING_TYPE_AAC_LC:
775 return "AAC";
776 case HDMI_AUDIO_CODING_TYPE_DTS:
777 return "DTS";
778 case HDMI_AUDIO_CODING_TYPE_ATRAC:
779 return "ATRAC";
780 case HDMI_AUDIO_CODING_TYPE_DSD:
781 return "One Bit Audio";
782 case HDMI_AUDIO_CODING_TYPE_EAC3:
783 return "Dolby Digital +";
784 case HDMI_AUDIO_CODING_TYPE_DTS_HD:
785 return "DTS-HD";
786 case HDMI_AUDIO_CODING_TYPE_MLP:
787 return "MAT (MLP)";
788 case HDMI_AUDIO_CODING_TYPE_DST:
789 return "DST";
790 case HDMI_AUDIO_CODING_TYPE_WMA_PRO:
791 return "WMA PRO";
792 case HDMI_AUDIO_CODING_TYPE_CXT:
793 return "Refer to CXT";
794 }
795 return "Invalid";
796}
797
798static const char *
799hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)
800{
801 switch (sample_size) {
802 case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
803 return "Refer to Stream Header";
804 case HDMI_AUDIO_SAMPLE_SIZE_16:
805 return "16 bit";
806 case HDMI_AUDIO_SAMPLE_SIZE_20:
807 return "20 bit";
808 case HDMI_AUDIO_SAMPLE_SIZE_24:
809 return "24 bit";
810 }
811 return "Invalid";
812}
813
814static const char *
815hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)
816{
817 switch (freq) {
818 case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
819 return "Refer to Stream Header";
820 case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
821 return "32 kHz";
822 case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
823 return "44.1 kHz (CD)";
824 case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
825 return "48 kHz";
826 case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
827 return "88.2 kHz";
828 case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
829 return "96 kHz";
830 case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
831 return "176.4 kHz";
832 case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
833 return "192 kHz";
834 }
835 return "Invalid";
836}
837
838static const char *
839hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
840{
841 if (ctx < 0 || ctx > 0x1f)
842 return "Invalid";
843
844 switch (ctx) {
845 case HDMI_AUDIO_CODING_TYPE_EXT_STREAM:
846 return "Refer to CT";
847 case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC:
848 return "HE AAC";
849 case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2:
850 return "HE AAC v2";
851 case HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND:
852 return "MPEG SURROUND";
853 case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC:
854 return "MPEG-4 HE AAC";
855 case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2:
856 return "MPEG-4 HE AAC v2";
857 case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC:
858 return "MPEG-4 AAC LC";
859 case HDMI_AUDIO_CODING_TYPE_EXT_DRA:
860 return "DRA";
861 case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND:
862 return "MPEG-4 HE AAC + MPEG Surround";
863 case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND:
864 return "MPEG-4 AAC LC + MPEG Surround";
865 }
866 return "Reserved";
867}
868
869/**
870 * hdmi_audio_infoframe_log() - log info of HDMI AUDIO infoframe
871 * @level: logging level
872 * @dev: device
873 * @frame: HDMI AUDIO infoframe
874 */
875static void hdmi_audio_infoframe_log(const char *level,
876 struct device *dev,
877 struct hdmi_audio_infoframe *frame)
878{
879 hdmi_infoframe_log_header(level, dev,
880 (struct hdmi_any_infoframe *)frame);
881
882 if (frame->channels)
883 hdmi_log(" channels: %u\n", frame->channels - 1);
884 else
885 hdmi_log(" channels: Refer to stream header\n");
886 hdmi_log(" coding type: %s\n",
887 hdmi_audio_coding_type_get_name(frame->coding_type));
888 hdmi_log(" sample size: %s\n",
889 hdmi_audio_sample_size_get_name(frame->sample_size));
890 hdmi_log(" sample frequency: %s\n",
891 hdmi_audio_sample_frequency_get_name(frame->sample_frequency));
892 hdmi_log(" coding type ext: %s\n",
893 hdmi_audio_coding_type_ext_get_name(frame->coding_type_ext));
894 hdmi_log(" channel allocation: 0x%x\n",
895 frame->channel_allocation);
896 hdmi_log(" level shift value: %u dB\n",
897 frame->level_shift_value);
898 hdmi_log(" downmix inhibit: %s\n",
899 frame->downmix_inhibit ? "Yes" : "No");
900}
901
902static const char *
903hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
904{
905 if (s3d_struct < 0 || s3d_struct > 0xf)
906 return "Invalid";
907
908 switch (s3d_struct) {
909 case HDMI_3D_STRUCTURE_FRAME_PACKING:
910 return "Frame Packing";
911 case HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE:
912 return "Field Alternative";
913 case HDMI_3D_STRUCTURE_LINE_ALTERNATIVE:
914 return "Line Alternative";
915 case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL:
916 return "Side-by-side (Full)";
917 case HDMI_3D_STRUCTURE_L_DEPTH:
918 return "L + Depth";
919 case HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH:
920 return "L + Depth + Graphics + Graphics-depth";
921 case HDMI_3D_STRUCTURE_TOP_AND_BOTTOM:
922 return "Top-and-Bottom";
923 case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF:
924 return "Side-by-side (Half)";
925 default:
926 break;
927 }
928 return "Reserved";
929}
930
931/**
932 * hdmi_vendor_infoframe_log() - log info of HDMI VENDOR infoframe
933 * @level: logging level
934 * @dev: device
935 * @frame: HDMI VENDOR infoframe
936 */
937static void
938hdmi_vendor_any_infoframe_log(const char *level,
939 struct device *dev,
940 union hdmi_vendor_any_infoframe *frame)
941{
942 struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
943
944 hdmi_infoframe_log_header(level, dev,
945 (struct hdmi_any_infoframe *)frame);
946
947 if (frame->any.oui != HDMI_IEEE_OUI) {
948 hdmi_log(" not a HDMI vendor infoframe\n");
949 return;
950 }
951 if (hvf->vic == 0 && hvf->s3d_struct == HDMI_3D_STRUCTURE_INVALID) {
952 hdmi_log(" empty frame\n");
953 return;
954 }
955
956 if (hvf->vic)
957 hdmi_log(" HDMI VIC: %u\n", hvf->vic);
958 if (hvf->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
959 hdmi_log(" 3D structure: %s\n",
960 hdmi_3d_structure_get_name(hvf->s3d_struct));
961 if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
962 hdmi_log(" 3D extension data: %d\n",
963 hvf->s3d_ext_data);
964 }
965}
966
967/**
968 * hdmi_infoframe_log() - log info of HDMI infoframe
969 * @level: logging level
970 * @dev: device
971 * @frame: HDMI infoframe
972 */
973void hdmi_infoframe_log(const char *level,
974 struct device *dev,
975 union hdmi_infoframe *frame)
976{
977 switch (frame->any.type) {
978 case HDMI_INFOFRAME_TYPE_AVI:
979 hdmi_avi_infoframe_log(level, dev, &frame->avi);
980 break;
981 case HDMI_INFOFRAME_TYPE_SPD:
982 hdmi_spd_infoframe_log(level, dev, &frame->spd);
983 break;
984 case HDMI_INFOFRAME_TYPE_AUDIO:
985 hdmi_audio_infoframe_log(level, dev, &frame->audio);
986 break;
987 case HDMI_INFOFRAME_TYPE_VENDOR:
988 hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
989 break;
990 }
991}
992EXPORT_SYMBOL(hdmi_infoframe_log);
993
994/**
995 * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
996 * @buffer: source buffer
997 * @frame: HDMI AVI infoframe
998 *
999 * Unpacks the information contained in binary @buffer into a structured
1000 * @frame of the HDMI Auxiliary Video (AVI) information frame.
1001 * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1002 * specification.
1003 *
1004 * Returns 0 on success or a negative error code on failure.
1005 */
1006static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
1007 void *buffer)
1008{
1009 u8 *ptr = buffer;
1010 int ret;
1011
1012 if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
1013 ptr[1] != 2 ||
1014 ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
1015 return -EINVAL;
1016
1017 if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AVI)) != 0)
1018 return -EINVAL;
1019
1020 ret = hdmi_avi_infoframe_init(frame);
1021 if (ret)
1022 return ret;
1023
1024 ptr += HDMI_INFOFRAME_HEADER_SIZE;
1025
1026 frame->colorspace = (ptr[0] >> 5) & 0x3;
1027 if (ptr[0] & 0x10)
1028 frame->active_aspect = ptr[1] & 0xf;
1029 if (ptr[0] & 0x8) {
1030 frame->top_bar = (ptr[5] << 8) + ptr[6];
1031 frame->bottom_bar = (ptr[7] << 8) + ptr[8];
1032 }
1033 if (ptr[0] & 0x4) {
1034 frame->left_bar = (ptr[9] << 8) + ptr[10];
1035 frame->right_bar = (ptr[11] << 8) + ptr[12];
1036 }
1037 frame->scan_mode = ptr[0] & 0x3;
1038
1039 frame->colorimetry = (ptr[1] >> 6) & 0x3;
1040 frame->picture_aspect = (ptr[1] >> 4) & 0x3;
1041 frame->active_aspect = ptr[1] & 0xf;
1042
1043 frame->itc = ptr[2] & 0x80 ? true : false;
1044 frame->extended_colorimetry = (ptr[2] >> 4) & 0x7;
1045 frame->quantization_range = (ptr[2] >> 2) & 0x3;
1046 frame->nups = ptr[2] & 0x3;
1047
1048 frame->video_code = ptr[3] & 0x7f;
1049 frame->ycc_quantization_range = (ptr[4] >> 6) & 0x3;
1050 frame->content_type = (ptr[4] >> 4) & 0x3;
1051
1052 frame->pixel_repeat = ptr[4] & 0xf;
1053
1054 return 0;
1055}
1056
1057/**
1058 * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
1059 * @buffer: source buffer
1060 * @frame: HDMI SPD infoframe
1061 *
1062 * Unpacks the information contained in binary @buffer into a structured
1063 * @frame of the HDMI Source Product Description (SPD) information frame.
1064 * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1065 * specification.
1066 *
1067 * Returns 0 on success or a negative error code on failure.
1068 */
1069static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
1070 void *buffer)
1071{
1072 u8 *ptr = buffer;
1073 int ret;
1074
1075 if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
1076 ptr[1] != 1 ||
1077 ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
1078 return -EINVAL;
1079 }
1080
1081 if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(SPD)) != 0)
1082 return -EINVAL;
1083
1084 ptr += HDMI_INFOFRAME_HEADER_SIZE;
1085
1086 ret = hdmi_spd_infoframe_init(frame, ptr, ptr + 8);
1087 if (ret)
1088 return ret;
1089
1090 frame->sdi = ptr[24];
1091
1092 return 0;
1093}
1094
1095/**
1096 * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
1097 * @buffer: source buffer
1098 * @frame: HDMI Audio infoframe
1099 *
1100 * Unpacks the information contained in binary @buffer into a structured
1101 * @frame of the HDMI Audio information frame.
1102 * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1103 * specification.
1104 *
1105 * Returns 0 on success or a negative error code on failure.
1106 */
1107static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
1108 void *buffer)
1109{
1110 u8 *ptr = buffer;
1111 int ret;
1112
1113 if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
1114 ptr[1] != 1 ||
1115 ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
1116 return -EINVAL;
1117 }
1118
1119 if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AUDIO)) != 0)
1120 return -EINVAL;
1121
1122 ret = hdmi_audio_infoframe_init(frame);
1123 if (ret)
1124 return ret;
1125
1126 ptr += HDMI_INFOFRAME_HEADER_SIZE;
1127
1128 frame->channels = ptr[0] & 0x7;
1129 frame->coding_type = (ptr[0] >> 4) & 0xf;
1130 frame->sample_size = ptr[1] & 0x3;
1131 frame->sample_frequency = (ptr[1] >> 2) & 0x7;
1132 frame->coding_type_ext = ptr[2] & 0x1f;
1133 frame->channel_allocation = ptr[3];
1134 frame->level_shift_value = (ptr[4] >> 3) & 0xf;
1135 frame->downmix_inhibit = ptr[4] & 0x80 ? true : false;
1136
1137 return 0;
1138}
1139
1140/**
1141 * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
1142 * @buffer: source buffer
1143 * @frame: HDMI Vendor infoframe
1144 *
1145 * Unpacks the information contained in binary @buffer into a structured
1146 * @frame of the HDMI Vendor information frame.
1147 * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1148 * specification.
1149 *
1150 * Returns 0 on success or a negative error code on failure.
1151 */
1152static int
1153hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
1154 void *buffer)
1155{
1156 u8 *ptr = buffer;
1157 size_t length;
1158 int ret;
1159 u8 hdmi_video_format;
1160 struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
1161
1162 if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
1163 ptr[1] != 1 ||
1164 (ptr[2] != 5 && ptr[2] != 6))
1165 return -EINVAL;
1166
1167 length = ptr[2];
1168
1169 if (hdmi_infoframe_checksum(buffer,
1170 HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
1171 return -EINVAL;
1172
1173 ptr += HDMI_INFOFRAME_HEADER_SIZE;
1174
1175 /* HDMI OUI */
1176 if ((ptr[0] != 0x03) ||
1177 (ptr[1] != 0x0c) ||
1178 (ptr[2] != 0x00))
1179 return -EINVAL;
1180
1181 hdmi_video_format = ptr[3] >> 5;
1182
1183 if (hdmi_video_format > 0x2)
1184 return -EINVAL;
1185
1186 ret = hdmi_vendor_infoframe_init(hvf);
1187 if (ret)
1188 return ret;
1189
1190 hvf->length = length;
1191
1192 if (hdmi_video_format == 0x1) {
1193 hvf->vic = ptr[4];
1194 } else if (hdmi_video_format == 0x2) {
1195 hvf->s3d_struct = ptr[4] >> 4;
1196 if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
1197 if (length == 6)
1198 hvf->s3d_ext_data = ptr[5] >> 4;
1199 else
1200 return -EINVAL;
1201 }
1202 }
1203
1204 return 0;
1205}
1206
1207/**
1208 * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
1209 * @buffer: source buffer
1210 * @frame: HDMI infoframe
1211 *
1212 * Unpacks the information contained in binary buffer @buffer into a structured
1213 * @frame of a HDMI infoframe.
1214 * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
1215 * specification.
1216 *
1217 * Returns 0 on success or a negative error code on failure.
1218 */
1219int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
1220{
1221 int ret;
1222 u8 *ptr = buffer;
1223
1224 switch (ptr[0]) {
1225 case HDMI_INFOFRAME_TYPE_AVI:
1226 ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
1227 break;
1228 case HDMI_INFOFRAME_TYPE_SPD:
1229 ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
1230 break;
1231 case HDMI_INFOFRAME_TYPE_AUDIO:
1232 ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
1233 break;
1234 case HDMI_INFOFRAME_TYPE_VENDOR:
1235 ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
1236 break;
1237 default:
1238 ret = -EINVAL;
1239 break;
1240 }
1241
1242 return ret;
1243}
1244EXPORT_SYMBOL(hdmi_infoframe_unpack);
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 5afc0bff2bbe..2ff34315a1bb 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -25,6 +25,7 @@
25#define __LINUX_HDMI_H_ 25#define __LINUX_HDMI_H_
26 26
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/device.h>
28 29
29enum hdmi_infoframe_type { 30enum hdmi_infoframe_type {
30 HDMI_INFOFRAME_TYPE_VENDOR = 0x81, 31 HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
@@ -327,5 +328,8 @@ union hdmi_infoframe {
327 328
328ssize_t 329ssize_t
329hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size); 330hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
331int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
332void hdmi_infoframe_log(const char *level, struct device *dev,
333 union hdmi_infoframe *frame);
330 334
331#endif /* _DRM_HDMI_H */ 335#endif /* _DRM_HDMI_H */