|  | /* Linux driver for Philips webcam | 
|  | Decompression for chipset version 2 et 3 | 
|  | (C) 2004-2006  Luc Saillard (luc@saillard.org) | 
|  |  | 
|  | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | 
|  | driver and thus may have bugs that are not present in the original version. | 
|  | Please send bug reports and support requests to <luc@saillard.org>. | 
|  | The decompression routines have been implemented by reverse-engineering the | 
|  | Nemosoft binary pwcx module. Caveat emptor. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 2 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the Free Software | 
|  | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  |  | 
|  | */ | 
|  |  | 
|  | #include "pwc-timon.h" | 
|  | #include "pwc-kiara.h" | 
|  | #include "pwc-dec23.h" | 
|  | #include <media/pwc-ioctl.h> | 
|  |  | 
|  | #include <linux/string.h> | 
|  |  | 
|  | /* | 
|  | * USE_LOOKUP_TABLE_TO_CLAMP | 
|  | *   0: use a C version of this tests:  {  a<0?0:(a>255?255:a) } | 
|  | *   1: use a faster lookup table for cpu with a big cache (intel) | 
|  | */ | 
|  | #define USE_LOOKUP_TABLE_TO_CLAMP	1 | 
|  | /* | 
|  | * UNROLL_LOOP_FOR_COPYING_BLOCK | 
|  | *   0: use a loop for a smaller code (but little slower) | 
|  | *   1: when unrolling the loop, gcc produces some faster code (perhaps only | 
|  | *   valid for intel processor class). Activating this option, automaticaly | 
|  | *   activate USE_LOOKUP_TABLE_TO_CLAMP | 
|  | */ | 
|  | #define UNROLL_LOOP_FOR_COPY		1 | 
|  | #if UNROLL_LOOP_FOR_COPY | 
|  | # undef USE_LOOKUP_TABLE_TO_CLAMP | 
|  | # define USE_LOOKUP_TABLE_TO_CLAMP 1 | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * ENABLE_BAYER_DECODER | 
|  | *   0: bayer decoder is not build (save some space) | 
|  | *   1: bayer decoder is build and can be used | 
|  | */ | 
|  | #define ENABLE_BAYER_DECODER 0 | 
|  |  | 
|  | static void build_subblock_pattern(struct pwc_dec23_private *pdec) | 
|  | { | 
|  | static const unsigned int initial_values[12] = { | 
|  | -0x526500, -0x221200, 0x221200, 0x526500, | 
|  | -0x3de200, 0x3de200, | 
|  | -0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480, | 
|  | -0x12c200, 0x12c200 | 
|  |  | 
|  | }; | 
|  | static const unsigned int values_derivated[12] = { | 
|  | 0xa4ca, 0x4424, -0x4424, -0xa4ca, | 
|  | 0x7bc4, -0x7bc4, | 
|  | 0xdb69, 0x5aba, -0x5aba, -0xdb69, | 
|  | 0x2584, -0x2584 | 
|  | }; | 
|  | unsigned int temp_values[12]; | 
|  | int i, j; | 
|  |  | 
|  | memcpy(temp_values, initial_values, sizeof(initial_values)); | 
|  | for (i = 0; i < 256; i++) { | 
|  | for (j = 0; j < 12; j++) { | 
|  | pdec->table_subblock[i][j] = temp_values[j]; | 
|  | temp_values[j] += values_derivated[j]; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void build_bit_powermask_table(struct pwc_dec23_private *pdec) | 
|  | { | 
|  | unsigned char *p; | 
|  | unsigned int bit, byte, mask, val; | 
|  | unsigned int bitpower = 1; | 
|  |  | 
|  | for (bit = 0; bit < 8; bit++) { | 
|  | mask = bitpower - 1; | 
|  | p = pdec->table_bitpowermask[bit]; | 
|  | for (byte = 0; byte < 256; byte++) { | 
|  | val = (byte & mask); | 
|  | if (byte & bitpower) | 
|  | val = -val; | 
|  | *p++ = val; | 
|  | } | 
|  | bitpower<<=1; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static void build_table_color(const unsigned int romtable[16][8], | 
|  | unsigned char p0004[16][1024], | 
|  | unsigned char p8004[16][256]) | 
|  | { | 
|  | int compression_mode, j, k, bit, pw; | 
|  | unsigned char *p0, *p8; | 
|  | const unsigned int *r; | 
|  |  | 
|  | /* We have 16 compressions tables */ | 
|  | for (compression_mode = 0; compression_mode < 16; compression_mode++) { | 
|  | p0 = p0004[compression_mode]; | 
|  | p8 = p8004[compression_mode]; | 
|  | r  = romtable[compression_mode]; | 
|  |  | 
|  | for (j = 0; j < 8; j++, r++, p0 += 128) { | 
|  |  | 
|  | for (k = 0; k < 16; k++) { | 
|  | if (k == 0) | 
|  | bit = 1; | 
|  | else if (k >= 1 && k < 3) | 
|  | bit = (r[0] >> 15) & 7; | 
|  | else if (k >= 3 && k < 6) | 
|  | bit = (r[0] >> 12) & 7; | 
|  | else if (k >= 6 && k < 10) | 
|  | bit = (r[0] >> 9) & 7; | 
|  | else if (k >= 10 && k < 13) | 
|  | bit = (r[0] >> 6) & 7; | 
|  | else if (k >= 13 && k < 15) | 
|  | bit = (r[0] >> 3) & 7; | 
|  | else | 
|  | bit = (r[0]) & 7; | 
|  | if (k == 0) | 
|  | *p8++ = 8; | 
|  | else | 
|  | *p8++ = j - bit; | 
|  | *p8++ = bit; | 
|  |  | 
|  | pw = 1 << bit; | 
|  | p0[k + 0x00] = (1 * pw) + 0x80; | 
|  | p0[k + 0x10] = (2 * pw) + 0x80; | 
|  | p0[k + 0x20] = (3 * pw) + 0x80; | 
|  | p0[k + 0x30] = (4 * pw) + 0x80; | 
|  | p0[k + 0x40] = (-1 * pw) + 0x80; | 
|  | p0[k + 0x50] = (-2 * pw) + 0x80; | 
|  | p0[k + 0x60] = (-3 * pw) + 0x80; | 
|  | p0[k + 0x70] = (-4 * pw) + 0x80; | 
|  | }	/* end of for (k=0; k<16; k++, p8++) */ | 
|  | }	/* end of for (j=0; j<8; j++ , table++) */ | 
|  | } /* end of foreach compression_mode */ | 
|  | } | 
|  |  | 
|  | /* | 
|  | * | 
|  | */ | 
|  | static void fill_table_dc00_d800(struct pwc_dec23_private *pdec) | 
|  | { | 
|  | #define SCALEBITS 15 | 
|  | #define ONE_HALF  (1UL << (SCALEBITS - 1)) | 
|  | int i; | 
|  | unsigned int offset1 = ONE_HALF; | 
|  | unsigned int offset2 = 0x0000; | 
|  |  | 
|  | for (i=0; i<256; i++) { | 
|  | pdec->table_dc00[i] = offset1 & ~(ONE_HALF); | 
|  | pdec->table_d800[i] = offset2; | 
|  |  | 
|  | offset1 += 0x7bc4; | 
|  | offset2 += 0x7bc4; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * To decode the stream: | 
|  | *   if look_bits(2) == 0:	# op == 2 in the lookup table | 
|  | *      skip_bits(2) | 
|  | *      end of the stream | 
|  | *   elif look_bits(3) == 7:	# op == 1 in the lookup table | 
|  | *      skip_bits(3) | 
|  | *      yyyy = get_bits(4) | 
|  | *      xxxx = get_bits(8) | 
|  | *   else:			# op == 0 in the lookup table | 
|  | *      skip_bits(x) | 
|  | * | 
|  | * For speedup processing, we build a lookup table and we takes the first 6 bits. | 
|  | * | 
|  | * struct { | 
|  | *   unsigned char op;	    // operation to execute | 
|  | *   unsigned char bits;    // bits use to perform operation | 
|  | *   unsigned char offset1; // offset to add to access in the table_0004 % 16 | 
|  | *   unsigned char offset2; // offset to add to access in the table_0004 | 
|  | * } | 
|  | * | 
|  | * How to build this table ? | 
|  | *   op == 2 when (i%4)==0 | 
|  | *   op == 1 when (i%8)==7 | 
|  | *   op == 0 otherwise | 
|  | * | 
|  | */ | 
|  | static const unsigned char hash_table_ops[64*4] = { | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x00, | 
|  | 0x00, 0x04, 0x01, 0x10, | 
|  | 0x00, 0x06, 0x01, 0x30, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x40, | 
|  | 0x00, 0x05, 0x01, 0x20, | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x00, | 
|  | 0x00, 0x04, 0x01, 0x50, | 
|  | 0x00, 0x05, 0x02, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x40, | 
|  | 0x00, 0x05, 0x03, 0x00, | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x00, | 
|  | 0x00, 0x04, 0x01, 0x10, | 
|  | 0x00, 0x06, 0x02, 0x10, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x40, | 
|  | 0x00, 0x05, 0x01, 0x60, | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x00, | 
|  | 0x00, 0x04, 0x01, 0x50, | 
|  | 0x00, 0x05, 0x02, 0x40, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x40, | 
|  | 0x00, 0x05, 0x03, 0x40, | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x00, | 
|  | 0x00, 0x04, 0x01, 0x10, | 
|  | 0x00, 0x06, 0x01, 0x70, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x40, | 
|  | 0x00, 0x05, 0x01, 0x20, | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x00, | 
|  | 0x00, 0x04, 0x01, 0x50, | 
|  | 0x00, 0x05, 0x02, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x40, | 
|  | 0x00, 0x05, 0x03, 0x00, | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x00, | 
|  | 0x00, 0x04, 0x01, 0x10, | 
|  | 0x00, 0x06, 0x02, 0x50, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x40, | 
|  | 0x00, 0x05, 0x01, 0x60, | 
|  | 0x01, 0x00, 0x00, 0x00, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x00, | 
|  | 0x00, 0x04, 0x01, 0x50, | 
|  | 0x00, 0x05, 0x02, 0x40, | 
|  | 0x02, 0x00, 0x00, 0x00, | 
|  | 0x00, 0x03, 0x01, 0x40, | 
|  | 0x00, 0x05, 0x03, 0x40, | 
|  | 0x01, 0x00, 0x00, 0x00 | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * | 
|  | */ | 
|  | static const unsigned int MulIdx[16][16] = { | 
|  | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, | 
|  | {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,}, | 
|  | {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,}, | 
|  | {4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,}, | 
|  | {6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,}, | 
|  | {4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,}, | 
|  | {1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,}, | 
|  | {0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,}, | 
|  | {0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,}, | 
|  | {1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,}, | 
|  | {7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,}, | 
|  | {4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,}, | 
|  | {7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,}, | 
|  | {1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,}, | 
|  | {1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,}, | 
|  | {10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10} | 
|  | }; | 
|  |  | 
|  | #if USE_LOOKUP_TABLE_TO_CLAMP | 
|  | #define MAX_OUTER_CROP_VALUE	(512) | 
|  | static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE]; | 
|  | #define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)]) | 
|  | #else | 
|  | #define CLAMP(x) ((x)>255?255:((x)<0?0:x)) | 
|  | #endif | 
|  |  | 
|  |  | 
|  | /* If the type or the command change, we rebuild the lookup table */ | 
|  | int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd) | 
|  | { | 
|  | int flags, version, shift, i; | 
|  | struct pwc_dec23_private *pdec; | 
|  |  | 
|  | if (pwc->decompress_data == NULL) { | 
|  | pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); | 
|  | if (pdec == NULL) | 
|  | return -ENOMEM; | 
|  | pwc->decompress_data = pdec; | 
|  | } | 
|  | pdec = pwc->decompress_data; | 
|  |  | 
|  | if (DEVICE_USE_CODEC3(type)) { | 
|  | flags = cmd[2] & 0x18; | 
|  | if (flags == 8) | 
|  | pdec->nbits = 7;	/* More bits, mean more bits to encode the stream, but better quality */ | 
|  | else if (flags == 0x10) | 
|  | pdec->nbits = 8; | 
|  | else | 
|  | pdec->nbits = 6; | 
|  |  | 
|  | version = cmd[2] >> 5; | 
|  | build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1); | 
|  | build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); | 
|  |  | 
|  | } else { | 
|  |  | 
|  | flags = cmd[2] & 6; | 
|  | if (flags == 2) | 
|  | pdec->nbits = 7; | 
|  | else if (flags == 4) | 
|  | pdec->nbits = 8; | 
|  | else | 
|  | pdec->nbits = 6; | 
|  |  | 
|  | version = cmd[2] >> 3; | 
|  | build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1); | 
|  | build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); | 
|  | } | 
|  |  | 
|  | /* Informations can be coded on a variable number of bits but never less than 8 */ | 
|  | shift = 8 - pdec->nbits; | 
|  | pdec->scalebits = SCALEBITS - shift; | 
|  | pdec->nbitsmask = 0xFF >> shift; | 
|  |  | 
|  | fill_table_dc00_d800(pdec); | 
|  | build_subblock_pattern(pdec); | 
|  | build_bit_powermask_table(pdec); | 
|  |  | 
|  | #if USE_LOOKUP_TABLE_TO_CLAMP | 
|  | /* Build the static table to clamp value [0-255] */ | 
|  | for (i=0;i<MAX_OUTER_CROP_VALUE;i++) | 
|  | pwc_crop_table[i] = 0; | 
|  | for (i=0; i<256; i++) | 
|  | pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i; | 
|  | for (i=0; i<MAX_OUTER_CROP_VALUE; i++) | 
|  | pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255; | 
|  | #endif | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Copy the 4x4 image block to Y plane buffer | 
|  | */ | 
|  | static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) | 
|  | { | 
|  | #if UNROLL_LOOP_FOR_COPY | 
|  | const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; | 
|  | const int *c = src; | 
|  | unsigned char *d = dst; | 
|  |  | 
|  | *d++ = cm[c[0] >> scalebits]; | 
|  | *d++ = cm[c[1] >> scalebits]; | 
|  | *d++ = cm[c[2] >> scalebits]; | 
|  | *d++ = cm[c[3] >> scalebits]; | 
|  |  | 
|  | d = dst + bytes_per_line; | 
|  | *d++ = cm[c[4] >> scalebits]; | 
|  | *d++ = cm[c[5] >> scalebits]; | 
|  | *d++ = cm[c[6] >> scalebits]; | 
|  | *d++ = cm[c[7] >> scalebits]; | 
|  |  | 
|  | d = dst + bytes_per_line*2; | 
|  | *d++ = cm[c[8] >> scalebits]; | 
|  | *d++ = cm[c[9] >> scalebits]; | 
|  | *d++ = cm[c[10] >> scalebits]; | 
|  | *d++ = cm[c[11] >> scalebits]; | 
|  |  | 
|  | d = dst + bytes_per_line*3; | 
|  | *d++ = cm[c[12] >> scalebits]; | 
|  | *d++ = cm[c[13] >> scalebits]; | 
|  | *d++ = cm[c[14] >> scalebits]; | 
|  | *d++ = cm[c[15] >> scalebits]; | 
|  | #else | 
|  | int i; | 
|  | const int *c = src; | 
|  | unsigned char *d = dst; | 
|  | for (i = 0; i < 4; i++, c++) | 
|  | *d++ = CLAMP((*c) >> scalebits); | 
|  |  | 
|  | d = dst + bytes_per_line; | 
|  | for (i = 0; i < 4; i++, c++) | 
|  | *d++ = CLAMP((*c) >> scalebits); | 
|  |  | 
|  | d = dst + bytes_per_line*2; | 
|  | for (i = 0; i < 4; i++, c++) | 
|  | *d++ = CLAMP((*c) >> scalebits); | 
|  |  | 
|  | d = dst + bytes_per_line*3; | 
|  | for (i = 0; i < 4; i++, c++) | 
|  | *d++ = CLAMP((*c) >> scalebits); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Copy the 4x4 image block to a CrCb plane buffer | 
|  | * | 
|  | */ | 
|  | static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) | 
|  | { | 
|  | #if UNROLL_LOOP_FOR_COPY | 
|  | /* Unroll all loops */ | 
|  | const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; | 
|  | const int *c = src; | 
|  | unsigned char *d = dst; | 
|  |  | 
|  | *d++ = cm[c[0] >> scalebits]; | 
|  | *d++ = cm[c[4] >> scalebits]; | 
|  | *d++ = cm[c[1] >> scalebits]; | 
|  | *d++ = cm[c[5] >> scalebits]; | 
|  | *d++ = cm[c[2] >> scalebits]; | 
|  | *d++ = cm[c[6] >> scalebits]; | 
|  | *d++ = cm[c[3] >> scalebits]; | 
|  | *d++ = cm[c[7] >> scalebits]; | 
|  |  | 
|  | d = dst + bytes_per_line; | 
|  | *d++ = cm[c[12] >> scalebits]; | 
|  | *d++ = cm[c[8] >> scalebits]; | 
|  | *d++ = cm[c[13] >> scalebits]; | 
|  | *d++ = cm[c[9] >> scalebits]; | 
|  | *d++ = cm[c[14] >> scalebits]; | 
|  | *d++ = cm[c[10] >> scalebits]; | 
|  | *d++ = cm[c[15] >> scalebits]; | 
|  | *d++ = cm[c[11] >> scalebits]; | 
|  | #else | 
|  | int i; | 
|  | const int *c1 = src; | 
|  | const int *c2 = src + 4; | 
|  | unsigned char *d = dst; | 
|  |  | 
|  | for (i = 0; i < 4; i++, c1++, c2++) { | 
|  | *d++ = CLAMP((*c1) >> scalebits); | 
|  | *d++ = CLAMP((*c2) >> scalebits); | 
|  | } | 
|  | c1 = src + 12; | 
|  | d = dst + bytes_per_line; | 
|  | for (i = 0; i < 4; i++, c1++, c2++) { | 
|  | *d++ = CLAMP((*c1) >> scalebits); | 
|  | *d++ = CLAMP((*c2) >> scalebits); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #if ENABLE_BAYER_DECODER | 
|  | /* | 
|  | * Format: 8x2 pixels | 
|  | *   . G . G . G . G . G . G . G | 
|  | *   . . . . . . . . . . . . . . | 
|  | *   . G . G . G . G . G . G . G | 
|  | *   . . . . . . . . . . . . . . | 
|  | *   or | 
|  | *   . . . . . . . . . . . . . . | 
|  | *   G . G . G . G . G . G . G . | 
|  | *   . . . . . . . . . . . . . . | 
|  | *   G . G . G . G . G . G . G . | 
|  | */ | 
|  | static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) | 
|  | { | 
|  | #if UNROLL_LOOP_FOR_COPY | 
|  | /* Unroll all loops */ | 
|  | const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; | 
|  | unsigned char *d = dst; | 
|  | const int *c = src; | 
|  |  | 
|  | d[0] = cm[c[0] >> scalebits]; | 
|  | d[2] = cm[c[1] >> scalebits]; | 
|  | d[4] = cm[c[2] >> scalebits]; | 
|  | d[6] = cm[c[3] >> scalebits]; | 
|  | d[8] = cm[c[4] >> scalebits]; | 
|  | d[10] = cm[c[5] >> scalebits]; | 
|  | d[12] = cm[c[6] >> scalebits]; | 
|  | d[14] = cm[c[7] >> scalebits]; | 
|  |  | 
|  | d = dst + bytes_per_line; | 
|  | d[0] = cm[c[8] >> scalebits]; | 
|  | d[2] = cm[c[9] >> scalebits]; | 
|  | d[4] = cm[c[10] >> scalebits]; | 
|  | d[6] = cm[c[11] >> scalebits]; | 
|  | d[8] = cm[c[12] >> scalebits]; | 
|  | d[10] = cm[c[13] >> scalebits]; | 
|  | d[12] = cm[c[14] >> scalebits]; | 
|  | d[14] = cm[c[15] >> scalebits]; | 
|  | #else | 
|  | int i; | 
|  | unsigned char *d; | 
|  | const int *c = src; | 
|  |  | 
|  | d = dst; | 
|  | for (i = 0; i < 8; i++, c++) | 
|  | d[i*2] = CLAMP((*c) >> scalebits); | 
|  |  | 
|  | d = dst + bytes_per_line; | 
|  | for (i = 0; i < 8; i++, c++) | 
|  | d[i*2] = CLAMP((*c) >> scalebits); | 
|  | #endif | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #if ENABLE_BAYER_DECODER | 
|  | /* | 
|  | * Format: 4x4 pixels | 
|  | *   R . R . R . R | 
|  | *   . B . B . B . | 
|  | *   R . R . R . R | 
|  | *   . B . B . B . | 
|  | */ | 
|  | static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) | 
|  | { | 
|  | #if UNROLL_LOOP_FOR_COPY | 
|  | /* Unroll all loops */ | 
|  | const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; | 
|  | unsigned char *d = dst; | 
|  | const int *c = src; | 
|  |  | 
|  | d[0] = cm[c[0] >> scalebits]; | 
|  | d[2] = cm[c[1] >> scalebits]; | 
|  | d[4] = cm[c[2] >> scalebits]; | 
|  | d[6] = cm[c[3] >> scalebits]; | 
|  |  | 
|  | d = dst + bytes_per_line; | 
|  | d[1] = cm[c[4] >> scalebits]; | 
|  | d[3] = cm[c[5] >> scalebits]; | 
|  | d[5] = cm[c[6] >> scalebits]; | 
|  | d[7] = cm[c[7] >> scalebits]; | 
|  |  | 
|  | d = dst + bytes_per_line*2; | 
|  | d[0] = cm[c[8] >> scalebits]; | 
|  | d[2] = cm[c[9] >> scalebits]; | 
|  | d[4] = cm[c[10] >> scalebits]; | 
|  | d[6] = cm[c[11] >> scalebits]; | 
|  |  | 
|  | d = dst + bytes_per_line*3; | 
|  | d[1] = cm[c[12] >> scalebits]; | 
|  | d[3] = cm[c[13] >> scalebits]; | 
|  | d[5] = cm[c[14] >> scalebits]; | 
|  | d[7] = cm[c[15] >> scalebits]; | 
|  | #else | 
|  | int i; | 
|  | unsigned char *d; | 
|  | const int *c = src; | 
|  |  | 
|  | d = dst; | 
|  | for (i = 0; i < 4; i++, c++) | 
|  | d[i*2] = CLAMP((*c) >> scalebits); | 
|  |  | 
|  | d = dst + bytes_per_line; | 
|  | for (i = 0; i < 4; i++, c++) | 
|  | d[i*2+1] = CLAMP((*c) >> scalebits); | 
|  |  | 
|  | d = dst + bytes_per_line*2; | 
|  | for (i = 0; i < 4; i++, c++) | 
|  | d[i*2] = CLAMP((*c) >> scalebits); | 
|  |  | 
|  | d = dst + bytes_per_line*3; | 
|  | for (i = 0; i < 4; i++, c++) | 
|  | d[i*2+1] = CLAMP((*c) >> scalebits); | 
|  | #endif | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * To manage the stream, we keep bits in a 32 bits register. | 
|  | * fill_nbits(n): fill the reservoir with at least n bits | 
|  | * skip_bits(n): discard n bits from the reservoir | 
|  | * get_bits(n): fill the reservoir, returns the first n bits and discard the | 
|  | *              bits from the reservoir. | 
|  | * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir | 
|  | *                 contains at least n bits. bits returned is discarded. | 
|  | */ | 
|  | #define fill_nbits(pdec, nbits_wanted) do { \ | 
|  | while (pdec->nbits_in_reservoir<(nbits_wanted)) \ | 
|  | { \ | 
|  | pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \ | 
|  | pdec->nbits_in_reservoir += 8; \ | 
|  | } \ | 
|  | }  while(0); | 
|  |  | 
|  | #define skip_nbits(pdec, nbits_to_skip) do { \ | 
|  | pdec->reservoir >>= (nbits_to_skip); \ | 
|  | pdec->nbits_in_reservoir -= (nbits_to_skip); \ | 
|  | }  while(0); | 
|  |  | 
|  | #define get_nbits(pdec, nbits_wanted, result) do { \ | 
|  | fill_nbits(pdec, nbits_wanted); \ | 
|  | result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \ | 
|  | skip_nbits(pdec, nbits_wanted); \ | 
|  | }  while(0); | 
|  |  | 
|  | #define __get_nbits(pdec, nbits_wanted, result) do { \ | 
|  | result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \ | 
|  | skip_nbits(pdec, nbits_wanted); \ | 
|  | }  while(0); | 
|  |  | 
|  | #define look_nbits(pdec, nbits_wanted) \ | 
|  | ((pdec->reservoir) & ((1U<<(nbits_wanted))-1)) | 
|  |  | 
|  | /* | 
|  | * Decode a 4x4 pixel block | 
|  | */ | 
|  | static void decode_block(struct pwc_dec23_private *pdec, | 
|  | const unsigned char *ptable0004, | 
|  | const unsigned char *ptable8004) | 
|  | { | 
|  | unsigned int primary_color; | 
|  | unsigned int channel_v, offset1, op; | 
|  | int i; | 
|  |  | 
|  | fill_nbits(pdec, 16); | 
|  | __get_nbits(pdec, pdec->nbits, primary_color); | 
|  |  | 
|  | if (look_nbits(pdec,2) == 0) { | 
|  | skip_nbits(pdec, 2); | 
|  | /* Very simple, the color is the same for all pixels of the square */ | 
|  | for (i = 0; i < 16; i++) | 
|  | pdec->temp_colors[i] = pdec->table_dc00[primary_color]; | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* This block is encoded with small pattern */ | 
|  | for (i = 0; i < 16; i++) | 
|  | pdec->temp_colors[i] = pdec->table_d800[primary_color]; | 
|  |  | 
|  | __get_nbits(pdec, 3, channel_v); | 
|  | channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2); | 
|  |  | 
|  | ptable0004 += (channel_v * 128); | 
|  | ptable8004 += (channel_v * 32); | 
|  |  | 
|  | offset1 = 0; | 
|  | do | 
|  | { | 
|  | unsigned int htable_idx, rows = 0; | 
|  | const unsigned int *block; | 
|  |  | 
|  | /* [  zzzz y x x ] | 
|  | *     xx == 00 :=> end of the block def, remove the two bits from the stream | 
|  | *    yxx == 111 | 
|  | *    yxx == any other value | 
|  | * | 
|  | */ | 
|  | fill_nbits(pdec, 16); | 
|  | htable_idx = look_nbits(pdec, 6); | 
|  | op = hash_table_ops[htable_idx * 4]; | 
|  |  | 
|  | if (op == 2) { | 
|  | skip_nbits(pdec, 2); | 
|  |  | 
|  | } else if (op == 1) { | 
|  | /* 15bits [ xxxx xxxx yyyy 111 ] | 
|  | * yyy => offset in the table8004 | 
|  | * xxx => offset in the tabled004 (tree) | 
|  | */ | 
|  | unsigned int mask, shift; | 
|  | unsigned int nbits, col1; | 
|  | unsigned int yyyy; | 
|  |  | 
|  | skip_nbits(pdec, 3); | 
|  | /* offset1 += yyyy */ | 
|  | __get_nbits(pdec, 4, yyyy); | 
|  | offset1 += 1 + yyyy; | 
|  | offset1 &= 0x0F; | 
|  | nbits = ptable8004[offset1 * 2]; | 
|  |  | 
|  | /* col1 = xxxx xxxx */ | 
|  | __get_nbits(pdec, nbits+1, col1); | 
|  |  | 
|  | /* Bit mask table */ | 
|  | mask = pdec->table_bitpowermask[nbits][col1]; | 
|  | shift = ptable8004[offset1 * 2 + 1]; | 
|  | rows = ((mask << shift) + 0x80) & 0xFF; | 
|  |  | 
|  | block = pdec->table_subblock[rows]; | 
|  | for (i = 0; i < 16; i++) | 
|  | pdec->temp_colors[i] += block[MulIdx[offset1][i]]; | 
|  |  | 
|  | } else { | 
|  | /* op == 0 | 
|  | * offset1 is coded on 3 bits | 
|  | */ | 
|  | unsigned int shift; | 
|  |  | 
|  | offset1 += hash_table_ops [htable_idx * 4 + 2]; | 
|  | offset1 &= 0x0F; | 
|  |  | 
|  | rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]]; | 
|  | block = pdec->table_subblock[rows]; | 
|  | for (i = 0; i < 16; i++) | 
|  | pdec->temp_colors[i] += block[MulIdx[offset1][i]]; | 
|  |  | 
|  | shift = hash_table_ops[htable_idx * 4 + 1]; | 
|  | skip_nbits(pdec, shift); | 
|  | } | 
|  |  | 
|  | } while (op != 2); | 
|  |  | 
|  | } | 
|  |  | 
|  | static void DecompressBand23(struct pwc_dec23_private *pdec, | 
|  | const unsigned char *rawyuv, | 
|  | unsigned char *planar_y, | 
|  | unsigned char *planar_u, | 
|  | unsigned char *planar_v, | 
|  | unsigned int   compressed_image_width, | 
|  | unsigned int   real_image_width) | 
|  | { | 
|  | int compression_index, nblocks; | 
|  | const unsigned char *ptable0004; | 
|  | const unsigned char *ptable8004; | 
|  |  | 
|  | pdec->reservoir = 0; | 
|  | pdec->nbits_in_reservoir = 0; | 
|  | pdec->stream = rawyuv + 1;	/* The first byte of the stream is skipped */ | 
|  |  | 
|  | get_nbits(pdec, 4, compression_index); | 
|  |  | 
|  | /* pass 1: uncompress Y component */ | 
|  | nblocks = compressed_image_width / 4; | 
|  |  | 
|  | ptable0004 = pdec->table_0004_pass1[compression_index]; | 
|  | ptable8004 = pdec->table_8004_pass1[compression_index]; | 
|  |  | 
|  | /* Each block decode a square of 4x4 */ | 
|  | while (nblocks) { | 
|  | decode_block(pdec, ptable0004, ptable8004); | 
|  | copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits); | 
|  | planar_y += 4; | 
|  | nblocks--; | 
|  | } | 
|  |  | 
|  | /* pass 2: uncompress UV component */ | 
|  | nblocks = compressed_image_width / 8; | 
|  |  | 
|  | ptable0004 = pdec->table_0004_pass2[compression_index]; | 
|  | ptable8004 = pdec->table_8004_pass2[compression_index]; | 
|  |  | 
|  | /* Each block decode a square of 4x4 */ | 
|  | while (nblocks) { | 
|  | decode_block(pdec, ptable0004, ptable8004); | 
|  | copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits); | 
|  |  | 
|  | decode_block(pdec, ptable0004, ptable8004); | 
|  | copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits); | 
|  |  | 
|  | planar_v += 8; | 
|  | planar_u += 8; | 
|  | nblocks -= 2; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | #if ENABLE_BAYER_DECODER | 
|  | /* | 
|  | * Size need to be a multiple of 8 in width | 
|  | * | 
|  | * Return a block of four line encoded like this: | 
|  | * | 
|  | *   G R G R G R G R G R G R G R G R | 
|  | *   B G B G B G B G B G B G B G B G | 
|  | *   G R G R G R G R G R G R G R G R | 
|  | *   B G B G B G B G B G B G B G B G | 
|  | * | 
|  | */ | 
|  | static void DecompressBandBayer(struct pwc_dec23_private *pdec, | 
|  | const unsigned char *rawyuv, | 
|  | unsigned char *rgbbayer, | 
|  | unsigned int   compressed_image_width, | 
|  | unsigned int   real_image_width) | 
|  | { | 
|  | int compression_index, nblocks; | 
|  | const unsigned char *ptable0004; | 
|  | const unsigned char *ptable8004; | 
|  | unsigned char *dest; | 
|  |  | 
|  | pdec->reservoir = 0; | 
|  | pdec->nbits_in_reservoir = 0; | 
|  | pdec->stream = rawyuv + 1;	/* The first byte of the stream is skipped */ | 
|  |  | 
|  | get_nbits(pdec, 4, compression_index); | 
|  |  | 
|  | /* pass 1: uncompress RB component */ | 
|  | nblocks = compressed_image_width / 4; | 
|  |  | 
|  | ptable0004 = pdec->table_0004_pass1[compression_index]; | 
|  | ptable8004 = pdec->table_8004_pass1[compression_index]; | 
|  | dest = rgbbayer; | 
|  |  | 
|  | /* Each block decode a square of 4x4 */ | 
|  | while (nblocks) { | 
|  | decode_block(pdec, ptable0004, ptable8004); | 
|  | copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits); | 
|  | dest += 8; | 
|  | nblocks--; | 
|  | } | 
|  |  | 
|  | /* pass 2: uncompress G component */ | 
|  | nblocks = compressed_image_width / 8; | 
|  |  | 
|  | ptable0004 = pdec->table_0004_pass2[compression_index]; | 
|  | ptable8004 = pdec->table_8004_pass2[compression_index]; | 
|  |  | 
|  | /* Each block decode a square of 4x4 */ | 
|  | while (nblocks) { | 
|  | decode_block(pdec, ptable0004, ptable8004); | 
|  | copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits); | 
|  |  | 
|  | decode_block(pdec, ptable0004, ptable8004); | 
|  | copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits); | 
|  |  | 
|  | rgbbayer += 16; | 
|  | nblocks -= 2; | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  |  | 
|  | /** | 
|  | * | 
|  | * Uncompress a pwc23 buffer. | 
|  | * | 
|  | * pwc.view: size of the image wanted | 
|  | * pwc.image: size of the image returned by the camera | 
|  | * pwc.offset: (x,y) to displayer image in the view | 
|  | * | 
|  | * src: raw data | 
|  | * dst: image output | 
|  | * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER | 
|  | */ | 
|  | void pwc_dec23_decompress(const struct pwc_device *pwc, | 
|  | const void *src, | 
|  | void *dst, | 
|  | int flags) | 
|  | { | 
|  | int bandlines_left, stride, bytes_per_block; | 
|  |  | 
|  | bandlines_left = pwc->image.y / 4; | 
|  | bytes_per_block = pwc->view.x * 4; | 
|  |  | 
|  | if (flags & PWCX_FLAG_BAYER) { | 
|  | #if ENABLE_BAYER_DECODER | 
|  | /* RGB Bayer format */ | 
|  | unsigned char *rgbout; | 
|  |  | 
|  | stride = pwc->view.x * pwc->offset.y; | 
|  | rgbout = dst + stride + pwc->offset.x; | 
|  |  | 
|  |  | 
|  | while (bandlines_left--) { | 
|  |  | 
|  | DecompressBandBayer(pwc->decompress_data, | 
|  | src, | 
|  | rgbout, | 
|  | pwc->image.x, pwc->view.x); | 
|  |  | 
|  | src += pwc->vbandlength; | 
|  | rgbout += bytes_per_block; | 
|  |  | 
|  | } | 
|  | #else | 
|  | memset(dst, 0, pwc->view.x * pwc->view.y); | 
|  | #endif | 
|  |  | 
|  | } else { | 
|  | /* YUV420P image format */ | 
|  | unsigned char *pout_planar_y; | 
|  | unsigned char *pout_planar_u; | 
|  | unsigned char *pout_planar_v; | 
|  | unsigned int   plane_size; | 
|  |  | 
|  | plane_size = pwc->view.x * pwc->view.y; | 
|  |  | 
|  | /* offset in Y plane */ | 
|  | stride = pwc->view.x * pwc->offset.y; | 
|  | pout_planar_y = dst + stride + pwc->offset.x; | 
|  |  | 
|  | /* offsets in U/V planes */ | 
|  | stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2; | 
|  | pout_planar_u = dst + plane_size + stride; | 
|  | pout_planar_v = dst + plane_size + plane_size / 4 + stride; | 
|  |  | 
|  | while (bandlines_left--) { | 
|  |  | 
|  | DecompressBand23(pwc->decompress_data, | 
|  | src, | 
|  | pout_planar_y, pout_planar_u, pout_planar_v, | 
|  | pwc->image.x, pwc->view.x); | 
|  | src += pwc->vbandlength; | 
|  | pout_planar_y += bytes_per_block; | 
|  | pout_planar_u += pwc->view.x; | 
|  | pout_planar_v += pwc->view.x; | 
|  |  | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | void pwc_dec23_exit(void) | 
|  | { | 
|  | /* Do nothing */ | 
|  |  | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Allocate a private structure used by lookup table. | 
|  | * You must call kfree() to free the memory allocated. | 
|  | */ | 
|  | int pwc_dec23_alloc(struct pwc_device *pwc) | 
|  | { | 
|  | pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); | 
|  | if (pwc->decompress_data == NULL) | 
|  | return -ENOMEM; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ |