1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2016 MediaTek Inc. |
4 | * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> |
5 | * Rick Chang <rick.chang@mediatek.com> |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/videodev2.h> |
10 | #include <media/jpeg.h> |
11 | |
12 | #include "mtk_jpeg_dec_parse.h" |
13 | |
14 | struct mtk_jpeg_stream { |
15 | u8 *addr; |
16 | u32 size; |
17 | u32 curr; |
18 | }; |
19 | |
20 | static int read_byte(struct mtk_jpeg_stream *stream) |
21 | { |
22 | if (stream->curr >= stream->size) |
23 | return -1; |
24 | return stream->addr[stream->curr++]; |
25 | } |
26 | |
27 | static int read_word_be(struct mtk_jpeg_stream *stream, u32 *word) |
28 | { |
29 | u32 temp; |
30 | int byte; |
31 | |
32 | byte = read_byte(stream); |
33 | if (byte == -1) |
34 | return -1; |
35 | temp = byte << 8; |
36 | byte = read_byte(stream); |
37 | if (byte == -1) |
38 | return -1; |
39 | *word = (u32)byte | temp; |
40 | |
41 | return 0; |
42 | } |
43 | |
44 | static void read_skip(struct mtk_jpeg_stream *stream, long len) |
45 | { |
46 | if (len <= 0) |
47 | return; |
48 | while (len--) |
49 | read_byte(stream); |
50 | } |
51 | |
52 | static bool mtk_jpeg_do_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va, |
53 | u32 src_size) |
54 | { |
55 | bool notfound = true; |
56 | struct mtk_jpeg_stream stream; |
57 | |
58 | stream.addr = src_addr_va; |
59 | stream.size = src_size; |
60 | stream.curr = 0; |
61 | |
62 | while (notfound) { |
63 | int i, length, byte; |
64 | u32 word; |
65 | |
66 | byte = read_byte(stream: &stream); |
67 | if (byte == -1) |
68 | return false; |
69 | if (byte != 0xff) |
70 | continue; |
71 | do |
72 | byte = read_byte(stream: &stream); |
73 | while (byte == 0xff); |
74 | if (byte == -1) |
75 | return false; |
76 | if (byte == 0) |
77 | continue; |
78 | |
79 | length = 0; |
80 | switch (byte) { |
81 | case JPEG_MARKER_SOF0: |
82 | /* length */ |
83 | if (read_word_be(stream: &stream, word: &word)) |
84 | break; |
85 | |
86 | /* precision */ |
87 | if (read_byte(stream: &stream) == -1) |
88 | break; |
89 | |
90 | if (read_word_be(stream: &stream, word: &word)) |
91 | break; |
92 | param->pic_h = word; |
93 | |
94 | if (read_word_be(stream: &stream, word: &word)) |
95 | break; |
96 | param->pic_w = word; |
97 | |
98 | param->comp_num = read_byte(stream: &stream); |
99 | if (param->comp_num != 1 && param->comp_num != 3) |
100 | break; |
101 | |
102 | for (i = 0; i < param->comp_num; i++) { |
103 | param->comp_id[i] = read_byte(stream: &stream); |
104 | if (param->comp_id[i] == -1) |
105 | break; |
106 | |
107 | /* sampling */ |
108 | byte = read_byte(stream: &stream); |
109 | if (byte == -1) |
110 | break; |
111 | param->sampling_w[i] = (byte >> 4) & 0x0F; |
112 | param->sampling_h[i] = byte & 0x0F; |
113 | |
114 | param->qtbl_num[i] = read_byte(stream: &stream); |
115 | if (param->qtbl_num[i] == -1) |
116 | break; |
117 | } |
118 | |
119 | notfound = !(i == param->comp_num); |
120 | break; |
121 | case JPEG_MARKER_RST ... JPEG_MARKER_RST + 7: |
122 | case JPEG_MARKER_SOI: |
123 | case JPEG_MARKER_EOI: |
124 | case JPEG_MARKER_TEM: |
125 | break; |
126 | default: |
127 | if (read_word_be(stream: &stream, word: &word)) |
128 | break; |
129 | length = (long)word - 2; |
130 | read_skip(stream: &stream, len: length); |
131 | break; |
132 | } |
133 | } |
134 | |
135 | return !notfound; |
136 | } |
137 | |
138 | bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va, |
139 | u32 src_size) |
140 | { |
141 | if (!mtk_jpeg_do_parse(param, src_addr_va, src_size)) |
142 | return false; |
143 | if (mtk_jpeg_dec_fill_param(param)) |
144 | return false; |
145 | |
146 | return true; |
147 | } |
148 | |