18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Linux driver for Philips webcam 38c2ecf20Sopenharmony_ci Decompression frontend. 48c2ecf20Sopenharmony_ci (C) 1999-2003 Nemosoft Unv. 58c2ecf20Sopenharmony_ci (C) 2004-2006 Luc Saillard (luc@saillard.org) 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx 88c2ecf20Sopenharmony_ci driver and thus may have bugs that are not present in the original version. 98c2ecf20Sopenharmony_ci Please send bug reports and support requests to <luc@saillard.org>. 108c2ecf20Sopenharmony_ci The decompression routines have been implemented by reverse-engineering the 118c2ecf20Sopenharmony_ci Nemosoft binary pwcx module. Caveat emptor. 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci vim: set ts=8: 158c2ecf20Sopenharmony_ci*/ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/current.h> 188c2ecf20Sopenharmony_ci#include <asm/types.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "pwc.h" 218c2ecf20Sopenharmony_ci#include "pwc-dec1.h" 228c2ecf20Sopenharmony_ci#include "pwc-dec23.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciint pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci int n, line, col; 278c2ecf20Sopenharmony_ci void *yuv, *image; 288c2ecf20Sopenharmony_ci u16 *src; 298c2ecf20Sopenharmony_ci u16 *dsty, *dstu, *dstv; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci image = vb2_plane_vaddr(&fbuf->vb.vb2_buf, 0); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* Raw format; that's easy... */ 368c2ecf20Sopenharmony_ci if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) 378c2ecf20Sopenharmony_ci { 388c2ecf20Sopenharmony_ci struct pwc_raw_frame *raw_frame = image; 398c2ecf20Sopenharmony_ci raw_frame->type = cpu_to_le16(pdev->type); 408c2ecf20Sopenharmony_ci raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength); 418c2ecf20Sopenharmony_ci /* cmd_buf is always 4 bytes, but sometimes, only the 428c2ecf20Sopenharmony_ci * first 3 bytes is filled (Nala case). We can 438c2ecf20Sopenharmony_ci * determine this using the type of the webcam */ 448c2ecf20Sopenharmony_ci memcpy(raw_frame->cmd, pdev->cmd_buf, 4); 458c2ecf20Sopenharmony_ci memcpy(raw_frame+1, yuv, pdev->frame_size); 468c2ecf20Sopenharmony_ci vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, 478c2ecf20Sopenharmony_ci pdev->frame_size + sizeof(struct pwc_raw_frame)); 488c2ecf20Sopenharmony_ci return 0; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, 528c2ecf20Sopenharmony_ci pdev->width * pdev->height * 3 / 2); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (pdev->vbandlength == 0) { 558c2ecf20Sopenharmony_ci /* Uncompressed mode. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * We do some byte shuffling here to go from the 588c2ecf20Sopenharmony_ci * native format to YUV420P. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci src = (u16 *)yuv; 618c2ecf20Sopenharmony_ci n = pdev->width * pdev->height; 628c2ecf20Sopenharmony_ci dsty = (u16 *)(image); 638c2ecf20Sopenharmony_ci dstu = (u16 *)(image + n); 648c2ecf20Sopenharmony_ci dstv = (u16 *)(image + n + n / 4); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci for (line = 0; line < pdev->height; line++) { 678c2ecf20Sopenharmony_ci for (col = 0; col < pdev->width; col += 4) { 688c2ecf20Sopenharmony_ci *dsty++ = *src++; 698c2ecf20Sopenharmony_ci *dsty++ = *src++; 708c2ecf20Sopenharmony_ci if (line & 1) 718c2ecf20Sopenharmony_ci *dstv++ = *src++; 728c2ecf20Sopenharmony_ci else 738c2ecf20Sopenharmony_ci *dstu++ = *src++; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * Compressed; 828c2ecf20Sopenharmony_ci * the decompressor routines will write the data in planar format 838c2ecf20Sopenharmony_ci * immediately. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci if (DEVICE_USE_CODEC1(pdev->type)) { 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* TODO & FIXME */ 888c2ecf20Sopenharmony_ci PWC_ERROR("This chipset is not supported for now\n"); 898c2ecf20Sopenharmony_ci return -ENXIO; /* No such device or address: missing decompressor */ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci } else { 928c2ecf20Sopenharmony_ci pwc_dec23_decompress(pdev, yuv, image); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 96