1 /* 2 * Copyright (C) 2012 Avionic Design GmbH 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/bitops.h> 10 #include <linux/errno.h> 11 #include <linux/export.h> 12 #include <linux/hdmi.h> 13 #include <linux/string.h> 14 15 static void hdmi_infoframe_checksum(void *buffer, size_t size) 16 { 17 u8 *ptr = buffer; 18 u8 csum = 0; 19 size_t i; 20 21 /* compute checksum */ 22 for (i = 0; i < size; i++) 23 csum += ptr[i]; 24 25 ptr[3] = 256 - csum; 26 } 27 28 /** 29 * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe 30 * @frame: HDMI AVI infoframe 31 * 32 * Returns 0 on success or a negative error code on failure. 33 */ 34 int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame) 35 { 36 memset(frame, 0, sizeof(*frame)); 37 38 frame->type = HDMI_INFOFRAME_TYPE_AVI; 39 frame->version = 2; 40 frame->length = 13; 41 42 return 0; 43 } 44 EXPORT_SYMBOL(hdmi_avi_infoframe_init); 45 46 /** 47 * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer 48 * @frame: HDMI AVI infoframe 49 * @buffer: destination buffer 50 * @size: size of buffer 51 * 52 * Packs the information contained in the @frame structure into a binary 53 * representation that can be written into the corresponding controller 54 * registers. Also computes the checksum as required by section 5.3.5 of 55 * the HDMI 1.4 specification. 56 * 57 * Returns the number of bytes packed into the binary buffer or a negative 58 * error code on failure. 59 */ 60 ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, 61 size_t size) 62 { 63 u8 *ptr = buffer; 64 size_t length; 65 66 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 67 68 if (size < length) 69 return -ENOSPC; 70 71 memset(buffer, 0, length); 72 73 ptr[0] = frame->type; 74 ptr[1] = frame->version; 75 ptr[2] = frame->length; 76 ptr[3] = 0; /* checksum */ 77 78 /* start infoframe payload */ 79 ptr += HDMI_INFOFRAME_HEADER_SIZE; 80 81 ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3); 82 83 if (frame->active_info_valid) 84 ptr[0] |= BIT(4); 85 86 if (frame->horizontal_bar_valid) 87 ptr[0] |= BIT(3); 88 89 if (frame->vertical_bar_valid) 90 ptr[0] |= BIT(2); 91 92 ptr[1] = ((frame->colorimetry & 0x3) << 6) | 93 ((frame->picture_aspect & 0x3) << 4) | 94 (frame->active_aspect & 0xf); 95 96 ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) | 97 ((frame->quantization_range & 0x3) << 2) | 98 (frame->nups & 0x3); 99 100 if (frame->itc) 101 ptr[2] |= BIT(7); 102 103 ptr[3] = frame->video_code & 0x7f; 104 105 ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) | 106 ((frame->content_type & 0x3) << 4) | 107 (frame->pixel_repeat & 0xf); 108 109 ptr[5] = frame->top_bar & 0xff; 110 ptr[6] = (frame->top_bar >> 8) & 0xff; 111 ptr[7] = frame->bottom_bar & 0xff; 112 ptr[8] = (frame->bottom_bar >> 8) & 0xff; 113 ptr[9] = frame->left_bar & 0xff; 114 ptr[10] = (frame->left_bar >> 8) & 0xff; 115 ptr[11] = frame->right_bar & 0xff; 116 ptr[12] = (frame->right_bar >> 8) & 0xff; 117 118 hdmi_infoframe_checksum(buffer, length); 119 120 return length; 121 } 122 EXPORT_SYMBOL(hdmi_avi_infoframe_pack); 123 124 /** 125 * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe 126 * @frame: HDMI SPD infoframe 127 * @vendor: vendor string 128 * @product: product string 129 * 130 * Returns 0 on success or a negative error code on failure. 131 */ 132 int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame, 133 const char *vendor, const char *product) 134 { 135 memset(frame, 0, sizeof(*frame)); 136 137 frame->type = HDMI_INFOFRAME_TYPE_SPD; 138 frame->version = 1; 139 frame->length = 25; 140 141 strncpy(frame->vendor, vendor, sizeof(frame->vendor)); 142 strncpy(frame->product, product, sizeof(frame->product)); 143 144 return 0; 145 } 146 EXPORT_SYMBOL(hdmi_spd_infoframe_init); 147 148 /** 149 * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer 150 * @frame: HDMI SPD infoframe 151 * @buffer: destination buffer 152 * @size: size of buffer 153 * 154 * Packs the information contained in the @frame structure into a binary 155 * representation that can be written into the corresponding controller 156 * registers. Also computes the checksum as required by section 5.3.5 of 157 * the HDMI 1.4 specification. 158 * 159 * Returns the number of bytes packed into the binary buffer or a negative 160 * error code on failure. 161 */ 162 ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer, 163 size_t size) 164 { 165 u8 *ptr = buffer; 166 size_t length; 167 168 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 169 170 if (size < length) 171 return -ENOSPC; 172 173 memset(buffer, 0, length); 174 175 ptr[0] = frame->type; 176 ptr[1] = frame->version; 177 ptr[2] = frame->length; 178 ptr[3] = 0; /* checksum */ 179 180 /* start infoframe payload */ 181 ptr += HDMI_INFOFRAME_HEADER_SIZE; 182 183 memcpy(ptr, frame->vendor, sizeof(frame->vendor)); 184 memcpy(ptr + 8, frame->product, sizeof(frame->product)); 185 186 ptr[24] = frame->sdi; 187 188 hdmi_infoframe_checksum(buffer, length); 189 190 return length; 191 } 192 EXPORT_SYMBOL(hdmi_spd_infoframe_pack); 193 194 /** 195 * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe 196 * @frame: HDMI audio infoframe 197 * 198 * Returns 0 on success or a negative error code on failure. 199 */ 200 int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame) 201 { 202 memset(frame, 0, sizeof(*frame)); 203 204 frame->type = HDMI_INFOFRAME_TYPE_AUDIO; 205 frame->version = 1; 206 frame->length = 10; 207 208 return 0; 209 } 210 EXPORT_SYMBOL(hdmi_audio_infoframe_init); 211 212 /** 213 * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer 214 * @frame: HDMI audio infoframe 215 * @buffer: destination buffer 216 * @size: size of buffer 217 * 218 * Packs the information contained in the @frame structure into a binary 219 * representation that can be written into the corresponding controller 220 * registers. Also computes the checksum as required by section 5.3.5 of 221 * the HDMI 1.4 specification. 222 * 223 * Returns the number of bytes packed into the binary buffer or a negative 224 * error code on failure. 225 */ 226 ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, 227 void *buffer, size_t size) 228 { 229 unsigned char channels; 230 u8 *ptr = buffer; 231 size_t length; 232 233 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 234 235 if (size < length) 236 return -ENOSPC; 237 238 memset(buffer, 0, length); 239 240 if (frame->channels >= 2) 241 channels = frame->channels - 1; 242 else 243 channels = 0; 244 245 ptr[0] = frame->type; 246 ptr[1] = frame->version; 247 ptr[2] = frame->length; 248 ptr[3] = 0; /* checksum */ 249 250 /* start infoframe payload */ 251 ptr += HDMI_INFOFRAME_HEADER_SIZE; 252 253 ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7); 254 ptr[1] = ((frame->sample_frequency & 0x7) << 2) | 255 (frame->sample_size & 0x3); 256 ptr[2] = frame->coding_type_ext & 0x1f; 257 ptr[3] = frame->channel_allocation; 258 ptr[4] = (frame->level_shift_value & 0xf) << 3; 259 260 if (frame->downmix_inhibit) 261 ptr[4] |= BIT(7); 262 263 hdmi_infoframe_checksum(buffer, length); 264 265 return length; 266 } 267 EXPORT_SYMBOL(hdmi_audio_infoframe_pack); 268 269 /** 270 * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary 271 * buffer 272 * @frame: HDMI vendor infoframe 273 * @buffer: destination buffer 274 * @size: size of buffer 275 * 276 * Packs the information contained in the @frame structure into a binary 277 * representation that can be written into the corresponding controller 278 * registers. Also computes the checksum as required by section 5.3.5 of 279 * the HDMI 1.4 specification. 280 * 281 * Returns the number of bytes packed into the binary buffer or a negative 282 * error code on failure. 283 */ 284 ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, 285 void *buffer, size_t size) 286 { 287 u8 *ptr = buffer; 288 size_t length; 289 290 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 291 292 if (size < length) 293 return -ENOSPC; 294 295 memset(buffer, 0, length); 296 297 ptr[0] = frame->type; 298 ptr[1] = frame->version; 299 ptr[2] = frame->length; 300 ptr[3] = 0; /* checksum */ 301 302 memcpy(&ptr[HDMI_INFOFRAME_HEADER_SIZE], frame->data, frame->length); 303 304 hdmi_infoframe_checksum(buffer, length); 305 306 return length; 307 } 308 EXPORT_SYMBOL(hdmi_vendor_infoframe_pack); 309