Linux-libre 5.3-gnu
[librecmc/linux-libre.git] / drivers / media / platform / mtk-jpeg / mtk_jpeg_parse.c
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
11 #include "mtk_jpeg_parse.h"
12
13 #define TEM     0x01
14 #define SOF0    0xc0
15 #define RST     0xd0
16 #define SOI     0xd8
17 #define EOI     0xd9
18
19 struct mtk_jpeg_stream {
20         u8 *addr;
21         u32 size;
22         u32 curr;
23 };
24
25 static int read_byte(struct mtk_jpeg_stream *stream)
26 {
27         if (stream->curr >= stream->size)
28                 return -1;
29         return stream->addr[stream->curr++];
30 }
31
32 static int read_word_be(struct mtk_jpeg_stream *stream, u32 *word)
33 {
34         u32 temp;
35         int byte;
36
37         byte = read_byte(stream);
38         if (byte == -1)
39                 return -1;
40         temp = byte << 8;
41         byte = read_byte(stream);
42         if (byte == -1)
43                 return -1;
44         *word = (u32)byte | temp;
45
46         return 0;
47 }
48
49 static void read_skip(struct mtk_jpeg_stream *stream, long len)
50 {
51         if (len <= 0)
52                 return;
53         while (len--)
54                 read_byte(stream);
55 }
56
57 static bool mtk_jpeg_do_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
58                               u32 src_size)
59 {
60         bool notfound = true;
61         struct mtk_jpeg_stream stream;
62
63         stream.addr = src_addr_va;
64         stream.size = src_size;
65         stream.curr = 0;
66
67         while (notfound) {
68                 int i, length, byte;
69                 u32 word;
70
71                 byte = read_byte(&stream);
72                 if (byte == -1)
73                         return false;
74                 if (byte != 0xff)
75                         continue;
76                 do
77                         byte = read_byte(&stream);
78                 while (byte == 0xff);
79                 if (byte == -1)
80                         return false;
81                 if (byte == 0)
82                         continue;
83
84                 length = 0;
85                 switch (byte) {
86                 case SOF0:
87                         /* length */
88                         if (read_word_be(&stream, &word))
89                                 break;
90
91                         /* precision */
92                         if (read_byte(&stream) == -1)
93                                 break;
94
95                         if (read_word_be(&stream, &word))
96                                 break;
97                         param->pic_h = word;
98
99                         if (read_word_be(&stream, &word))
100                                 break;
101                         param->pic_w = word;
102
103                         param->comp_num = read_byte(&stream);
104                         if (param->comp_num != 1 && param->comp_num != 3)
105                                 break;
106
107                         for (i = 0; i < param->comp_num; i++) {
108                                 param->comp_id[i] = read_byte(&stream);
109                                 if (param->comp_id[i] == -1)
110                                         break;
111
112                                 /* sampling */
113                                 byte = read_byte(&stream);
114                                 if (byte == -1)
115                                         break;
116                                 param->sampling_w[i] = (byte >> 4) & 0x0F;
117                                 param->sampling_h[i] = byte & 0x0F;
118
119                                 param->qtbl_num[i] = read_byte(&stream);
120                                 if (param->qtbl_num[i] == -1)
121                                         break;
122                         }
123
124                         notfound = !(i == param->comp_num);
125                         break;
126                 case RST ... RST + 7:
127                 case SOI:
128                 case EOI:
129                 case TEM:
130                         break;
131                 default:
132                         if (read_word_be(&stream, &word))
133                                 break;
134                         length = (long)word - 2;
135                         read_skip(&stream, length);
136                         break;
137                 }
138         }
139
140         return !notfound;
141 }
142
143 bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
144                     u32 src_size)
145 {
146         if (!mtk_jpeg_do_parse(param, src_addr_va, src_size))
147                 return false;
148         if (mtk_jpeg_dec_fill_param(param))
149                 return false;
150
151         return true;
152 }