Skip to content

Commit

Permalink
[media] gspca_zc3xx: Always automatically adjust BRC as needed
Browse files Browse the repository at this point in the history
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: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Hans de Goede authored and Mauro Carvalho Chehab committed May 14, 2012
1 parent 83fb2e2 commit 55db765
Showing 1 changed file with 53 additions and 106 deletions.
159 changes: 53 additions & 106 deletions drivers/media/video/gspca/zc3xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -5921,22 +5921,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
static void setquality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
s8 reg07;

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);
if (reg07 != 0)
reg_w(gspca_dev, reg07, 0x0007);
}

/* Matches the sensor's internal frame rate to the lighting frequency.
Expand Down Expand Up @@ -6070,110 +6056,63 @@ static void setautogain(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, autoval, 0x0180);
}

/* update the transfer parameters */
/* This function is executed from a work queue. */
/* The exact use of the bridge registers 07 and 08 is not known.
* The following algorithm has been adapted from ms-win traces */
/*
* Update the transfer parameters.
* This function is executed from a work queue.
*/
static void transfer_update(struct work_struct *work)
{
struct sd *sd = container_of(work, struct sd, work);
struct gspca_dev *gspca_dev = &sd->gspca_dev;
int change, good;
u8 reg07, qual, reg11;
u8 reg07, reg11;

/* synchronize with the main driver and initialize the registers */
mutex_lock(&gspca_dev->usb_lock);
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);
/* reg07 gets set to 0 by sd_start before starting us */
reg07 = 0;

good = 0;
for (;;) {
msleep(100);

/* get the transfer status */
/* the bit 0 of the bridge register 11 indicates overflow */
mutex_lock(&gspca_dev->usb_lock);
if (gspca_dev->frozen || !gspca_dev->dev ||
!gspca_dev->streaming)
goto err;

/* Bit 0 of register 11 indicates FIFO overflow */
gspca_dev->usb_err = 0;
reg11 = reg_r(gspca_dev, 0x0011);
if (gspca_dev->usb_err < 0
|| !gspca_dev->present || !gspca_dev->streaming)
if (gspca_dev->usb_err)
goto err;

change = reg11 & 0x01;
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;

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 */
if (reg07 != 0) { /* if not max */
good++;
if (good >= 10) {
good = 0;
good++;
if (good >= 10) {
good = 0;
if (reg07) { /* BRC enabled? */
change = 1;
reg07 += 2;
switch (reg07) {
case 0x30:
if (sd->sensor == SENSOR_PAS202B)
reg07 += 2;
break;
case 0x32:
case 0x34:
if (reg07 < 0x32)
reg07 += 2;
else
reg07 = 0;
break;
}
}
} else { /* reg07 max */
if (qual < sizeof jpeg_qual - 1) {
good++;
if (good > 10) {
qual++;
change = 2;
}
}
}
}
if (change) {
if (change & 1) {
reg_w(gspca_dev, reg07, 0x0007);
if (gspca_dev->usb_err < 0
|| !gspca_dev->present
|| !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]);
}
gspca_dev->usb_err = 0;
reg_w(gspca_dev, reg07, 0x0007);
if (gspca_dev->usb_err)
goto err;
}
mutex_unlock(&gspca_dev->usb_lock);
}
Expand Down Expand Up @@ -6721,14 +6660,10 @@ static int sd_init(struct gspca_dev *gspca_dev)

switch (sd->sensor) {
case SENSOR_HV7131R:
gspca_dev->ctrl_dis = (1 << QUALITY);
break;
case SENSOR_OV7630C:
gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
break;
case SENSOR_PAS202B:
gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE);
break;
default:
gspca_dev->ctrl_dis = (1 << EXPOSURE);
break;
Expand All @@ -6743,6 +6678,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
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)
{
struct sd *sd = (struct sd *) gspca_dev;
Expand Down Expand Up @@ -6868,6 +6810,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
}
setquality(gspca_dev);
/* Start with BRC disabled, transfer_update will enable it if needed */
reg_w(gspca_dev, 0x00, 0x0007);
setlightfreq(gspca_dev);

switch (sd->sensor) {
Expand Down Expand Up @@ -6905,19 +6849,14 @@ static int sd_start(struct gspca_dev *gspca_dev)

setautogain(gspca_dev);

/* start the transfer update thread if needed */
if (gspca_dev->usb_err >= 0) {
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;
}
}
if (gspca_dev->usb_err < 0)
return gspca_dev->usb_err;

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 */
Expand Down Expand Up @@ -7020,8 +6959,15 @@ static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
&& i == qual
&& val < jpeg_qual[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->ctrls[QUALITY].val = jpeg_qual[i];

if (gspca_dev->streaming)
setquality(gspca_dev);
return gspca_dev->usb_err;
Expand Down Expand Up @@ -7071,6 +7017,7 @@ static const struct sd_desc sd_desc = {
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
.isoc_init = sd_pre_start,
.start = sd_start,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
Expand Down

0 comments on commit 55db765

Please sign in to comment.