1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) STMicroelectronics SA 2013 4 * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics. 5 */ 6 7 #include "delta.h" 8 #include "delta-mjpeg.h" 9 10 #define MJPEG_SOF_0 0xc0 11 #define MJPEG_SOF_1 0xc1 12 #define MJPEG_SOI 0xd8 13 #define MJPEG_MARKER 0xff 14 15 static char *header_str(struct mjpeg_header *header, 16 char *str, 17 unsigned int len) 18 { 19 char *cur = str; 20 unsigned int left = len; 21 22 if (!header) 23 return ""; 24 25 snprintf(cur, left, "[MJPEG header]\n" 26 "|- length = %d\n" 27 "|- precision = %d\n" 28 "|- width = %d\n" 29 "|- height = %d\n" 30 "|- components = %d\n", 31 header->length, 32 header->sample_precision, 33 header->frame_width, 34 header->frame_height, 35 header->nb_of_components); 36 37 return str; 38 } 39 40 static int delta_mjpeg_read_sof(struct delta_ctx *pctx, 41 unsigned char *data, unsigned int size, 42 struct mjpeg_header *header) 43 { 44 struct delta_dev *delta = pctx->dev; 45 unsigned int offset = 0; 46 47 if (size < 64) 48 goto err_no_more; 49 50 memset(header, 0, sizeof(*header)); 51 header->length = be16_to_cpu(*(__be16 *)(data + offset)); 52 offset += sizeof(u16); 53 header->sample_precision = *(u8 *)(data + offset); 54 offset += sizeof(u8); 55 header->frame_height = be16_to_cpu(*(__be16 *)(data + offset)); 56 offset += sizeof(u16); 57 header->frame_width = be16_to_cpu(*(__be16 *)(data + offset)); 58 offset += sizeof(u16); 59 header->nb_of_components = *(u8 *)(data + offset); 60 offset += sizeof(u8); 61 62 if (header->nb_of_components >= MJPEG_MAX_COMPONENTS) { 63 dev_err(delta->dev, 64 "%s unsupported number of components (%d > %d)\n", 65 pctx->name, header->nb_of_components, 66 MJPEG_MAX_COMPONENTS); 67 return -EINVAL; 68 } 69 70 if ((offset + header->nb_of_components * 71 sizeof(header->components[0])) > size) 72 goto err_no_more; 73 74 return 0; 75 76 err_no_more: 77 dev_err(delta->dev, 78 "%s sof: reached end of %d size input stream\n", 79 pctx->name, size); 80 return -ENODATA; 81 } 82 83 int delta_mjpeg_read_header(struct delta_ctx *pctx, 84 unsigned char *data, unsigned int size, 85 struct mjpeg_header *header, 86 unsigned int *data_offset) 87 { 88 struct delta_dev *delta = pctx->dev; 89 unsigned char str[200]; 90 91 unsigned int ret = 0; 92 unsigned int offset = 0; 93 unsigned int soi = 0; 94 95 if (size < 2) 96 goto err_no_more; 97 98 offset = 0; 99 while (1) { 100 if (data[offset] == MJPEG_MARKER) 101 switch (data[offset + 1]) { 102 case MJPEG_SOI: 103 soi = 1; 104 *data_offset = offset; 105 break; 106 107 case MJPEG_SOF_0: 108 case MJPEG_SOF_1: 109 if (!soi) { 110 dev_err(delta->dev, 111 "%s wrong sequence, got SOF while SOI not seen\n", 112 pctx->name); 113 return -EINVAL; 114 } 115 116 ret = delta_mjpeg_read_sof(pctx, 117 &data[offset + 2], 118 size - (offset + 2), 119 header); 120 if (ret) 121 goto err; 122 123 goto done; 124 125 default: 126 break; 127 } 128 129 offset++; 130 if ((offset + 2) >= size) 131 goto err_no_more; 132 } 133 134 done: 135 dev_dbg(delta->dev, 136 "%s found header @ offset %d:\n%s", pctx->name, 137 *data_offset, 138 header_str(header, str, sizeof(str))); 139 return 0; 140 141 err_no_more: 142 dev_err(delta->dev, 143 "%s no header found within %d bytes input stream\n", 144 pctx->name, size); 145 return -ENODATA; 146 147 err: 148 return ret; 149 } 150