// SPDX-License-Identifier: GPL-2.0-only 
 | 
/* 
 | 
 * Copyright (c) 2016 MediaTek Inc. 
 | 
 * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> 
 | 
 *         Rick Chang <rick.chang@mediatek.com> 
 | 
 */ 
 | 
  
 | 
#include <linux/kernel.h> 
 | 
#include <linux/videodev2.h> 
 | 
  
 | 
#include "mtk_jpeg_dec_parse.h" 
 | 
  
 | 
#define TEM    0x01 
 | 
#define SOF0    0xc0 
 | 
#define RST    0xd0 
 | 
#define SOI    0xd8 
 | 
#define EOI    0xd9 
 | 
  
 | 
struct mtk_jpeg_stream { 
 | 
    u8 *addr; 
 | 
    u32 size; 
 | 
    u32 curr; 
 | 
}; 
 | 
  
 | 
static int read_byte(struct mtk_jpeg_stream *stream) 
 | 
{ 
 | 
    if (stream->curr >= stream->size) 
 | 
        return -1; 
 | 
    return stream->addr[stream->curr++]; 
 | 
} 
 | 
  
 | 
static int read_word_be(struct mtk_jpeg_stream *stream, u32 *word) 
 | 
{ 
 | 
    u32 temp; 
 | 
    int byte; 
 | 
  
 | 
    byte = read_byte(stream); 
 | 
    if (byte == -1) 
 | 
        return -1; 
 | 
    temp = byte << 8; 
 | 
    byte = read_byte(stream); 
 | 
    if (byte == -1) 
 | 
        return -1; 
 | 
    *word = (u32)byte | temp; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static void read_skip(struct mtk_jpeg_stream *stream, long len) 
 | 
{ 
 | 
    if (len <= 0) 
 | 
        return; 
 | 
    while (len--) 
 | 
        read_byte(stream); 
 | 
} 
 | 
  
 | 
static bool mtk_jpeg_do_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va, 
 | 
                  u32 src_size) 
 | 
{ 
 | 
    bool notfound = true; 
 | 
    struct mtk_jpeg_stream stream; 
 | 
  
 | 
    stream.addr = src_addr_va; 
 | 
    stream.size = src_size; 
 | 
    stream.curr = 0; 
 | 
  
 | 
    while (notfound) { 
 | 
        int i, length, byte; 
 | 
        u32 word; 
 | 
  
 | 
        byte = read_byte(&stream); 
 | 
        if (byte == -1) 
 | 
            return false; 
 | 
        if (byte != 0xff) 
 | 
            continue; 
 | 
        do 
 | 
            byte = read_byte(&stream); 
 | 
        while (byte == 0xff); 
 | 
        if (byte == -1) 
 | 
            return false; 
 | 
        if (byte == 0) 
 | 
            continue; 
 | 
  
 | 
        length = 0; 
 | 
        switch (byte) { 
 | 
        case SOF0: 
 | 
            /* length */ 
 | 
            if (read_word_be(&stream, &word)) 
 | 
                break; 
 | 
  
 | 
            /* precision */ 
 | 
            if (read_byte(&stream) == -1) 
 | 
                break; 
 | 
  
 | 
            if (read_word_be(&stream, &word)) 
 | 
                break; 
 | 
            param->pic_h = word; 
 | 
  
 | 
            if (read_word_be(&stream, &word)) 
 | 
                break; 
 | 
            param->pic_w = word; 
 | 
  
 | 
            param->comp_num = read_byte(&stream); 
 | 
            if (param->comp_num != 1 && param->comp_num != 3) 
 | 
                break; 
 | 
  
 | 
            for (i = 0; i < param->comp_num; i++) { 
 | 
                param->comp_id[i] = read_byte(&stream); 
 | 
                if (param->comp_id[i] == -1) 
 | 
                    break; 
 | 
  
 | 
                /* sampling */ 
 | 
                byte = read_byte(&stream); 
 | 
                if (byte == -1) 
 | 
                    break; 
 | 
                param->sampling_w[i] = (byte >> 4) & 0x0F; 
 | 
                param->sampling_h[i] = byte & 0x0F; 
 | 
  
 | 
                param->qtbl_num[i] = read_byte(&stream); 
 | 
                if (param->qtbl_num[i] == -1) 
 | 
                    break; 
 | 
            } 
 | 
  
 | 
            notfound = !(i == param->comp_num); 
 | 
            break; 
 | 
        case RST ... RST + 7: 
 | 
        case SOI: 
 | 
        case EOI: 
 | 
        case TEM: 
 | 
            break; 
 | 
        default: 
 | 
            if (read_word_be(&stream, &word)) 
 | 
                break; 
 | 
            length = (long)word - 2; 
 | 
            read_skip(&stream, length); 
 | 
            break; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return !notfound; 
 | 
} 
 | 
  
 | 
bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va, 
 | 
            u32 src_size) 
 | 
{ 
 | 
    if (!mtk_jpeg_do_parse(param, src_addr_va, src_size)) 
 | 
        return false; 
 | 
    if (mtk_jpeg_dec_fill_param(param)) 
 | 
        return false; 
 | 
  
 | 
    return true; 
 | 
} 
 |