aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/zc3xx.c
diff options
context:
space:
mode:
authorJean-François Moine <moinejf@free.fr>2012-02-27 05:48:32 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-03-08 06:03:18 -0500
commitf1801904eeb79f46e7854e4d18c7107160a16093 (patch)
tree402d96a017ea7614fe92d04a5a60b1f0af4f566a /drivers/media/video/gspca/zc3xx.c
parent30c73d464a10bee4bb8375bb2ed8cc102c507bb7 (diff)
[media] gspca - zc3xx: Do automatic transfer control for hv7131r and pas202b
The bridge register 11 reports the current transfer status. This value is used to know about a possible overflow and to adjust the transfer parameters (registers 07 and 08). Signed-off-by: Jean-François Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca/zc3xx.c')
-rw-r--r--drivers/media/video/gspca/zc3xx.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index c02fb31987cc..d6175f5d1056 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -57,6 +57,9 @@ struct sd {
57 57
58 struct gspca_ctrl ctrls[NCTRLS]; 58 struct gspca_ctrl ctrls[NCTRLS];
59 59
60 struct work_struct work;
61 struct workqueue_struct *work_thread;
62
60 u8 reg08; /* webcam compression quality */ 63 u8 reg08; /* webcam compression quality */
61 64
62 u8 bridge; 65 u8 bridge;
@@ -5932,6 +5935,9 @@ static void setquality(struct gspca_dev *gspca_dev)
5932 case SENSOR_OV7620: 5935 case SENSOR_OV7620:
5933 reg07 = 0x30; 5936 reg07 = 0x30;
5934 break; 5937 break;
5938 case SENSOR_HV7131R:
5939 case SENSOR_PAS202B:
5940 return; /* done by work queue */
5935 } 5941 }
5936 reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); 5942 reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
5937 if (reg07 != 0) 5943 if (reg07 != 0)
@@ -6069,6 +6075,114 @@ static void setautogain(struct gspca_dev *gspca_dev)
6069 reg_w(gspca_dev, autoval, 0x0180); 6075 reg_w(gspca_dev, autoval, 0x0180);
6070} 6076}
6071 6077
6078/* update the transfer parameters */
6079/* This function is executed from a work queue. */
6080/* The exact use of the bridge registers 07 and 08 is not known.
6081 * The following algorithm has been adapted from ms-win traces */
6082static void transfer_update(struct work_struct *work)
6083{
6084 struct sd *sd = container_of(work, struct sd, work);
6085 struct gspca_dev *gspca_dev = &sd->gspca_dev;
6086 int change, good;
6087 u8 reg07, reg11;
6088
6089 /* synchronize with the main driver and initialize the registers */
6090 mutex_lock(&gspca_dev->usb_lock);
6091 reg07 = 0; /* max */
6092 reg_w(gspca_dev, reg07, 0x0007);
6093 reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
6094 mutex_unlock(&gspca_dev->usb_lock);
6095
6096 good = 0;
6097 for (;;) {
6098 msleep(100);
6099
6100 /* get the transfer status */
6101 /* the bit 0 of the bridge register 11 indicates overflow */
6102 mutex_lock(&gspca_dev->usb_lock);
6103 if (!gspca_dev->present || !gspca_dev->streaming)
6104 goto err;
6105 reg11 = reg_r(gspca_dev, 0x0011);
6106 if (gspca_dev->usb_err < 0
6107 || !gspca_dev->present || !gspca_dev->streaming)
6108 goto err;
6109
6110 change = reg11 & 0x01;
6111 if (change) { /* overflow */
6112 switch (reg07) {
6113 case 0: /* max */
6114 reg07 = sd->sensor == SENSOR_HV7131R
6115 ? 0x30 : 0x32;
6116 if (sd->reg08 != 0) {
6117 change = 3;
6118 sd->reg08--;
6119 }
6120 break;
6121 case 0x32:
6122 reg07 -= 4;
6123 break;
6124 default:
6125 reg07 -= 2;
6126 break;
6127 case 2:
6128 change = 0; /* already min */
6129 break;
6130 }
6131 good = 0;
6132 } else { /* no overflow */
6133 if (reg07 != 0) { /* if not max */
6134 good++;
6135 if (good >= 10) {
6136 good = 0;
6137 change = 1;
6138 reg07 += 2;
6139 switch (reg07) {
6140 case 0x30:
6141 if (sd->sensor == SENSOR_PAS202B)
6142 reg07 += 2;
6143 break;
6144 case 0x32:
6145 case 0x34:
6146 reg07 = 0;
6147 break;
6148 }
6149 }
6150 } else { /* reg07 max */
6151 if (sd->reg08 < sizeof jpeg_qual - 1) {
6152 good++;
6153 if (good > 10) {
6154 sd->reg08++;
6155 change = 2;
6156 }
6157 }
6158 }
6159 }
6160 if (change) {
6161 if (change & 1) {
6162 reg_w(gspca_dev, reg07, 0x0007);
6163 if (gspca_dev->usb_err < 0
6164 || !gspca_dev->present
6165 || !gspca_dev->streaming)
6166 goto err;
6167 }
6168 if (change & 2) {
6169 reg_w(gspca_dev, sd->reg08,
6170 ZC3XX_R008_CLOCKSETTING);
6171 if (gspca_dev->usb_err < 0
6172 || !gspca_dev->present
6173 || !gspca_dev->streaming)
6174 goto err;
6175 jpeg_set_qual(sd->jpeg_hdr,
6176 jpeg_qual[sd->reg08]);
6177 }
6178 }
6179 mutex_unlock(&gspca_dev->usb_lock);
6180 }
6181 return;
6182err:
6183 mutex_unlock(&gspca_dev->usb_lock);
6184}
6185
6072static void send_unknown(struct gspca_dev *gspca_dev, int sensor) 6186static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
6073{ 6187{
6074 reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */ 6188 reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */
@@ -6398,6 +6512,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
6398 gspca_dev->cam.ctrls = sd->ctrls; 6512 gspca_dev->cam.ctrls = sd->ctrls;
6399 sd->reg08 = REG08_DEF; 6513 sd->reg08 = REG08_DEF;
6400 6514
6515 INIT_WORK(&sd->work, transfer_update);
6516
6401 return 0; 6517 return 0;
6402} 6518}
6403 6519
@@ -6807,6 +6923,18 @@ static int sd_start(struct gspca_dev *gspca_dev)
6807 } 6923 }
6808 6924
6809 setautogain(gspca_dev); 6925 setautogain(gspca_dev);
6926
6927 /* start the transfer update thread if needed */
6928 if (gspca_dev->usb_err >= 0) {
6929 switch (sd->sensor) {
6930 case SENSOR_HV7131R:
6931 case SENSOR_PAS202B:
6932 sd->work_thread = create_singlethread_workqueue(MODULE_NAME);
6933 queue_work(sd->work_thread, &sd->work);
6934 break;
6935 }
6936 }
6937
6810 return gspca_dev->usb_err; 6938 return gspca_dev->usb_err;
6811} 6939}
6812 6940
@@ -6815,6 +6943,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
6815{ 6943{
6816 struct sd *sd = (struct sd *) gspca_dev; 6944 struct sd *sd = (struct sd *) gspca_dev;
6817 6945
6946 if (sd->work_thread != NULL) {
6947 mutex_unlock(&gspca_dev->usb_lock);
6948 destroy_workqueue(sd->work_thread);
6949 mutex_lock(&gspca_dev->usb_lock);
6950 sd->work_thread = NULL;
6951 }
6818 if (!gspca_dev->present) 6952 if (!gspca_dev->present)
6819 return; 6953 return;
6820 send_unknown(gspca_dev, sd->sensor); 6954 send_unknown(gspca_dev, sd->sensor);