/* * qce-ga, linux V4L driver for the Quickcam Express and Dexxa Quickcam * * hdcs.c - HDCS Sensor Implementation * * 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 "quickcam.h" #include "hdcs.h" #include "helper.h" static unsigned char control; static unsigned char config; /* start grabbing */ static int hdcs_start(struct usb_device * dev, struct sensorctrl *sensor_ctrl) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); usb_quickcam_i2c_add(&i2cbuff,control,0x04); return(usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR)); } /* stop grabbing */ static int hdcs_stop(struct usb_device * dev, struct sensorctrl *sensor_ctrl) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); usb_quickcam_i2c_add(&i2cbuff,control,0x00); if (usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR) < 0) return (-2); return(0); } /* sensor window to read out */ static int hdcs_set_size(struct usb_device *dev, int mode) { if(mode != 0 && mode != 1) goto error; // 1: Y-full, 2: y-half if (usb_quickcam_set1(dev, STV_Y_CTRL, 1) < 0) goto error; // 06/0a : Half/Full if (usb_quickcam_set1(dev, STV_X_CTRL, 0x0a) < 0) goto error; return(0); error: return(-1); } /* * initialise parameters - copy + paste from Georg Acher's user module * for hdcs sensor. */ static int hdcs_init(struct usb_device *dev, int mode, int *rgain, int *bgain, int *ggain, struct sensorctrl *sensor_ctrl) { struct quickcam_i2c i2cbuff; short isosize; if (*rgain<=0 || *rgain>255) *rgain=RGAIN_DEF; if (*bgain<=0 || *bgain>255) *bgain=BGAIN_DEF; if (*ggain<=0 || *ggain>255) *ggain=GGAIN_DEF; sensor_ctrl->mode=mode; if (mode) { sensor_ctrl->mode=2; // quater. sensor_ctrl->width = 176; sensor_ctrl->height = 144; } else { sensor_ctrl->width = 352; sensor_ctrl->height = 288; } if (usb_quickcam_set1(dev, STV_REG23, 0) < 0) goto error; /* set the STV0602AA in STV0600 emulation mode */ if (dev->descriptor.idProduct==0x0870) if (usb_quickcam_set1(dev, 0x1446, 1) < 0) goto error; /* * reset the Image Sensor. (keeping it to 1 is a problem). */ usb_quickcam_i2c_new(&i2cbuff); usb_quickcam_i2c_add(&i2cbuff,control,1); if (usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR) < 0) { printk(KERN_ERR "usb_quickcam_i2c_send HDCS_CONTROL(0x01) failed\n"); goto error; } usb_quickcam_i2c_add(&i2cbuff,control,0); if (usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR) < 0) { printk(KERN_ERR "usb_quickcam_i2c_send HDCS_CONTROL(0x00) failed\n"); goto error; } // clear status. usb_quickcam_i2c_add(&i2cbuff,HDCS_STATUS, 0x00); // clear interrupt mask. usb_quickcam_i2c_add(&i2cbuff,HDCS_IMASK, 0x00); if (usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR) < 0) goto error; /* was the place where Georg sets gains */ if (usb_quickcam_set1(dev, STV_REG00, 0x1d) < 0) goto error; if (usb_quickcam_set1(dev, STV_REG04, 0x07) < 0) goto error; if (usb_quickcam_set1(dev, STV_REG03, 0x95) < 0) goto error; if (usb_quickcam_set1(dev, STV_REG23, 0) < 0) goto error; // larger -> slower if (usb_quickcam_set1(dev, STV_SCAN_RATE, 0x20) <0) goto error; // ISO-Size, 0x34f = 847 .. 0x284 = 644 if (dev->descriptor.idProduct==0x0870) isosize = 644; else isosize = 847; if (usb_quickcam_set2(dev, STV_ISO_SIZE, isosize) < 0) { printk(KERN_ERR "usb_quickcam_set2 STV_ISO_SIZE(847) failed\n"); goto error; } // Set Size if (hdcs_set_size(dev, mode) < 0) goto error; usb_quickcam_i2c_add(&i2cbuff,HDCS_STARTY, 2); usb_quickcam_i2c_add(&i2cbuff,HDCS_STARTX, 4); usb_quickcam_i2c_add(&i2cbuff,HDCS_STOPY, 0x4e); usb_quickcam_i2c_add(&i2cbuff,HDCS_STOPX, 0x5b); // 0x7-0x50 if (dev->descriptor.idProduct==0x0870) usb_quickcam_i2c_add(&i2cbuff,HDCS_INTEGRATE, 0x7e); else usb_quickcam_i2c_add(&i2cbuff,HDCS_INTEGRATE, 0x09); usb_quickcam_i2c_add(&i2cbuff,control, 0); usb_quickcam_i2c_add(&i2cbuff,HDCS_REG2A, 0x0); usb_quickcam_i2c_add(&i2cbuff,HDCS_REG2C, 0x0); if (usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR) < 0) goto error; if (usb_quickcam_set1(dev, STV_REG01, 0xb5) < 0) goto error; if (usb_quickcam_set1(dev, STV_REG02, 0xa8) < 0) goto error; usb_quickcam_i2c_add(&i2cbuff,HDCS_REG06, 0x63); usb_quickcam_i2c_add(&i2cbuff,HDCS_REG08, 0x00); usb_quickcam_i2c_add(&i2cbuff,HDCS_REG0A, 0x20); usb_quickcam_i2c_add(&i2cbuff,HDCS_REG0C, 0x12); /* * CONFIG: 0x08 Continous Frame Capture. * 0x04 Stop when Frame Complete. */ usb_quickcam_i2c_add(&i2cbuff,config, (mode?0x38:0x08)); usb_quickcam_i2c_add(&i2cbuff,HDCS_ADC_BITS, 10); if (usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR) < 0) goto error; return(0); error: return(-1); } /* set_shutter */ static int hdcs_set_shutter(struct usb_device *dev, int sval, int xval) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); usb_quickcam_i2c_add(&i2cbuff,control, 0); usb_quickcam_i2c_add(&i2cbuff,HDCS_SHUTTERL, sval&255); usb_quickcam_i2c_add(&i2cbuff,HDCS_SHUTTERH, sval>>8); usb_quickcam_i2c_add(&i2cbuff,HDCS_REG2A, xval&255); usb_quickcam_i2c_add(&i2cbuff,HDCS_REG2C, xval>>8); usb_quickcam_i2c_add(&i2cbuff,control, 4); return(usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR)); } /* * set gains * According to spec's 128 multiplies by 2 the values. */ static int hdcs_set_gains(struct usb_device *dev, int rgain, int bgain, int ggain) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); usb_quickcam_i2c_add(&i2cbuff,HDCS_GAIN_GREEN1, 128+qcmax(0,qcmin(127,ggain/2))); usb_quickcam_i2c_add(&i2cbuff,HDCS_GAIN_RED, 128+qcmax(0,qcmin(127,rgain/2))); usb_quickcam_i2c_add(&i2cbuff,HDCS_GAIN_BLUE, 128+qcmax(0,qcmin(127,bgain/2))); usb_quickcam_i2c_add(&i2cbuff,HDCS_GAIN_GREEN2, 128+qcmax(0,qcmin(127,ggain/2))); return(usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR)); } /* * Sets the size (scaling) of the capture window. * If subsample could return the image size we use subsample. */ static int hdcs_set_window(struct usb_device *dev, int x, int y, int width, int height, struct sensorctrl *sensor_ctrl) { struct quickcam_i2c i2cbuff; usb_quickcam_i2c_new(&i2cbuff); if (!sensor_ctrl->mode) { sensor_ctrl->width=width; sensor_ctrl->height=height; if (width<=176 && height<=144) { width =width*2; height=height*2; usb_quickcam_i2c_add(&i2cbuff,config, 0x38); } else usb_quickcam_i2c_add(&i2cbuff,config, 0x08); } else { sensor_ctrl->width=width/2; sensor_ctrl->height=height/2; } usb_quickcam_i2c_add(&i2cbuff,HDCS_STARTY,2+y); usb_quickcam_i2c_add(&i2cbuff,HDCS_STARTX,4+x); usb_quickcam_i2c_add(&i2cbuff,HDCS_STOPY,(height+4)/4); // 4 usb_quickcam_i2c_add(&i2cbuff,HDCS_STOPX,(width+12)/4); // 12 return(usb_quickcam_i2c_send(dev,&i2cbuff,HDCS_ADDR)); } /* * Fill the pointers so that the routines are called from quickcam.c */ void load_hdcs_mod(struct sensorctrl *sensor_ctrl) { sensor_ctrl->init = hdcs_init; sensor_ctrl->set_shutter = hdcs_set_shutter; sensor_ctrl->set_gains = hdcs_set_gains; sensor_ctrl->set_window = hdcs_set_window; sensor_ctrl->set_size = hdcs_set_size; sensor_ctrl->start = hdcs_start; sensor_ctrl->stop = hdcs_stop; control = HDCS_CONTROL; config = HDCS_CONFIG; } void load_hdcs20_mod(struct sensorctrl *sensor_ctrl) { load_hdcs_mod(sensor_ctrl); control = HDCS20_CONTROL; config = HDCS20_CONFIG; }