Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Martin Bugge and committed by
Mauro Carvalho Chehab
2c676f37 05c80d75

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