1 /*
2  * Copyright (c) 2016 MediaTek Inc.
3  * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
4  *         Rick Chang <rick.chang@mediatek.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15 
16 #include <linux/kernel.h>
17 #include <linux/videodev2.h>
18 
19 #include "mtk_jpeg_parse.h"
20 
21 #define TEM	0x01
22 #define SOF0	0xc0
23 #define RST	0xd0
24 #define SOI	0xd8
25 #define EOI	0xd9
26 
27 struct mtk_jpeg_stream {
28 	u8 *addr;
29 	u32 size;
30 	u32 curr;
31 };
32 
read_byte(struct mtk_jpeg_stream * stream)33 static int read_byte(struct mtk_jpeg_stream *stream)
34 {
35 	if (stream->curr >= stream->size)
36 		return -1;
37 	return stream->addr[stream->curr++];
38 }
39 
read_word_be(struct mtk_jpeg_stream * stream,u32 * word)40 static int read_word_be(struct mtk_jpeg_stream *stream, u32 *word)
41 {
42 	u32 temp;
43 	int byte;
44 
45 	byte = read_byte(stream);
46 	if (byte == -1)
47 		return -1;
48 	temp = byte << 8;
49 	byte = read_byte(stream);
50 	if (byte == -1)
51 		return -1;
52 	*word = (u32)byte | temp;
53 
54 	return 0;
55 }
56 
read_skip(struct mtk_jpeg_stream * stream,long len)57 static void read_skip(struct mtk_jpeg_stream *stream, long len)
58 {
59 	if (len <= 0)
60 		return;
61 	while (len--)
62 		read_byte(stream);
63 }
64 
mtk_jpeg_do_parse(struct mtk_jpeg_dec_param * param,u8 * src_addr_va,u32 src_size)65 static bool mtk_jpeg_do_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
66 			      u32 src_size)
67 {
68 	bool notfound = true;
69 	struct mtk_jpeg_stream stream;
70 
71 	stream.addr = src_addr_va;
72 	stream.size = src_size;
73 	stream.curr = 0;
74 
75 	while (notfound) {
76 		int i, length, byte;
77 		u32 word;
78 
79 		byte = read_byte(&stream);
80 		if (byte == -1)
81 			return false;
82 		if (byte != 0xff)
83 			continue;
84 		do
85 			byte = read_byte(&stream);
86 		while (byte == 0xff);
87 		if (byte == -1)
88 			return false;
89 		if (byte == 0)
90 			continue;
91 
92 		length = 0;
93 		switch (byte) {
94 		case SOF0:
95 			/* length */
96 			if (read_word_be(&stream, &word))
97 				break;
98 
99 			/* precision */
100 			if (read_byte(&stream) == -1)
101 				break;
102 
103 			if (read_word_be(&stream, &word))
104 				break;
105 			param->pic_h = word;
106 
107 			if (read_word_be(&stream, &word))
108 				break;
109 			param->pic_w = word;
110 
111 			param->comp_num = read_byte(&stream);
112 			if (param->comp_num != 1 && param->comp_num != 3)
113 				break;
114 
115 			for (i = 0; i < param->comp_num; i++) {
116 				param->comp_id[i] = read_byte(&stream);
117 				if (param->comp_id[i] == -1)
118 					break;
119 
120 				/* sampling */
121 				byte = read_byte(&stream);
122 				if (byte == -1)
123 					break;
124 				param->sampling_w[i] = (byte >> 4) & 0x0F;
125 				param->sampling_h[i] = byte & 0x0F;
126 
127 				param->qtbl_num[i] = read_byte(&stream);
128 				if (param->qtbl_num[i] == -1)
129 					break;
130 			}
131 
132 			notfound = !(i == param->comp_num);
133 			break;
134 		case RST ... RST + 7:
135 		case SOI:
136 		case EOI:
137 		case TEM:
138 			break;
139 		default:
140 			if (read_word_be(&stream, &word))
141 				break;
142 			length = (long)word - 2;
143 			read_skip(&stream, length);
144 			break;
145 		}
146 	}
147 
148 	return !notfound;
149 }
150 
mtk_jpeg_parse(struct mtk_jpeg_dec_param * param,u8 * src_addr_va,u32 src_size)151 bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
152 		    u32 src_size)
153 {
154 	if (!mtk_jpeg_do_parse(param, src_addr_va, src_size))
155 		return false;
156 	if (mtk_jpeg_dec_fill_param(param))
157 		return false;
158 
159 	return true;
160 }
161