📄 qcamvc.c
字号:
/* * * Connectix USB QuickCam VC Video Camera driver * * (C) Copyright 2001 De Marchi Daniele * (C) Copyright 2004 Renzo Davoli (Integer version) * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * Jan 2001 This driver develop started on the linux * kernel 2.4.0. * *//*#define BWONLY*/#include "qcamvc.h"#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#include <linux/proc_fs.h>#include <linux/vmalloc.h>#include <linux/wrapper.h>#ifdef MODULEMODULE_AUTHOR("Daniele De Marchi<demarchidaniele@libero.it> + Renzo Davoli <renzo@cs.unibo.it>");MODULE_DESCRIPTION("V4L-driver for QuickCam VC cameras");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("video");#endif#ifdef CONFIG_VIDEO_QCAMVC_PPextern int qcamvc_pp_init(void);#endif#ifdef CONFIG_VIDEO_QCAMVC_USBextern int qcamvc_usb_init(void);#endifstatic long qcamvc_vread(struct video_device *dev, char *buf, unsigned long count, int noblock);static long qcamvc_vwrite(struct video_device *dev, const char *buf, unsigned long count, int noblock);static int qcamvc_vioctl(struct video_device *dev, unsigned int cmd, void *arg);static int qcamvc_vopen(struct video_device *dev, int flags);static void qcamvc_vclose(struct video_device *dev);static int qcamvc_init_done(struct video_device *dev);#ifdef USE_MMAPstatic int qcamvc_vmmap(struct video_device *dev, const char *adr, unsigned long size);#endifstatic struct video_device qcamvc_template = { name: "QuickCam VC", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_QCAM_C, open: qcamvc_vopen, close: qcamvc_vclose, read: qcamvc_vread, write: qcamvc_vwrite, ioctl: qcamvc_vioctl, initialize: qcamvc_init_done,#ifdef USE_MMAP mmap: qcamvc_vmmap,#endif};#ifdef FLOAT_IN_KERNEL_NO/*****************************************************************************//* *//* QuickCam Video CODEC *//* *//*****************************************************************************/static void hue_reg(struct qcamvc *qcamvc){ float a,b; int cnt; if (qcamvc->hue_calc == 1) return; a = (qcamvc->blue_hue * 1.12) / 128; b = (qcamvc->red_hue * 1.39999999999) / 128; for (cnt = 0 ; cnt < 0xff ; cnt++) { qcamvc->table_a[cnt] = (float) cnt * b; qcamvc->table_b[cnt] = (float) cnt * a; if(qcamvc->table_a[cnt] > 0xff) qcamvc->table_a[cnt] = 0xff; if(qcamvc->table_a[cnt] < 0 ) qcamvc->table_a[cnt] = 0; if(qcamvc->table_b[cnt] > 0xff) qcamvc->table_b[cnt] = 0xff; if(qcamvc->table_b[cnt] < 0 ) qcamvc->table_b[cnt] = 0; } a = qcamvc->santrast / 100; qcamvc->VAR_A = a * 1.731999999999999; qcamvc->VAR_B = a * 0.336; qcamvc->VAR_C = a * 0.697999999999999; qcamvc->VAR_D = a * 1.370999999999999; qcamvc->hue_calc = 1;}static void get_pixel(struct qcamvc *qcamvc, float pix_a, float pix_b, unsigned char pix_c, \ unsigned char pix_d, float pix_e, \ unsigned char *pred, unsigned char *pgreen, unsigned char *pblue){ float a,b; float blue,green,red; a = pix_b - qcamvc->table_a[pix_c]; b = qcamvc->table_b[pix_d] - pix_e; if(pix_a >= 0) {if(pix_a > 0xff) {pix_a = 0xff;}} else {pix_a = 0;} if(a <= 112) {if(a < -112) {a = -112;}} else {a = 112;} if(b <= 112) {if(b < -112) {b = -112;}} else {b = 112;} blue = ( b * qcamvc->VAR_A ) + pix_a; green = ( a * qcamvc->VAR_C ) - (( b * qcamvc->VAR_B) - pix_a ); red = ( a * qcamvc->VAR_D ) + pix_a; if(red >= 0) {if(red > 0xff) red = 0xff;} else {red = 0;} if(green >= 0) {if(green > 0xff) green = 0xff;} else {green = 0;} if(blue >= 0) {if(blue > 0xff) blue = 0xff;} else {blue = 0;} *pred = (unsigned char) red; *pgreen = (unsigned char) green; *pblue = (unsigned char) blue; }#else#ifdef BWONLY/*****************************************************************************//* QuickCam Video CODEC BW ONLY (no float) *//*****************************************************************************/static void hue_reg(struct qcamvc *qcamvc){ if (qcamvc->hue_calc == 1) return; qcamvc->hue_calc = 1;}static void get_pixel(struct qcamvc *qcamvc, int pix_a, int pix_b, unsigned char pix_c, \ unsigned char pix_d, int pix_e, \ unsigned char *pred, unsigned char *pgreen, unsigned char *pblue){ int blue,green,red; blue = pix_a; green = pix_a; red = pix_a; if(red >= 0) {if(red > 0xff) red = 0xff;} else {red = 0;} if(green >= 0) {if(green > 0xff) green = 0xff;} else {green = 0;} if(blue >= 0) {if(blue > 0xff) blue = 0xff;} else {blue = 0;} *pred = (unsigned char) red; *pgreen = (unsigned char) green; *pblue = (unsigned char) blue;}#else/*****************************************************************************//* QuickCam Video CODEC test color no float *//*****************************************************************************/#define coffset 20#define coffact (1<<coffset)#define ff20 (0xff<<coffset)static void hue_reg(struct qcamvc *qcamvc){ int a,b; int cnt; //printk("hue_reg %d %d %d\n", qcamvc->blue_hue, qcamvc->red_hue, qcamvc->santrast); if (qcamvc->hue_calc == 1) return; a = qcamvc->red_hue * (int)((1.39999999999 * (coffact / 128))); b = qcamvc->blue_hue * (int)((1.12 * (coffact / 128))); //printk("hue_reg ab %d %d\n",a,b); for (cnt = 0 ; cnt < 0xff ; cnt++) { qcamvc->table_a[cnt] = cnt * a; qcamvc->table_b[cnt] = cnt * b; if(qcamvc->table_a[cnt] > ff20) qcamvc->table_a[cnt] = ff20; if(qcamvc->table_a[cnt] < 0 ) qcamvc->table_a[cnt] = 0; if(qcamvc->table_b[cnt] > ff20) qcamvc->table_b[cnt] = ff20; if(qcamvc->table_b[cnt] < 0 ) qcamvc->table_b[cnt] = 0; //if (cnt==100) //printk("tatb %d %d\n",qcamvc->table_a[cnt],qcamvc->table_b[cnt]); } //a = qcamvc->santrast / 100; a = qcamvc->santrast; qcamvc->VAR_A = a * (int)((1.731999999999999 * coffact) / 100); qcamvc->VAR_B = a * (int)((0.336 * coffact) / 100); qcamvc->VAR_C = a * (int)((0.697999999999999 * coffact) / 100); qcamvc->VAR_D = a * (int)((1.370999999999999 * coffact) / 100); //printk("hue_reg ABCD %d %d %d %d\n", //qcamvc->VAR_A, //qcamvc->VAR_B, //qcamvc->VAR_C, //qcamvc->VAR_D); qcamvc->hue_calc = 1;}static void get_pixel(struct qcamvc *qcamvc, int pix_a, int pix_b, unsigned char pix_c, \ unsigned char pix_d, int pix_e, \ unsigned char *pred, unsigned char *pgreen, unsigned char *pblue){ int a,b; int blue,green,red; //static int counter; //counter++; //if((counter & 0xfffff) == 0) //printk("gp %d %d %d %d %d\n",pix_a,pix_b,pix_c,pix_d,pix_e); //a = pix_b * coffact - qcamvc->table_a[pix_c]; //b = qcamvc->table_b[pix_d] - pix_e * coffact; a = qcamvc->table_a[pix_c] - pix_b * coffact; b = pix_e * coffact - qcamvc->table_b[pix_d]; if(pix_a >= 0) {if(pix_a > 0xff) {pix_a = 0xff;}} else {pix_a = 0;} if(a <= 112<<coffset) {if(a < -112<<coffset) {a = -112<<coffset;}} else {a = 112<<coffset;} if(b <= 112<<coffset) {if(b < -112<<coffset) {b = -112<<coffset;}} else {b = 112<<coffset;} //if((counter & 0xfffff) == 0) //printk("gp pixab %d %d / %d %d\n",qcamvc->table_a[pix_c], qcamvc->table_b[pix_d],a,b);#define hi(x) ((x) >> 16)#define lo(x) ((x)&0xffff)#define mulcoff(x,y) (( (hi(x)*hi(y)) << (32-coffset))+ \ (( (hi(x)*lo(y)) + (lo(x)*hi(y)) )>>(coffset-16))+\ ( (lo(x)*lo(y)) >> coffset) ) //blue = ( b * qcamvc->VAR_A ) + pix_a; //green = ( a * qcamvc->VAR_C ) - (( b * qcamvc->VAR_B) - pix_a ); //red = ( a * qcamvc->VAR_D ) + pix_a; //blue = (mulcoff(b,qcamvc->VAR_A) >> coffset) + pix_a; //green =((mulcoff(a,qcamvc->VAR_C) - mulcoff(b,qcamvc->VAR_B)) >> coffset) + pix_a ; //red = (mulcoff(a,qcamvc->VAR_D) >> coffset) + pix_a; red=green=blue= pix_a << coffset; blue += mulcoff(b,qcamvc->VAR_A); green += mulcoff(a,qcamvc->VAR_C) - mulcoff(b,qcamvc->VAR_B); red += mulcoff(a,qcamvc->VAR_D); blue>>=coffset; green>>=coffset; red>>=coffset; if(red >= 0) {if(red > 0xff) red = 0xff;} else {red = 0;} if(green >= 0) {if(green > 0xff) green = 0xff;} else {green = 0;} if(blue >= 0) {if(blue > 0xff) blue = 0xff;} else {blue = 0;} *pred = (unsigned char) red; *pgreen = (unsigned char) green; *pblue = (unsigned char) blue; //if((counter & 0xfffff) == 0) //printk("RGB %d %d %d\n",red,green,blue);}#endif#endifstatic void codec(struct qcamvc *qcamvc, unsigned char *inbuf, unsigned char *outbuf){ int width=qcamvc->width; int height=qcamvc->height; unsigned char red=0, green=0, blue=0; int x,y; unsigned char pix1, pix2, pix3, pix4; unsigned char *pointer1, *pointer2; unsigned char *table = (unsigned char *) kmalloc(width * height, GFP_KERNEL); unsigned char *pointer_last_line =(unsigned char *) kmalloc(width, GFP_KERNEL); pointer1 = inbuf; pointer2 = table; for (y = 0 ; y < height ; y ++ ){ for (x = width - 1 ; x >= 0 ; x--){ *(pointer2 + x) = *(pointer1); pointer1 ++; } pointer2 = pointer2 + width; } pointer1 = inbuf; pointer2 = (outbuf + qcamvc->width * qcamvc->height * 3) - 1; if (qcamvc->hue_calc == 0 ) hue_reg(qcamvc); memcpy( pointer_last_line, pointer1, width); for(y = 0 ; y < height ; y++) { if (current->need_resched) schedule(); if((y & 1) == 0) { for (x = 0 ; x < width ; x++){ if((x & 1) != 0) { pix1 = (*(width + pointer1) + *(x + pointer_last_line)) / 2; pix2 = (*(width + pointer1 + 1) + *(x + pointer_last_line)) / 2 ; pix3 = *pointer1; pix4 = *(pointer1 + 1); } else { pix1 = (*(width + pointer1 + 1) + *(x + 1 + pointer_last_line)) / 2; pix2 = (*(width + pointer1) + *(x + pointer_last_line)) / 2; pix3 = *(pointer1 + 1); pix4 = *pointer1; } get_pixel(qcamvc, (pix3 + pix4) / 2, pix4, pix3, pix1, pix2, &blue, &green, &red); (unsigned char)*(pointer2) = blue; (unsigned char)*(pointer2 - 1) = green; (unsigned char)*(pointer2 - 2) = red; pointer2-=3; pointer1++; } } else { for (x = 0 ; x < width ; x++){ if((x & 1) != 0) { pix1 = (*(width + pointer1) + *(x + pointer_last_line)) / 2; pix2 = (*(width + pointer1 + 1) + *(x + 1 + pointer_last_line)) / 2; pix3 = *pointer1; pix4 = *(pointer1 + 1); } else { pix1 = (*(width + pointer1 + 1) + *(x + 1 + pointer_last_line)) / 2; pix2 = (*(width + pointer1) + *(x + pointer_last_line)) / 2; pix3 = *(pointer1 + 1); pix4 = *pointer1; } get_pixel(qcamvc, (pix3 + pix4) / 2, pix2, pix1, pix3, pix4, &blue, &green, &red); (unsigned char)*(pointer2) = blue; (unsigned char)*(pointer2 - 1) = green; (unsigned char)*(pointer2 - 2) = red; pointer2-=3; pointer1++; } } memcpy(pointer_last_line, pointer1 - width, width); } kfree(table); kfree(pointer_last_line);}static void qcamvc_set_topmost_row(struct qcamvc *qcamvc, unsigned char val){ qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_TOPMOST_ROW, &val, sizeof(val));}static void qcamvc_set_bottommost_row(struct qcamvc *qcamvc, unsigned char val){ qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_BOTTOMMOST_ROW, &val, sizeof(val));}static void qcamvc_set_leftmost_column(struct qcamvc *qcamvc, unsigned char val){ qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_LEFTMOST_COLUMN, &val, sizeof(val));}static void qcamvc_set_rightmost_column(struct qcamvc *qcamvc, unsigned char val){ qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_RIGHTMOST_COLUMN, &val, sizeof(val));}static void qcamvc_set_exposure(struct qcamvc *qcamvc, unsigned char val){ unsigned char buffer[2]; GET_VALUES(buffer,val); qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_EXPOSURE, buffer, sizeof(buffer)); if(qcamvc->streaming) qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_GET_FRAME, NULL, 0);}static void qcamvc_set_brightness(struct qcamvc *qcamvc, unsigned char val){ short i,j; unsigned char buffer[21]={ 0x58, 0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x58, 0xd8, 0x5c}; for(i=1, j=18 ; i<=0x80 ; i*=2 , j-=2) { if( val & i) { buffer[j] = buffer[j] | 1; buffer[j+1] = buffer[j+1] | 1;} } qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_BRIGHTNESS, buffer, sizeof(buffer)); if(qcamvc->streaming) qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_GET_FRAME, NULL, 0);}static int bpc6_init(struct qcamvc *qcamvc){ int ret=0; long i,q; unsigned char buffer[0x40]; unsigned char *bigbuffer; FIRST_ROW; LAST_ROW; FIRST_COL; LAST_COL; MUL_FACTOR; bigbuffer=kmalloc(BIGBUFFER_SIZE , GFP_KERNEL); if (bigbuffer==NULL) { printk("QuickCam VC: Init bigbuffer kmalloc error.\n"); return -1; } for(i=0; i<BIGBUFFER_SIZE ; i+=2) { q=i; *(bigbuffer + i ) = (unsigned char )(q >> 11); *(bigbuffer + i + 1) = (unsigned char) 0xc0; } buffer[0]=0x78; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_MISC, buffer, 1); buffer[0]=0x58; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); buffer[0]=0x18; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); qcamvc_set_topmost_row (qcamvc, 0x0e); qcamvc_set_leftmost_column (qcamvc, 0x0f); qcamvc_set_bottommost_row (qcamvc, 0x86); qcamvc_set_rightmost_column(qcamvc, 0xaf); qcamvc_set_brightness(qcamvc, qcamvc->brightness); buffer[0]=0x7f;buffer[1]=0x81; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x02, buffer, 2); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_MISC, buffer, 1); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0e, buffer, 1); qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0d, bigbuffer, BIGBUFFER_SIZE); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0e, buffer, 1); buffer[0]=0x01; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0e, buffer, 1); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_MISC, buffer, 1); buffer[0]=0x78; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_MISC, buffer, 1); buffer[0]=0x58; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); qcamvc_set_brightness(qcamvc, qcamvc->brightness); qcamvc_set_exposure(qcamvc, qcamvc->exposure); buffer[0]=0x11; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0a, buffer, 1); buffer[0]=0x11; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0a, buffer, 1); qcamvc_set_topmost_row (qcamvc, firstrow[qcamvc->res]); qcamvc_set_leftmost_column (qcamvc, firstcolumn[qcamvc->res]); qcamvc_set_bottommost_row (qcamvc, lastrow[qcamvc->res]); qcamvc_set_rightmost_column(qcamvc, lastcolumn[qcamvc->res]); buffer[0] = mulfactor[qcamvc->res]; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0a, buffer, 1); kfree(bigbuffer); return ret;}static int bpc8_init(struct qcamvc *qcamvc){ FIRST_ROW; LAST_ROW; FIRST_COL; LAST_COL; MUL_FACTOR; int q,i; unsigned char *bigbuffer; unsigned char buffer[0x40]; unsigned char a=0xff; bigbuffer = kmalloc(BIGBUFFER_SIZE , GFP_KERNEL); if (bigbuffer==NULL) { printk("QuickCam VC: Init bigbuffer kmalloc error.\n"); return -1; } for(i=0; i<BIGBUFFER_SIZE ; i+=2) { q=i; *(bigbuffer + i) = 0; *(bigbuffer + i +1) = (unsigned char )(q >> 11); } buffer[0]=0x78; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_MISC, buffer, 1); buffer[0]=0x58; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); buffer[0]=0x18; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); //#ifdef CAM_DEBUG qcamvc->ops->qcamvc_get_reg(qcamvc->lowlevel_data, 0x8f, buffer, sizeof(buffer)); printk("QuickCam VC:8bpp init bpc8 0x8f, len=%d, ",sizeof(buffer)); for (i=0 ; i < sizeof(buffer) ; i++) printk (" 0x%02x ", buffer[i]); printk("\n"); qcamvc->ops->qcamvc_get_reg(qcamvc->lowlevel_data, 0x80, buffer, sizeof(buffer)); printk("QuickCam VC:Set init bcp8 0x80, len=%d, ",sizeof(buffer)); for (i=0 ; i < sizeof(buffer) ; i++) printk (" 0x%02x ", buffer[i]); printk("\n"); //#endif qcamvc_set_topmost_row (qcamvc, 0x0e); qcamvc_set_leftmost_column (qcamvc, 0x0f); qcamvc_set_bottommost_row (qcamvc, 0x86); qcamvc_set_rightmost_column(qcamvc, 0xaf); qcamvc_set_brightness(qcamvc, 0x80); buffer[0]=0xaf;buffer[1]=0xaf; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x02, buffer, 2); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_MISC, buffer, 1); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0e, buffer, 1); qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0d, bigbuffer, BIGBUFFER_SIZE); printk("QuickCam VC:8bpc bigbuffer write, len=%d, ",sizeof(buffer)); for (i=1 ; i < BIGBUFFER_SIZE ; i+=2) { if (a != *(bigbuffer + i)) { printk (" 0x%02x ", *(bigbuffer + i)); a=*(bigbuffer + i);} } printk("\n"); buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0e, buffer, 1); qcamvc->ops->qcamvc_get_reg(qcamvc->lowlevel_data, 0x8d, bigbuffer, BIGBUFFER_SIZE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -