hdmi.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /*
  2. * Copyright (C) 2012 Avionic Design GmbH
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sub license,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice (including the
  12. * next paragraph) shall be included in all copies or substantial portions
  13. * of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21. * DEALINGS IN THE SOFTWARE.
  22. */
  23. #include <linux/bitops.h>
  24. #include <linux/bug.h>
  25. #include <linux/errno.h>
  26. #include <linux/export.h>
  27. #include <linux/hdmi.h>
  28. #include <linux/string.h>
  29. static void hdmi_infoframe_checksum(void *buffer, size_t size)
  30. {
  31. u8 *ptr = buffer;
  32. u8 csum = 0;
  33. size_t i;
  34. /* compute checksum */
  35. for (i = 0; i < size; i++)
  36. csum += ptr[i];
  37. ptr[3] = 256 - csum;
  38. }
  39. /**
  40. * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe
  41. * @frame: HDMI AVI infoframe
  42. *
  43. * Returns 0 on success or a negative error code on failure.
  44. */
  45. int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
  46. {
  47. memset(frame, 0, sizeof(*frame));
  48. frame->type = HDMI_INFOFRAME_TYPE_AVI;
  49. frame->version = 2;
  50. frame->length = HDMI_AVI_INFOFRAME_SIZE;
  51. return 0;
  52. }
  53. EXPORT_SYMBOL(hdmi_avi_infoframe_init);
  54. /**
  55. * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
  56. * @frame: HDMI AVI infoframe
  57. * @buffer: destination buffer
  58. * @size: size of buffer
  59. *
  60. * Packs the information contained in the @frame structure into a binary
  61. * representation that can be written into the corresponding controller
  62. * registers. Also computes the checksum as required by section 5.3.5 of
  63. * the HDMI 1.4 specification.
  64. *
  65. * Returns the number of bytes packed into the binary buffer or a negative
  66. * error code on failure.
  67. */
  68. ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
  69. size_t size)
  70. {
  71. u8 *ptr = buffer;
  72. size_t length;
  73. length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
  74. if (size < length)
  75. return -ENOSPC;
  76. memset(buffer, 0, length);
  77. ptr[0] = frame->type;
  78. ptr[1] = frame->version;
  79. ptr[2] = frame->length;
  80. ptr[3] = 0; /* checksum */
  81. /* start infoframe payload */
  82. ptr += HDMI_INFOFRAME_HEADER_SIZE;
  83. ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3);
  84. if (frame->active_info_valid)
  85. ptr[0] |= BIT(4);
  86. if (frame->horizontal_bar_valid)
  87. ptr[0] |= BIT(3);
  88. if (frame->vertical_bar_valid)
  89. ptr[0] |= BIT(2);
  90. ptr[1] = ((frame->colorimetry & 0x3) << 6) |
  91. ((frame->picture_aspect & 0x3) << 4) |
  92. (frame->active_aspect & 0xf);
  93. ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) |
  94. ((frame->quantization_range & 0x3) << 2) |
  95. (frame->nups & 0x3);
  96. if (frame->itc)
  97. ptr[2] |= BIT(7);
  98. ptr[3] = frame->video_code & 0x7f;
  99. ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) |
  100. ((frame->content_type & 0x3) << 4) |
  101. (frame->pixel_repeat & 0xf);
  102. ptr[5] = frame->top_bar & 0xff;
  103. ptr[6] = (frame->top_bar >> 8) & 0xff;
  104. ptr[7] = frame->bottom_bar & 0xff;
  105. ptr[8] = (frame->bottom_bar >> 8) & 0xff;
  106. ptr[9] = frame->left_bar & 0xff;
  107. ptr[10] = (frame->left_bar >> 8) & 0xff;
  108. ptr[11] = frame->right_bar & 0xff;
  109. ptr[12] = (frame->right_bar >> 8) & 0xff;
  110. hdmi_infoframe_checksum(buffer, length);
  111. return length;
  112. }
  113. EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
  114. /**
  115. * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe
  116. * @frame: HDMI SPD infoframe
  117. * @vendor: vendor string
  118. * @product: product string
  119. *
  120. * Returns 0 on success or a negative error code on failure.
  121. */
  122. int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
  123. const char *vendor, const char *product)
  124. {
  125. memset(frame, 0, sizeof(*frame));
  126. frame->type = HDMI_INFOFRAME_TYPE_SPD;
  127. frame->version = 1;
  128. frame->length = HDMI_SPD_INFOFRAME_SIZE;
  129. strncpy(frame->vendor, vendor, sizeof(frame->vendor));
  130. strncpy(frame->product, product, sizeof(frame->product));
  131. return 0;
  132. }
  133. EXPORT_SYMBOL(hdmi_spd_infoframe_init);
  134. /**
  135. * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
  136. * @frame: HDMI SPD infoframe
  137. * @buffer: destination buffer
  138. * @size: size of buffer
  139. *
  140. * Packs the information contained in the @frame structure into a binary
  141. * representation that can be written into the corresponding controller
  142. * registers. Also computes the checksum as required by section 5.3.5 of
  143. * the HDMI 1.4 specification.
  144. *
  145. * Returns the number of bytes packed into the binary buffer or a negative
  146. * error code on failure.
  147. */
  148. ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
  149. size_t size)
  150. {
  151. u8 *ptr = buffer;
  152. size_t length;
  153. length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
  154. if (size < length)
  155. return -ENOSPC;
  156. memset(buffer, 0, length);
  157. ptr[0] = frame->type;
  158. ptr[1] = frame->version;
  159. ptr[2] = frame->length;
  160. ptr[3] = 0; /* checksum */
  161. /* start infoframe payload */
  162. ptr += HDMI_INFOFRAME_HEADER_SIZE;
  163. memcpy(ptr, frame->vendor, sizeof(frame->vendor));
  164. memcpy(ptr + 8, frame->product, sizeof(frame->product));
  165. ptr[24] = frame->sdi;
  166. hdmi_infoframe_checksum(buffer, length);
  167. return length;
  168. }
  169. EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
  170. /**
  171. * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe
  172. * @frame: HDMI audio infoframe
  173. *
  174. * Returns 0 on success or a negative error code on failure.
  175. */
  176. int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
  177. {
  178. memset(frame, 0, sizeof(*frame));
  179. frame->type = HDMI_INFOFRAME_TYPE_AUDIO;
  180. frame->version = 1;
  181. frame->length = HDMI_AUDIO_INFOFRAME_SIZE;
  182. return 0;
  183. }
  184. EXPORT_SYMBOL(hdmi_audio_infoframe_init);
  185. /**
  186. * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
  187. * @frame: HDMI audio infoframe
  188. * @buffer: destination buffer
  189. * @size: size of buffer
  190. *
  191. * Packs the information contained in the @frame structure into a binary
  192. * representation that can be written into the corresponding controller
  193. * registers. Also computes the checksum as required by section 5.3.5 of
  194. * the HDMI 1.4 specification.
  195. *
  196. * Returns the number of bytes packed into the binary buffer or a negative
  197. * error code on failure.
  198. */
  199. ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
  200. void *buffer, size_t size)
  201. {
  202. unsigned char channels;
  203. u8 *ptr = buffer;
  204. size_t length;
  205. length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
  206. if (size < length)
  207. return -ENOSPC;
  208. memset(buffer, 0, length);
  209. if (frame->channels >= 2)
  210. channels = frame->channels - 1;
  211. else
  212. channels = 0;
  213. ptr[0] = frame->type;
  214. ptr[1] = frame->version;
  215. ptr[2] = frame->length;
  216. ptr[3] = 0; /* checksum */
  217. /* start infoframe payload */
  218. ptr += HDMI_INFOFRAME_HEADER_SIZE;
  219. ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
  220. ptr[1] = ((frame->sample_frequency & 0x7) << 2) |
  221. (frame->sample_size & 0x3);
  222. ptr[2] = frame->coding_type_ext & 0x1f;
  223. ptr[3] = frame->channel_allocation;
  224. ptr[4] = (frame->level_shift_value & 0xf) << 3;
  225. if (frame->downmix_inhibit)
  226. ptr[4] |= BIT(7);
  227. hdmi_infoframe_checksum(buffer, length);
  228. return length;
  229. }
  230. EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
  231. /**
  232. * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary
  233. * buffer
  234. * @frame: HDMI vendor infoframe
  235. * @buffer: destination buffer
  236. * @size: size of buffer
  237. *
  238. * Packs the information contained in the @frame structure into a binary
  239. * representation that can be written into the corresponding controller
  240. * registers. Also computes the checksum as required by section 5.3.5 of
  241. * the HDMI 1.4 specification.
  242. *
  243. * Returns the number of bytes packed into the binary buffer or a negative
  244. * error code on failure.
  245. */
  246. ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
  247. void *buffer, size_t size)
  248. {
  249. u8 *ptr = buffer;
  250. size_t length;
  251. length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
  252. if (size < length)
  253. return -ENOSPC;
  254. memset(buffer, 0, length);
  255. ptr[0] = frame->type;
  256. ptr[1] = frame->version;
  257. ptr[2] = frame->length;
  258. ptr[3] = 0; /* checksum */
  259. memcpy(&ptr[HDMI_INFOFRAME_HEADER_SIZE], frame->data, frame->length);
  260. hdmi_infoframe_checksum(buffer, length);
  261. return length;
  262. }
  263. EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
  264. /**
  265. * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
  266. * @frame: HDMI infoframe
  267. * @buffer: destination buffer
  268. * @size: size of buffer
  269. *
  270. * Packs the information contained in the @frame structure into a binary
  271. * representation that can be written into the corresponding controller
  272. * registers. Also computes the checksum as required by section 5.3.5 of
  273. * the HDMI 1.4 specification.
  274. *
  275. * Returns the number of bytes packed into the binary buffer or a negative
  276. * error code on failure.
  277. */
  278. ssize_t
  279. hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
  280. {
  281. ssize_t length;
  282. switch (frame->any.type) {
  283. case HDMI_INFOFRAME_TYPE_AVI:
  284. length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size);
  285. break;
  286. case HDMI_INFOFRAME_TYPE_SPD:
  287. length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size);
  288. break;
  289. case HDMI_INFOFRAME_TYPE_AUDIO:
  290. length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size);
  291. break;
  292. case HDMI_INFOFRAME_TYPE_VENDOR:
  293. length = hdmi_vendor_infoframe_pack(&frame->vendor,
  294. buffer, size);
  295. break;
  296. default:
  297. WARN(1, "Bad infoframe type %d\n", frame->any.type);
  298. length = -EINVAL;
  299. }
  300. return length;
  301. }
  302. EXPORT_SYMBOL(hdmi_infoframe_pack);