xref: /OK3568_Linux_fs/kernel/lib/zlib_dfltcc/dfltcc_inflate.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: Zlib
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun #include "../zlib_inflate/inflate.h"
4*4882a593Smuzhiyun #include "dfltcc_util.h"
5*4882a593Smuzhiyun #include "dfltcc.h"
6*4882a593Smuzhiyun #include <asm/setup.h>
7*4882a593Smuzhiyun #include <linux/export.h>
8*4882a593Smuzhiyun #include <linux/zutil.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun /*
11*4882a593Smuzhiyun  * Expand.
12*4882a593Smuzhiyun  */
dfltcc_can_inflate(z_streamp strm)13*4882a593Smuzhiyun int dfltcc_can_inflate(
14*4882a593Smuzhiyun     z_streamp strm
15*4882a593Smuzhiyun )
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun     struct inflate_state *state = (struct inflate_state *)strm->state;
18*4882a593Smuzhiyun     struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun     /* Check for kernel dfltcc command line parameter */
21*4882a593Smuzhiyun     if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED ||
22*4882a593Smuzhiyun             zlib_dfltcc_support == ZLIB_DFLTCC_DEFLATE_ONLY)
23*4882a593Smuzhiyun         return 0;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun     /* Unsupported compression settings */
26*4882a593Smuzhiyun     if (state->wbits != HB_BITS)
27*4882a593Smuzhiyun         return 0;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun     /* Unsupported hardware */
30*4882a593Smuzhiyun     return is_bit_set(dfltcc_state->af.fns, DFLTCC_XPND) &&
31*4882a593Smuzhiyun                is_bit_set(dfltcc_state->af.fmts, DFLTCC_FMT0);
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun EXPORT_SYMBOL(dfltcc_can_inflate);
34*4882a593Smuzhiyun 
dfltcc_was_inflate_used(z_streamp strm)35*4882a593Smuzhiyun static int dfltcc_was_inflate_used(
36*4882a593Smuzhiyun     z_streamp strm
37*4882a593Smuzhiyun )
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun     struct inflate_state *state = (struct inflate_state *)strm->state;
40*4882a593Smuzhiyun     struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun     return !param->nt;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
dfltcc_inflate_disable(z_streamp strm)45*4882a593Smuzhiyun static int dfltcc_inflate_disable(
46*4882a593Smuzhiyun     z_streamp strm
47*4882a593Smuzhiyun )
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun     struct inflate_state *state = (struct inflate_state *)strm->state;
50*4882a593Smuzhiyun     struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun     if (!dfltcc_can_inflate(strm))
53*4882a593Smuzhiyun         return 0;
54*4882a593Smuzhiyun     if (dfltcc_was_inflate_used(strm))
55*4882a593Smuzhiyun         /* DFLTCC has already decompressed some data. Since there is not
56*4882a593Smuzhiyun          * enough information to resume decompression in software, the call
57*4882a593Smuzhiyun          * must fail.
58*4882a593Smuzhiyun          */
59*4882a593Smuzhiyun         return 1;
60*4882a593Smuzhiyun     /* DFLTCC was not used yet - decompress in software */
61*4882a593Smuzhiyun     memset(&dfltcc_state->af, 0, sizeof(dfltcc_state->af));
62*4882a593Smuzhiyun     return 0;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
dfltcc_xpnd(z_streamp strm)65*4882a593Smuzhiyun static dfltcc_cc dfltcc_xpnd(
66*4882a593Smuzhiyun     z_streamp strm
67*4882a593Smuzhiyun )
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun     struct inflate_state *state = (struct inflate_state *)strm->state;
70*4882a593Smuzhiyun     struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
71*4882a593Smuzhiyun     size_t avail_in = strm->avail_in;
72*4882a593Smuzhiyun     size_t avail_out = strm->avail_out;
73*4882a593Smuzhiyun     dfltcc_cc cc;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun     cc = dfltcc(DFLTCC_XPND | HBT_CIRCULAR,
76*4882a593Smuzhiyun                 param, &strm->next_out, &avail_out,
77*4882a593Smuzhiyun                 &strm->next_in, &avail_in, state->window);
78*4882a593Smuzhiyun     strm->avail_in = avail_in;
79*4882a593Smuzhiyun     strm->avail_out = avail_out;
80*4882a593Smuzhiyun     return cc;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
dfltcc_inflate(z_streamp strm,int flush,int * ret)83*4882a593Smuzhiyun dfltcc_inflate_action dfltcc_inflate(
84*4882a593Smuzhiyun     z_streamp strm,
85*4882a593Smuzhiyun     int flush,
86*4882a593Smuzhiyun     int *ret
87*4882a593Smuzhiyun )
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun     struct inflate_state *state = (struct inflate_state *)strm->state;
90*4882a593Smuzhiyun     struct dfltcc_state *dfltcc_state = GET_DFLTCC_STATE(state);
91*4882a593Smuzhiyun     struct dfltcc_param_v0 *param = &dfltcc_state->param;
92*4882a593Smuzhiyun     dfltcc_cc cc;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun     if (flush == Z_BLOCK) {
95*4882a593Smuzhiyun         /* DFLTCC does not support stopping on block boundaries */
96*4882a593Smuzhiyun         if (dfltcc_inflate_disable(strm)) {
97*4882a593Smuzhiyun             *ret = Z_STREAM_ERROR;
98*4882a593Smuzhiyun             return DFLTCC_INFLATE_BREAK;
99*4882a593Smuzhiyun         } else
100*4882a593Smuzhiyun             return DFLTCC_INFLATE_SOFTWARE;
101*4882a593Smuzhiyun     }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun     if (state->last) {
104*4882a593Smuzhiyun         if (state->bits != 0) {
105*4882a593Smuzhiyun             strm->next_in++;
106*4882a593Smuzhiyun             strm->avail_in--;
107*4882a593Smuzhiyun             state->bits = 0;
108*4882a593Smuzhiyun         }
109*4882a593Smuzhiyun         state->mode = CHECK;
110*4882a593Smuzhiyun         return DFLTCC_INFLATE_CONTINUE;
111*4882a593Smuzhiyun     }
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun     if (strm->avail_in == 0 && !param->cf)
114*4882a593Smuzhiyun         return DFLTCC_INFLATE_BREAK;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun     if (!state->window || state->wsize == 0) {
117*4882a593Smuzhiyun         state->mode = MEM;
118*4882a593Smuzhiyun         return DFLTCC_INFLATE_CONTINUE;
119*4882a593Smuzhiyun     }
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun     /* Translate stream to parameter block */
122*4882a593Smuzhiyun     param->cvt = CVT_ADLER32;
123*4882a593Smuzhiyun     param->sbb = state->bits;
124*4882a593Smuzhiyun     param->hl = state->whave; /* Software and hardware history formats match */
125*4882a593Smuzhiyun     param->ho = (state->write - state->whave) & ((1 << HB_BITS) - 1);
126*4882a593Smuzhiyun     if (param->hl)
127*4882a593Smuzhiyun         param->nt = 0; /* Honor history for the first block */
128*4882a593Smuzhiyun     param->cv = state->check;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun     /* Inflate */
131*4882a593Smuzhiyun     do {
132*4882a593Smuzhiyun         cc = dfltcc_xpnd(strm);
133*4882a593Smuzhiyun     } while (cc == DFLTCC_CC_AGAIN);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun     /* Translate parameter block to stream */
136*4882a593Smuzhiyun     strm->msg = oesc_msg(dfltcc_state->msg, param->oesc);
137*4882a593Smuzhiyun     state->last = cc == DFLTCC_CC_OK;
138*4882a593Smuzhiyun     state->bits = param->sbb;
139*4882a593Smuzhiyun     state->whave = param->hl;
140*4882a593Smuzhiyun     state->write = (param->ho + param->hl) & ((1 << HB_BITS) - 1);
141*4882a593Smuzhiyun     state->check = param->cv;
142*4882a593Smuzhiyun     if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) {
143*4882a593Smuzhiyun         /* Report an error if stream is corrupted */
144*4882a593Smuzhiyun         state->mode = BAD;
145*4882a593Smuzhiyun         return DFLTCC_INFLATE_CONTINUE;
146*4882a593Smuzhiyun     }
147*4882a593Smuzhiyun     state->mode = TYPEDO;
148*4882a593Smuzhiyun     /* Break if operands are exhausted, otherwise continue looping */
149*4882a593Smuzhiyun     return (cc == DFLTCC_CC_OP1_TOO_SHORT || cc == DFLTCC_CC_OP2_TOO_SHORT) ?
150*4882a593Smuzhiyun         DFLTCC_INFLATE_BREAK : DFLTCC_INFLATE_CONTINUE;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun EXPORT_SYMBOL(dfltcc_inflate);
153