GNU Linux-libre 4.4.284-gnu1
[releases.git] / drivers / misc / altera-stapl / altera-comp.c
1 /*
2  * altera-comp.c
3  *
4  * altera FPGA driver
5  *
6  * Copyright (C) Altera Corporation 1998-2001
7  * Copyright (C) 2010 NetUP Inc.
8  * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #include <linux/kernel.h>
27 #include "altera-exprt.h"
28
29 #define SHORT_BITS              16
30 #define CHAR_BITS               8
31 #define DATA_BLOB_LENGTH        3
32 #define MATCH_DATA_LENGTH       8192
33 #define ALTERA_REQUEST_SIZE     1024
34 #define ALTERA_BUFFER_SIZE      (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE)
35
36 static u32 altera_bits_req(u32 n)
37 {
38         u32 result = SHORT_BITS;
39
40         if (n == 0)
41                 result = 1;
42         else {
43                 /* Look for the highest non-zero bit position */
44                 while ((n & (1 << (SHORT_BITS - 1))) == 0) {
45                         n <<= 1;
46                         --result;
47                 }
48         }
49
50         return result;
51 }
52
53 static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail,
54                                                         u32 *in_index)
55 {
56         u32 result = 0;
57         u32 shift = 0;
58         u32 databyte = 0;
59
60         while (bits > 0) {
61                 databyte = buffer[*in_index];
62                 result |= (((databyte >> (CHAR_BITS - *bits_avail))
63                         & (0xff >> (CHAR_BITS - *bits_avail))) << shift);
64
65                 if (bits <= *bits_avail) {
66                         result &= (0xffff >> (SHORT_BITS - (bits + shift)));
67                         *bits_avail -= bits;
68                         bits = 0;
69                 } else {
70                         ++(*in_index);
71                         shift += *bits_avail;
72                         bits -= *bits_avail;
73                         *bits_avail = CHAR_BITS;
74                 }
75         }
76
77         return result;
78 }
79
80 u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version)
81 {
82         u32 i, j, data_length = 0L;
83         u32 offset, length;
84         u32 match_data_length = MATCH_DATA_LENGTH;
85         u32 bits_avail = CHAR_BITS;
86         u32 in_index = 0L;
87
88         if (version > 0)
89                 --match_data_length;
90
91         for (i = 0; i < out_length; ++i)
92                 out[i] = 0;
93
94         /* Read number of bytes in data. */
95         for (i = 0; i < sizeof(in_length); ++i) {
96                 data_length = data_length | (
97                         altera_read_packed(in,
98                                         CHAR_BITS,
99                                         &bits_avail,
100                                         &in_index) << (i * CHAR_BITS));
101         }
102
103         if (data_length > out_length) {
104                 data_length = 0L;
105                 return data_length;
106         }
107
108         i = 0;
109         while (i < data_length) {
110                 /* A 0 bit indicates literal data. */
111                 if (altera_read_packed(in, 1, &bits_avail,
112                                                 &in_index) == 0) {
113                         for (j = 0; j < DATA_BLOB_LENGTH; ++j) {
114                                 if (i < data_length) {
115                                         out[i] = (u8)altera_read_packed(in,
116                                                         CHAR_BITS,
117                                                         &bits_avail,
118                                                         &in_index);
119                                         i++;
120                                 }
121                         }
122                 } else {
123                         /* A 1 bit indicates offset/length to follow. */
124                         offset = altera_read_packed(in, altera_bits_req((s16)
125                                         (i > match_data_length ?
126                                                 match_data_length : i)),
127                                         &bits_avail,
128                                         &in_index);
129                         length = altera_read_packed(in, CHAR_BITS,
130                                         &bits_avail,
131                                         &in_index);
132                         for (j = 0; j < length; ++j) {
133                                 if (i < data_length) {
134                                         out[i] = out[i - offset];
135                                         i++;
136                                 }
137                         }
138                 }
139         }
140
141         return data_length;
142 }