mirror of https://gitee.com/openkylin/linux.git
V4L/DVB (9689): gspca: Memory leak when disconnect while streaming.
As a side effect, the sd routine stop0 is called on disconnect. This permits the subdriver to free its resources. Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
818a557eeb
commit
98522a7be9
|
@ -846,10 +846,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* called on streamoff with alt 0 and on disconnect */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
int retry = 50;
|
||||
|
||||
if (!gspca_dev->present)
|
||||
return;
|
||||
reg_w_val(gspca_dev, 0x0000, 0x00);
|
||||
reg_r(gspca_dev, 0x0002, 1);
|
||||
reg_w_val(gspca_dev, 0x0053, 0x00);
|
||||
|
|
|
@ -276,6 +276,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
|
|||
/* Stop the state machine */
|
||||
if (dev->state != FPIX_NOP)
|
||||
wait_for_completion(&dev->can_close);
|
||||
}
|
||||
|
||||
/* called on streamoff with alt 0 and disconnect */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
|
||||
|
||||
usb_free_urb(dev->control_urb);
|
||||
dev->control_urb = NULL;
|
||||
|
@ -385,6 +391,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
|||
error:
|
||||
/* Free the ressources */
|
||||
sd_stopN(gspca_dev);
|
||||
sd_stop0(gspca_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -425,6 +432,7 @@ static const struct sd_desc sd_desc = {
|
|||
.init = sd_init,
|
||||
.start = sd_start,
|
||||
.stopN = sd_stopN,
|
||||
.stop0 = sd_stop0,
|
||||
};
|
||||
|
||||
/* -- device connect -- */
|
||||
|
|
|
@ -646,15 +646,14 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
|
|||
{
|
||||
gspca_dev->streaming = 0;
|
||||
atomic_set(&gspca_dev->nevent, 0);
|
||||
if (gspca_dev->present) {
|
||||
if (gspca_dev->sd_desc->stopN)
|
||||
gspca_dev->sd_desc->stopN(gspca_dev);
|
||||
destroy_urbs(gspca_dev);
|
||||
gspca_set_alt0(gspca_dev);
|
||||
if (gspca_dev->sd_desc->stop0)
|
||||
gspca_dev->sd_desc->stop0(gspca_dev);
|
||||
PDEBUG(D_STREAM, "stream off OK");
|
||||
}
|
||||
if (gspca_dev->present
|
||||
&& gspca_dev->sd_desc->stopN)
|
||||
gspca_dev->sd_desc->stopN(gspca_dev);
|
||||
destroy_urbs(gspca_dev);
|
||||
gspca_set_alt0(gspca_dev);
|
||||
if (gspca_dev->sd_desc->stop0)
|
||||
gspca_dev->sd_desc->stop0(gspca_dev);
|
||||
PDEBUG(D_STREAM, "stream off OK");
|
||||
}
|
||||
|
||||
static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
|
||||
|
|
|
@ -97,7 +97,7 @@ struct sd_desc {
|
|||
cam_pkt_op pkt_scan;
|
||||
/* optional operations */
|
||||
cam_v_op stopN; /* called on stream off - main alt */
|
||||
cam_v_op stop0; /* called on stream off - alt 0 */
|
||||
cam_v_op stop0; /* called on stream off & disconnect - alt 0 */
|
||||
cam_v_op dq_callback; /* called when a frame has been dequeued */
|
||||
cam_jpg_op get_jcomp;
|
||||
cam_jpg_op set_jcomp;
|
||||
|
|
|
@ -749,10 +749,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
|
|||
reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
|
||||
}
|
||||
|
||||
/* called on streamoff with alt 0 and on disconnect */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
if (!gspca_dev->present)
|
||||
return;
|
||||
if (sd->sensor == SENSOR_PAC7302) {
|
||||
reg_w(gspca_dev, 0xff, 0x01);
|
||||
reg_w(gspca_dev, 0x78, 0x40);
|
||||
|
|
|
@ -2022,8 +2022,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
|
|||
reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00);
|
||||
}
|
||||
|
||||
/* called on streamoff with alt 0 and on disconnect */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
if (!gspca_dev->present)
|
||||
return;
|
||||
reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
|
||||
}
|
||||
|
||||
|
|
|
@ -742,8 +742,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
|
|||
reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
|
||||
}
|
||||
|
||||
/* called on streamoff with alt 0 and on disconnect */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
if (!gspca_dev->present)
|
||||
return;
|
||||
|
||||
/* This maybe reset or power control */
|
||||
reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
|
||||
reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
|
||||
|
|
|
@ -766,10 +766,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
|
|||
}
|
||||
}
|
||||
|
||||
/* called on streamoff with alt 0 and on disconnect */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
if (!gspca_dev->present)
|
||||
return;
|
||||
if (sd->chip_revision == Rev012A) {
|
||||
reg_w_val(gspca_dev->dev, 0x8118, 0x29);
|
||||
reg_w_val(gspca_dev->dev, 0x8114, 0x08);
|
||||
|
|
|
@ -1633,10 +1633,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
|
|||
reg_w(dev, 0xa0, 0x09, 0xb003);
|
||||
}
|
||||
|
||||
/* called on streamoff with alt 0 and on disconnect */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct usb_device *dev = gspca_dev->dev;
|
||||
|
||||
if (!gspca_dev->present)
|
||||
return;
|
||||
reg_w(dev, 0x89, 0xffff, 0xffff);
|
||||
}
|
||||
|
||||
|
|
|
@ -7336,10 +7336,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* called on streamoff with alt 0 and on disconnect */
|
||||
static void sd_stop0(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
if (!gspca_dev->present)
|
||||
return;
|
||||
send_unknown(gspca_dev->dev, sd->sensor);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue