18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2013 48c2ecf20Sopenharmony_ci * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "delta.h" 88c2ecf20Sopenharmony_ci#include "delta-mjpeg.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define MJPEG_SOF_0 0xc0 118c2ecf20Sopenharmony_ci#define MJPEG_SOF_1 0xc1 128c2ecf20Sopenharmony_ci#define MJPEG_SOI 0xd8 138c2ecf20Sopenharmony_ci#define MJPEG_MARKER 0xff 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic char *header_str(struct mjpeg_header *header, 168c2ecf20Sopenharmony_ci char *str, 178c2ecf20Sopenharmony_ci unsigned int len) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci char *cur = str; 208c2ecf20Sopenharmony_ci unsigned int left = len; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci if (!header) 238c2ecf20Sopenharmony_ci return ""; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci snprintf(cur, left, "[MJPEG header]\n" 268c2ecf20Sopenharmony_ci "|- length = %d\n" 278c2ecf20Sopenharmony_ci "|- precision = %d\n" 288c2ecf20Sopenharmony_ci "|- width = %d\n" 298c2ecf20Sopenharmony_ci "|- height = %d\n" 308c2ecf20Sopenharmony_ci "|- components = %d\n", 318c2ecf20Sopenharmony_ci header->length, 328c2ecf20Sopenharmony_ci header->sample_precision, 338c2ecf20Sopenharmony_ci header->frame_width, 348c2ecf20Sopenharmony_ci header->frame_height, 358c2ecf20Sopenharmony_ci header->nb_of_components); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return str; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int delta_mjpeg_read_sof(struct delta_ctx *pctx, 418c2ecf20Sopenharmony_ci unsigned char *data, unsigned int size, 428c2ecf20Sopenharmony_ci struct mjpeg_header *header) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct delta_dev *delta = pctx->dev; 458c2ecf20Sopenharmony_ci unsigned int offset = 0; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (size < 64) 488c2ecf20Sopenharmony_ci goto err_no_more; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci memset(header, 0, sizeof(*header)); 518c2ecf20Sopenharmony_ci header->length = be16_to_cpu(*(__be16 *)(data + offset)); 528c2ecf20Sopenharmony_ci offset += sizeof(u16); 538c2ecf20Sopenharmony_ci header->sample_precision = *(u8 *)(data + offset); 548c2ecf20Sopenharmony_ci offset += sizeof(u8); 558c2ecf20Sopenharmony_ci header->frame_height = be16_to_cpu(*(__be16 *)(data + offset)); 568c2ecf20Sopenharmony_ci offset += sizeof(u16); 578c2ecf20Sopenharmony_ci header->frame_width = be16_to_cpu(*(__be16 *)(data + offset)); 588c2ecf20Sopenharmony_ci offset += sizeof(u16); 598c2ecf20Sopenharmony_ci header->nb_of_components = *(u8 *)(data + offset); 608c2ecf20Sopenharmony_ci offset += sizeof(u8); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (header->nb_of_components >= MJPEG_MAX_COMPONENTS) { 638c2ecf20Sopenharmony_ci dev_err(delta->dev, 648c2ecf20Sopenharmony_ci "%s unsupported number of components (%d > %d)\n", 658c2ecf20Sopenharmony_ci pctx->name, header->nb_of_components, 668c2ecf20Sopenharmony_ci MJPEG_MAX_COMPONENTS); 678c2ecf20Sopenharmony_ci return -EINVAL; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if ((offset + header->nb_of_components * 718c2ecf20Sopenharmony_ci sizeof(header->components[0])) > size) 728c2ecf20Sopenharmony_ci goto err_no_more; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cierr_no_more: 778c2ecf20Sopenharmony_ci dev_err(delta->dev, 788c2ecf20Sopenharmony_ci "%s sof: reached end of %d size input stream\n", 798c2ecf20Sopenharmony_ci pctx->name, size); 808c2ecf20Sopenharmony_ci return -ENODATA; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciint delta_mjpeg_read_header(struct delta_ctx *pctx, 848c2ecf20Sopenharmony_ci unsigned char *data, unsigned int size, 858c2ecf20Sopenharmony_ci struct mjpeg_header *header, 868c2ecf20Sopenharmony_ci unsigned int *data_offset) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct delta_dev *delta = pctx->dev; 898c2ecf20Sopenharmony_ci unsigned char str[200]; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci unsigned int ret = 0; 928c2ecf20Sopenharmony_ci unsigned int offset = 0; 938c2ecf20Sopenharmony_ci unsigned int soi = 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (size < 2) 968c2ecf20Sopenharmony_ci goto err_no_more; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci offset = 0; 998c2ecf20Sopenharmony_ci while (1) { 1008c2ecf20Sopenharmony_ci if (data[offset] == MJPEG_MARKER) 1018c2ecf20Sopenharmony_ci switch (data[offset + 1]) { 1028c2ecf20Sopenharmony_ci case MJPEG_SOI: 1038c2ecf20Sopenharmony_ci soi = 1; 1048c2ecf20Sopenharmony_ci *data_offset = offset; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci case MJPEG_SOF_0: 1088c2ecf20Sopenharmony_ci case MJPEG_SOF_1: 1098c2ecf20Sopenharmony_ci if (!soi) { 1108c2ecf20Sopenharmony_ci dev_err(delta->dev, 1118c2ecf20Sopenharmony_ci "%s wrong sequence, got SOF while SOI not seen\n", 1128c2ecf20Sopenharmony_ci pctx->name); 1138c2ecf20Sopenharmony_ci return -EINVAL; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci ret = delta_mjpeg_read_sof(pctx, 1178c2ecf20Sopenharmony_ci &data[offset + 2], 1188c2ecf20Sopenharmony_ci size - (offset + 2), 1198c2ecf20Sopenharmony_ci header); 1208c2ecf20Sopenharmony_ci if (ret) 1218c2ecf20Sopenharmony_ci goto err; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci goto done; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci default: 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci offset++; 1308c2ecf20Sopenharmony_ci if ((offset + 2) >= size) 1318c2ecf20Sopenharmony_ci goto err_no_more; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cidone: 1358c2ecf20Sopenharmony_ci dev_dbg(delta->dev, 1368c2ecf20Sopenharmony_ci "%s found header @ offset %d:\n%s", pctx->name, 1378c2ecf20Sopenharmony_ci *data_offset, 1388c2ecf20Sopenharmony_ci header_str(header, str, sizeof(str))); 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cierr_no_more: 1428c2ecf20Sopenharmony_ci dev_err(delta->dev, 1438c2ecf20Sopenharmony_ci "%s no header found within %d bytes input stream\n", 1448c2ecf20Sopenharmony_ci pctx->name, size); 1458c2ecf20Sopenharmony_ci return -ENODATA; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cierr: 1488c2ecf20Sopenharmony_ci return ret; 1498c2ecf20Sopenharmony_ci} 150