1 /* Linux driver for Philips webcam
2 Decompression for chipset version 2 et 3
3 (C) 2004 Luc Saillard (luc@saillard.org)
5 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
6 driver and thus may have bugs that are not present in the original version.
7 Please send bug reports and support requests to <luc@saillard.org>.
8 The decompression routines have been implemented by reverse-engineering the
9 Nemosoft binary pwcx module. Caveat emptor.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "pwc-timon.h"
27 #include "pwc-kiara.h"
28 #include "pwc-dec23.h"
29 #include "pwc-ioctl.h"
31 #include <linux/string.h>
40 static void fill_table_a000(unsigned int *p
)
42 static unsigned int initial_values
[12] = {
43 0xFFAD9B00, 0xFFDDEE00, 0x00221200, 0x00526500,
44 0xFFC21E00, 0x003DE200, 0xFF924B80, 0xFFD2A300,
45 0x002D5D00, 0x006DB480, 0xFFED3E00, 0x0012C200
47 static unsigned int values_derivated
[12] = {
48 0x0000A4CA, 0x00004424, 0xFFFFBBDC, 0xFFFF5B36,
49 0x00007BC4, 0xFFFF843C, 0x0000DB69, 0x00005ABA,
50 0xFFFFA546, 0xFFFF2497, 0x00002584, 0xFFFFDA7C
52 unsigned int temp_values
[12];
55 memcpy(temp_values
,initial_values
,sizeof(initial_values
));
60 *p
++ = temp_values
[j
];
61 temp_values
[j
] += values_derivated
[j
];
66 static void fill_table_d000(unsigned char *p
)
70 for (bit
=0; bit
<8; bit
++)
72 unsigned char bitpower
= 1<<bit
;
73 unsigned char mask
= bitpower
-1;
74 for (byte
=0; byte
<256; byte
++)
77 *p
++ = -(byte
& mask
);
86 * Kiara: 0 <= ver <= 7
87 * Timon: 0 <= ver <= 15
90 static void fill_table_color(unsigned int version
, const unsigned int *romtable
,
94 const unsigned int *table
;
95 unsigned char *p0
, *p8
;
99 romtable
+= version
*256;
103 table
= romtable
+ i
*128;
105 for (dl
=0; dl
<16; dl
++)
107 p0
= p0004
+ (i
<<14) + (dl
<<10);
108 p8
= p8004
+ (i
<<12) + (dl
<<8);
110 for (j
=0; j
<8; j
++ , table
++, p0
+=128)
116 else if (k
>=1 && k
<3)
117 bit
=(table
[0]>>15)&7;
118 else if (k
>=3 && k
<6)
119 bit
=(table
[0]>>12)&7;
120 else if (k
>=6 && k
<10)
122 else if (k
>=10 && k
<13)
124 else if (k
>=13 && k
<15)
129 *(unsigned char *)p8
++ = 8;
131 *(unsigned char *)p8
++ = j
- bit
;
132 *(unsigned char *)p8
++ = bit
;
135 p0
[k
+0x00] = (1*pw
) + 0x80;
136 p0
[k
+0x10] = (2*pw
) + 0x80;
137 p0
[k
+0x20] = (3*pw
) + 0x80;
138 p0
[k
+0x30] = (4*pw
) + 0x80;
139 p0
[k
+0x40] = (-pw
) + 0x80;
140 p0
[k
+0x50] = (2*-pw
) + 0x80;
141 p0
[k
+0x60] = (3*-pw
) + 0x80;
142 p0
[k
+0x70] = (4*-pw
) + 0x80;
143 } /* end of for (k=0; k<16; k++, p8++) */
144 } /* end of for (j=0; j<8; j++ , table++) */
145 } /* end of for (dl=0; dl<16; dl++) */
146 } /* end of for (i=0; i<2; i++) */
150 * precision = (pdev->xx + pdev->yy)
153 static void fill_table_dc00_d800(unsigned int precision
, unsigned int *pdc00
, unsigned int *pd800
)
156 unsigned int offset1
, offset2
;
158 for(i
=0,offset1
=0x4000, offset2
=0; i
<256 ; i
++,offset1
+=0x7BC4, offset2
+=0x7BC4)
160 unsigned int msb
= offset1
>> 15;
170 *pdc00
++ = msb
<< precision
;
178 * unsigned char op; // operation to execute
179 * unsigned char bits; // bits use to perform operation
180 * unsigned char offset1; // offset to add to access in the table_0004 % 16
181 * unsigned char offset2; // offset to add to access in the table_0004
185 static unsigned int table_ops
[] = {
186 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x30,
187 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00,
188 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00,
189 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00,
190 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x10,
191 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00,
192 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40,
193 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00,
194 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x70,
195 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00,
196 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00,
197 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00,
198 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x50,
199 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00,
200 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40,
201 0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00
205 * TODO: multiply by 4 all values
208 static unsigned int MulIdx
[256] = {
209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
211 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
212 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,
213 6, 7, 8, 9, 7,10,11, 8, 8,11,10, 7, 9, 8, 7, 6,
214 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,
215 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,
216 0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,
217 0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,
218 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,
219 7,10,11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8,11,10, 7,
220 4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,
221 7, 9, 6, 8,10, 8, 7,11,11, 7, 8,10, 8, 6, 9, 7,
222 1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,
223 1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,
224 10, 8, 7,11, 8, 6, 9, 7, 7, 9, 6, 8,11, 7, 8,10
229 void pwc_dec23_init(int type
, int release
, unsigned char *mode
, void *data
)
232 struct pwc_dec23_private
*pdev
= data
;
241 flags
= mode
[2]&0x18; /* our: flags = 8, mode[2]==e8 */
244 else if (flags
==0x10)
248 flags
= mode
[2]>>5; /* our: 7 */
250 fill_table_color(flags
, (unsigned int *)KiaraRomTable
, pdev
->table_0004
, pdev
->table_8004
);
266 fill_table_color(flags
, (unsigned int *)TimonRomTable
, pdev
->table_0004
, pdev
->table_8004
);
275 pdev
->xx
= 8 - pdev
->zz
;
276 pdev
->yy
= 15 - pdev
->xx
;
277 pdev
->zzmask
= 0xFF>>pdev
->xx
;
278 //pdev->zzmask = (1U<<pdev->zz)-1;
281 fill_table_dc00_d800(pdev
->xx
+ pdev
->yy
, pdev
->table_dc00
, pdev
->table_d800
);
282 fill_table_a000(pdev
->table_a004
);
283 fill_table_d000(pdev
->table_d004
);
288 * To manage the stream, we keep in a 32 bits variables,
289 * the next bits in the stream. fill_reservoir() add to
290 * the reservoir at least wanted nbits.
294 #define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
295 while (nbits_in_reservoir<nbits_wanted) \
297 reservoir |= (*(stream)++) << nbits_in_reservoir; \
298 nbits_in_reservoir+=8; \
302 #define get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \
303 fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted); \
304 result = (reservoir) & ((1U<<nbits_wanted)-1); \
305 reservoir >>= nbits_wanted; \
306 nbits_in_reservoir -= nbits_wanted; \
311 static void DecompressBand23(const struct pwc_dec23_private
*pdev
,
312 const unsigned char *rawyuv
,
313 unsigned char *planar_y
,
314 unsigned char *planar_u
,
315 unsigned char *planar_v
,
316 unsigned int image_x
, /* aka number of pixels wanted ??? */
317 unsigned int pixels_per_line
, /* aka number of pixels per line */
322 unsigned int reservoir
, nbits_in_reservoir
;
324 unsigned int bytes_per_channel
;
325 int line_size
; /* size of the line (4Y+U+V) */
327 const unsigned char *ptable0004
, *ptable8004
;
330 unsigned int temp_colors
[16];
333 const unsigned char *stream
;
334 unsigned char *dest_y
, *dest_u
=NULL
, *dest_v
=NULL
;
335 unsigned int offset_to_plane_u
, offset_to_plane_v
;
341 nbits_in_reservoir
= 0;
342 stream
= rawyuv
+1; /* The first byte of the stream is skipped */
345 get_nbits(reservoir
,nbits_in_reservoir
,stream
,4,first_4_bits
);
347 line_size
= pixels_per_line
*3;
349 for (passes
=0;passes
<2;passes
++)
353 bytes_per_channel
= pixels_per_line
;
359 /* Format planar: All Y, then all U, then all V */
360 bytes_per_channel
= pixels_per_line
/2;
367 offset_to_plane_u
= bytes_per_channel
*2;
368 offset_to_plane_v
= bytes_per_channel
*3;
370 printf("bytes_per_channel = %d\n",bytes_per_channel);
371 printf("offset_to_plane_u = %d\n",offset_to_plane_u);
372 printf("offset_to_plane_v = %d\n",offset_to_plane_v);
377 unsigned int gray_index
;
379 fill_nbits(reservoir
,nbits_in_reservoir
,stream
,16);
380 gray_index
= reservoir
& pdev
->zzmask
;
381 reservoir
>>= pdev
->zz
;
382 nbits_in_reservoir
-= pdev
->zz
;
384 fill_nbits(reservoir
,nbits_in_reservoir
,stream
,2);
386 if ( (reservoir
& 3) == 0)
389 nbits_in_reservoir
-=2;
391 temp_colors
[i
] = pdev
->table_dc00
[gray_index
];
396 unsigned int channel_v
, offset1
;
398 /* swap bit 0 and 2 of offset_OR */
399 channel_v
= ((reservoir
& 1) << 2) | (reservoir
& 2) | ((reservoir
& 4)>>2);
401 nbits_in_reservoir
-=3;
404 temp_colors
[i
] = pdev
->table_d800
[gray_index
];
406 ptable0004
= pdev
->table_0004
+ (passes
*16384) + (first_4_bits
*1024) + (channel_v
*128);
407 ptable8004
= pdev
->table_8004
+ (passes
*4096) + (first_4_bits
*256) + (channel_v
*32);
412 unsigned int index_in_table_ops
, op
, rows
=0;
413 fill_nbits(reservoir
,nbits_in_reservoir
,stream
,16);
415 /* mode is 0,1 or 2 */
416 index_in_table_ops
= (reservoir
&0x3F);
417 op
= table_ops
[ index_in_table_ops
*4 ];
421 nbits_in_reservoir
-= 2;
422 break; /* exit the while(1) */
428 offset1
= (offset1
+ table_ops
[index_in_table_ops
*4+2]) & 0x0F;
429 shift
= table_ops
[ index_in_table_ops
*4+1 ];
431 nbits_in_reservoir
-= shift
;
432 rows
= ptable0004
[ offset1
+ table_ops
[index_in_table_ops
*4+3] ];
436 /* 10bits [ xxxx xxxx yyyy 000 ]
437 * yyy => offset in the table8004
438 * xxx => offset in the tabled004
440 unsigned int mask
, shift
;
441 unsigned int col1
, row1
, total_bits
;
443 offset1
= (offset1
+ ((reservoir
>>3)&0x0F)+1) & 0x0F;
445 col1
= (reservoir
>>7) & 0xFF;
446 row1
= ptable8004
[ offset1
*2 ];
449 mask
= pdev
->table_d004
[ (row1
<<8) + col1
];
450 shift
= ptable8004
[ offset1
*2 + 1];
451 rows
= ((mask
<< shift
) + 0x80) & 0xFF;
453 total_bits
= row1
+ 8;
454 reservoir
>>= total_bits
;
455 nbits_in_reservoir
-= total_bits
;
458 const unsigned int *table_a004
= pdev
->table_a004
+ rows
*12;
459 unsigned int *poffset
= MulIdx
+ offset1
*16; /* 64/4 (int) */
462 temp_colors
[i
] += table_a004
[ *poffset
];
468 #define USE_SIGNED_INT_FOR_COLOR
469 #ifdef USE_SIGNED_INT_FOR_COLOR
470 # define CLAMP(x) ((x)>255?255:((x)<0?0:x))
472 # define CLAMP(x) ((x)>255?255:x)
477 #ifdef USE_SIGNED_INT_FOR_COLOR
478 const int *c
= temp_colors
;
480 const unsigned int *c
= temp_colors
;
485 for (i
=0;i
<4;i
++,c
++)
486 *d
++ = CLAMP((*c
) >> pdev
->yy
);
488 d
= dest_y
+ bytes_per_channel
;
489 for (i
=0;i
<4;i
++,c
++)
490 *d
++ = CLAMP((*c
) >> pdev
->yy
);
492 d
= dest_y
+ offset_to_plane_u
;
493 for (i
=0;i
<4;i
++,c
++)
494 *d
++ = CLAMP((*c
) >> pdev
->yy
);
496 d
= dest_y
+ offset_to_plane_v
;
497 for (i
=0;i
<4;i
++,c
++)
498 *d
++ = CLAMP((*c
) >> pdev
->yy
);
502 else if (passes
== 1)
504 #ifdef USE_SIGNED_INT_FOR_COLOR
505 int *c1
= temp_colors
;
506 int *c2
= temp_colors
+4;
508 unsigned int *c1
= temp_colors
;
509 unsigned int *c2
= temp_colors
+4;
514 for (i
=0;i
<4;i
++,c1
++,c2
++)
516 *d
++ = CLAMP((*c1
) >> pdev
->yy
);
517 *d
++ = CLAMP((*c2
) >> pdev
->yy
);
520 //c2 = temp_colors+8;
521 d
= dest_y
+ bytes_per_channel
;
522 for (i
=0;i
<4;i
++,c1
++,c2
++)
524 *d
++ = CLAMP((*c1
) >> pdev
->yy
);
525 *d
++ = CLAMP((*c2
) >> pdev
->yy
);
528 if (even_line
) /* Each line, swap u/v */
542 } /* end of while (nblocks-->0) */
544 } /* end of for (passes=0;passes<2;passes++) */
551 * image: size of the image wanted
552 * view : size of the image returned by the camera
553 * offset: (x,y) to displayer image in the view
557 * flags: PWCX_FLAG_PLANAR
558 * pdev: private buffer
562 void pwc_dec23_decompress(const struct pwc_coord
*image
,
563 const struct pwc_coord
*view
,
564 const struct pwc_coord
*offset
,
571 const struct pwc_dec23_private
*pdev
= data
;
572 unsigned char *pout
, *pout_planar_y
=NULL
, *pout_planar_u
=NULL
, *pout_planar_v
=NULL
;
573 int i
,n
,stride
,pixel_size
;
576 if (flags
& PWCX_FLAG_BAYER
)
578 pout
= dst
+ (view
->x
* offset
->y
) + offset
->x
;
579 pixel_size
= view
->x
* 4;
583 n
= view
->x
* view
->y
;
585 /* offset in Y plane */
586 stride
= view
->x
* offset
->y
;
587 pout_planar_y
= dst
+ stride
+ offset
->x
;
589 /* offsets in U/V planes */
590 stride
= (view
->x
* offset
->y
)/4 + offset
->x
/2;
591 pout_planar_u
= dst
+ n
+ + stride
;
592 pout_planar_v
= dst
+ n
+ n
/4 + stride
;
594 pixel_size
= view
->x
* 4;
598 for (i
=0;i
<image
->y
;i
+=4)
600 if (flags
& PWCX_FLAG_BAYER
)
603 //DecompressBandBayer(pdev,src,pout,image.x,view->x,flags);
609 DecompressBand23(pdev
,src
,pout_planar_y
,pout_planar_u
,pout_planar_v
,image
->x
,view
->x
,flags
);
611 pout_planar_y
+= pixel_size
;
612 pout_planar_u
+= view
->x
;
613 pout_planar_v
+= view
->x
;
618 void pwc_dec23_exit(void)