1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * altera-comp.c 4 * 5 * altera FPGA driver 6 * 7 * Copyright (C) Altera Corporation 1998-2001 8 * Copyright (C) 2010 NetUP Inc. 9 * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru> 10 */ 11 12 #include <linux/kernel.h> 13 #include "altera-exprt.h" 14 15 #define SHORT_BITS 16 16 #define CHAR_BITS 8 17 #define DATA_BLOB_LENGTH 3 18 #define MATCH_DATA_LENGTH 8192 19 #define ALTERA_REQUEST_SIZE 1024 20 #define ALTERA_BUFFER_SIZE (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE) 21 22 static u32 altera_bits_req(u32 n) 23 { 24 u32 result = SHORT_BITS; 25 26 if (n == 0) 27 result = 1; 28 else { 29 /* Look for the highest non-zero bit position */ 30 while ((n & (1 << (SHORT_BITS - 1))) == 0) { 31 n <<= 1; 32 --result; 33 } 34 } 35 36 return result; 37 } 38 39 static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail, 40 u32 *in_index) 41 { 42 u32 result = 0; 43 u32 shift = 0; 44 u32 databyte = 0; 45 46 while (bits > 0) { 47 databyte = buffer[*in_index]; 48 result |= (((databyte >> (CHAR_BITS - *bits_avail)) 49 & (0xff >> (CHAR_BITS - *bits_avail))) << shift); 50 51 if (bits <= *bits_avail) { 52 result &= (0xffff >> (SHORT_BITS - (bits + shift))); 53 *bits_avail -= bits; 54 bits = 0; 55 } else { 56 ++(*in_index); 57 shift += *bits_avail; 58 bits -= *bits_avail; 59 *bits_avail = CHAR_BITS; 60 } 61 } 62 63 return result; 64 } 65 66 u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version) 67 { 68 u32 i, j, data_length = 0L; 69 u32 offset, length; 70 u32 match_data_length = MATCH_DATA_LENGTH; 71 u32 bits_avail = CHAR_BITS; 72 u32 in_index = 0L; 73 74 if (version > 0) 75 --match_data_length; 76 77 for (i = 0; i < out_length; ++i) 78 out[i] = 0; 79 80 /* Read number of bytes in data. */ 81 for (i = 0; i < sizeof(in_length); ++i) { 82 data_length = data_length | ( 83 altera_read_packed(in, 84 CHAR_BITS, 85 &bits_avail, 86 &in_index) << (i * CHAR_BITS)); 87 } 88 89 if (data_length > out_length) { 90 data_length = 0L; 91 return data_length; 92 } 93 94 i = 0; 95 while (i < data_length) { 96 /* A 0 bit indicates literal data. */ 97 if (altera_read_packed(in, 1, &bits_avail, 98 &in_index) == 0) { 99 for (j = 0; j < DATA_BLOB_LENGTH; ++j) { 100 if (i < data_length) { 101 out[i] = (u8)altera_read_packed(in, 102 CHAR_BITS, 103 &bits_avail, 104 &in_index); 105 i++; 106 } 107 } 108 } else { 109 /* A 1 bit indicates offset/length to follow. */ 110 offset = altera_read_packed(in, altera_bits_req((s16) 111 (i > match_data_length ? 112 match_data_length : i)), 113 &bits_avail, 114 &in_index); 115 length = altera_read_packed(in, CHAR_BITS, 116 &bits_avail, 117 &in_index); 118 for (j = 0; j < length; ++j) { 119 if (i < data_length) { 120 out[i] = out[i - offset]; 121 i++; 122 } 123 } 124 } 125 } 126 127 return data_length; 128 } 129