Commit 98522a7b authored by Jean-Francois Moine's avatar Jean-Francois Moine Committed by Mauro Carvalho Chehab

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: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 818a557e
......@@ -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);
}
......
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