Commit 55db765c authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab

[media] gspca_zc3xx: Always automatically adjust BRC as needed

Always automatically adjust the Bit Rate Control setting as needed, independent
of the sensor type. BRC is needed to not run out of bandwidth with higher
quality settings independent of the sensor.

Also only automatically adjust BRC, and don't adjust the JPEG quality control
automatically, as that is not needed and leads to ugly flashes when it is
changed. Note that before this patch-set the quality was never changed
either due to the bugs in the quality handling fixed in previous patches in
this set.
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 83fb2e2e
...@@ -5921,22 +5921,8 @@ static void setexposure(struct gspca_dev *gspca_dev) ...@@ -5921,22 +5921,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
static void setquality(struct gspca_dev *gspca_dev) static void setquality(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s8 reg07;
jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08 >> 1]); jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08 >> 1]);
reg07 = 0;
switch (sd->sensor) {
case SENSOR_OV7620:
reg07 = 0x30;
break;
case SENSOR_HV7131R:
case SENSOR_PAS202B:
return; /* done by work queue */
}
reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
if (reg07 != 0)
reg_w(gspca_dev, reg07, 0x0007);
} }
/* Matches the sensor's internal frame rate to the lighting frequency. /* Matches the sensor's internal frame rate to the lighting frequency.
...@@ -6070,110 +6056,63 @@ static void setautogain(struct gspca_dev *gspca_dev) ...@@ -6070,110 +6056,63 @@ static void setautogain(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, autoval, 0x0180); reg_w(gspca_dev, autoval, 0x0180);
} }
/* update the transfer parameters */ /*
/* This function is executed from a work queue. */ * Update the transfer parameters.
/* The exact use of the bridge registers 07 and 08 is not known. * This function is executed from a work queue.
* The following algorithm has been adapted from ms-win traces */ */
static void transfer_update(struct work_struct *work) static void transfer_update(struct work_struct *work)
{ {
struct sd *sd = container_of(work, struct sd, work); struct sd *sd = container_of(work, struct sd, work);
struct gspca_dev *gspca_dev = &sd->gspca_dev; struct gspca_dev *gspca_dev = &sd->gspca_dev;
int change, good; int change, good;
u8 reg07, qual, reg11; u8 reg07, reg11;
/* synchronize with the main driver and initialize the registers */ /* reg07 gets set to 0 by sd_start before starting us */
mutex_lock(&gspca_dev->usb_lock); reg07 = 0;
reg07 = 0; /* max */
qual = sd->reg08 >> 1;
reg_w(gspca_dev, reg07, 0x0007);
reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
mutex_unlock(&gspca_dev->usb_lock);
good = 0; good = 0;
for (;;) { for (;;) {
msleep(100); msleep(100);
/* get the transfer status */
/* the bit 0 of the bridge register 11 indicates overflow */
mutex_lock(&gspca_dev->usb_lock); mutex_lock(&gspca_dev->usb_lock);
if (gspca_dev->frozen || !gspca_dev->dev || if (gspca_dev->frozen || !gspca_dev->dev ||
!gspca_dev->streaming) !gspca_dev->streaming)
goto err; goto err;
/* Bit 0 of register 11 indicates FIFO overflow */
gspca_dev->usb_err = 0;
reg11 = reg_r(gspca_dev, 0x0011); reg11 = reg_r(gspca_dev, 0x0011);
if (gspca_dev->usb_err < 0 if (gspca_dev->usb_err)
|| !gspca_dev->present || !gspca_dev->streaming)
goto err; goto err;
change = reg11 & 0x01; change = reg11 & 0x01;
if (change) { /* overflow */ if (change) { /* overflow */
switch (reg07) {
case 0: /* max */
reg07 = sd->sensor == SENSOR_HV7131R
? 0x30 : 0x32;
if (qual != 0) {
change = 3;
qual--;
}
break;
case 0x32:
reg07 -= 4;
break;
default:
reg07 -= 2;
break;
case 2:
change = 0; /* already min */
break;
}
good = 0; good = 0;
if (reg07 == 0) /* Bit Rate Control not enabled? */
reg07 = 0x32; /* Allow 98 bytes / unit */
else if (reg07 > 2)
reg07 -= 2; /* Decrease allowed bytes / unit */
else
change = 0;
} else { /* no overflow */ } else { /* no overflow */
if (reg07 != 0) { /* if not max */ good++;
good++; if (good >= 10) {
if (good >= 10) { good = 0;
good = 0; if (reg07) { /* BRC enabled? */
change = 1; change = 1;
reg07 += 2; if (reg07 < 0x32)
switch (reg07) { reg07 += 2;
case 0x30: else
if (sd->sensor == SENSOR_PAS202B)
reg07 += 2;
break;
case 0x32:
case 0x34:
reg07 = 0; reg07 = 0;
break;
}
}
} else { /* reg07 max */
if (qual < sizeof jpeg_qual - 1) {
good++;
if (good > 10) {
qual++;
change = 2;
}
} }
} }
} }
if (change) { if (change) {
if (change & 1) { gspca_dev->usb_err = 0;
reg_w(gspca_dev, reg07, 0x0007); reg_w(gspca_dev, reg07, 0x0007);
if (gspca_dev->usb_err < 0 if (gspca_dev->usb_err)
|| !gspca_dev->present goto err;
|| !gspca_dev->streaming)
goto err;
}
if (change & 2) {
sd->reg08 = (qual << 1) | 1;
reg_w(gspca_dev, sd->reg08,
ZC3XX_R008_CLOCKSETTING);
if (gspca_dev->usb_err < 0
|| !gspca_dev->present
|| !gspca_dev->streaming)
goto err;
sd->ctrls[QUALITY].val = jpeg_qual[qual];
jpeg_set_qual(sd->jpeg_hdr,
jpeg_qual[qual]);
}
} }
mutex_unlock(&gspca_dev->usb_lock); mutex_unlock(&gspca_dev->usb_lock);
} }
...@@ -6721,14 +6660,10 @@ static int sd_init(struct gspca_dev *gspca_dev) ...@@ -6721,14 +6660,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
switch (sd->sensor) { switch (sd->sensor) {
case SENSOR_HV7131R: case SENSOR_HV7131R:
gspca_dev->ctrl_dis = (1 << QUALITY);
break; break;
case SENSOR_OV7630C: case SENSOR_OV7630C:
gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
break; break;
case SENSOR_PAS202B:
gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE);
break;
default: default:
gspca_dev->ctrl_dis = (1 << EXPOSURE); gspca_dev->ctrl_dis = (1 << EXPOSURE);
break; break;
...@@ -6743,6 +6678,13 @@ static int sd_init(struct gspca_dev *gspca_dev) ...@@ -6743,6 +6678,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err; return gspca_dev->usb_err;
} }
static int sd_pre_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
gspca_dev->cam.needs_full_bandwidth = (sd->reg08 >= 4) ? 1 : 0;
return 0;
}
static int sd_start(struct gspca_dev *gspca_dev) static int sd_start(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -6868,6 +6810,8 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -6868,6 +6810,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
break; break;
} }
setquality(gspca_dev); setquality(gspca_dev);
/* Start with BRC disabled, transfer_update will enable it if needed */
reg_w(gspca_dev, 0x00, 0x0007);
setlightfreq(gspca_dev); setlightfreq(gspca_dev);
switch (sd->sensor) { switch (sd->sensor) {
...@@ -6905,19 +6849,14 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -6905,19 +6849,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
setautogain(gspca_dev); setautogain(gspca_dev);
/* start the transfer update thread if needed */ if (gspca_dev->usb_err < 0)
if (gspca_dev->usb_err >= 0) { return gspca_dev->usb_err;
switch (sd->sensor) {
case SENSOR_HV7131R:
case SENSOR_PAS202B:
sd->work_thread =
create_singlethread_workqueue(KBUILD_MODNAME);
queue_work(sd->work_thread, &sd->work);
break;
}
}
return gspca_dev->usb_err; /* Start the transfer parameters update thread */
sd->work_thread = create_singlethread_workqueue(KBUILD_MODNAME);
queue_work(sd->work_thread, &sd->work);
return 0;
} }
/* called on streamoff with alt 0 and on disconnect */ /* called on streamoff with alt 0 and on disconnect */
...@@ -7020,8 +6959,15 @@ static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val) ...@@ -7020,8 +6959,15 @@ static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
&& i == qual && i == qual
&& val < jpeg_qual[i]) && val < jpeg_qual[i])
i--; i--;
/* With high quality settings we need max bandwidth */
if (i >= 2 && gspca_dev->streaming &&
!gspca_dev->cam.needs_full_bandwidth)
return -EBUSY;
sd->reg08 = (i << 1) | 1; sd->reg08 = (i << 1) | 1;
sd->ctrls[QUALITY].val = jpeg_qual[i]; sd->ctrls[QUALITY].val = jpeg_qual[i];
if (gspca_dev->streaming) if (gspca_dev->streaming)
setquality(gspca_dev); setquality(gspca_dev);
return gspca_dev->usb_err; return gspca_dev->usb_err;
...@@ -7071,6 +7017,7 @@ static const struct sd_desc sd_desc = { ...@@ -7071,6 +7017,7 @@ static const struct sd_desc sd_desc = {
.nctrls = ARRAY_SIZE(sd_ctrls), .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config, .config = sd_config,
.init = sd_init, .init = sd_init,
.isoc_init = sd_pre_start,
.start = sd_start, .start = sd_start,
.stop0 = sd_stop0, .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan, .pkt_scan = sd_pkt_scan,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment