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) ...@@ -846,10 +846,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
return 0; return 0;
} }
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev)
{ {
int retry = 50; int retry = 50;
if (!gspca_dev->present)
return;
reg_w_val(gspca_dev, 0x0000, 0x00); reg_w_val(gspca_dev, 0x0000, 0x00);
reg_r(gspca_dev, 0x0002, 1); reg_r(gspca_dev, 0x0002, 1);
reg_w_val(gspca_dev, 0x0053, 0x00); reg_w_val(gspca_dev, 0x0053, 0x00);
......
...@@ -276,6 +276,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -276,6 +276,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
/* Stop the state machine */ /* Stop the state machine */
if (dev->state != FPIX_NOP) if (dev->state != FPIX_NOP)
wait_for_completion(&dev->can_close); 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); usb_free_urb(dev->control_urb);
dev->control_urb = NULL; dev->control_urb = NULL;
...@@ -385,6 +391,7 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -385,6 +391,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
error: error:
/* Free the ressources */ /* Free the ressources */
sd_stopN(gspca_dev); sd_stopN(gspca_dev);
sd_stop0(gspca_dev);
return ret; return ret;
} }
...@@ -425,6 +432,7 @@ static const struct sd_desc sd_desc = { ...@@ -425,6 +432,7 @@ static const struct sd_desc sd_desc = {
.init = sd_init, .init = sd_init,
.start = sd_start, .start = sd_start,
.stopN = sd_stopN, .stopN = sd_stopN,
.stop0 = sd_stop0,
}; };
/* -- device connect -- */ /* -- device connect -- */
......
...@@ -646,15 +646,14 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev) ...@@ -646,15 +646,14 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
{ {
gspca_dev->streaming = 0; gspca_dev->streaming = 0;
atomic_set(&gspca_dev->nevent, 0); atomic_set(&gspca_dev->nevent, 0);
if (gspca_dev->present) { if (gspca_dev->present
if (gspca_dev->sd_desc->stopN) && gspca_dev->sd_desc->stopN)
gspca_dev->sd_desc->stopN(gspca_dev); gspca_dev->sd_desc->stopN(gspca_dev);
destroy_urbs(gspca_dev); destroy_urbs(gspca_dev);
gspca_set_alt0(gspca_dev); gspca_set_alt0(gspca_dev);
if (gspca_dev->sd_desc->stop0) if (gspca_dev->sd_desc->stop0)
gspca_dev->sd_desc->stop0(gspca_dev); gspca_dev->sd_desc->stop0(gspca_dev);
PDEBUG(D_STREAM, "stream off OK"); PDEBUG(D_STREAM, "stream off OK");
}
} }
static void gspca_set_default_mode(struct gspca_dev *gspca_dev) static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
......
...@@ -97,7 +97,7 @@ struct sd_desc { ...@@ -97,7 +97,7 @@ struct sd_desc {
cam_pkt_op pkt_scan; cam_pkt_op pkt_scan;
/* optional operations */ /* optional operations */
cam_v_op stopN; /* called on stream off - main alt */ 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_v_op dq_callback; /* called when a frame has been dequeued */
cam_jpg_op get_jcomp; cam_jpg_op get_jcomp;
cam_jpg_op set_jcomp; cam_jpg_op set_jcomp;
......
...@@ -749,10 +749,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -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 */ 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) static void sd_stop0(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
if (!gspca_dev->present)
return;
if (sd->sensor == SENSOR_PAC7302) { if (sd->sensor == SENSOR_PAC7302) {
reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x78, 0x40); reg_w(gspca_dev, 0x78, 0x40);
......
...@@ -2022,8 +2022,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -2022,8 +2022,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00); 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) static void sd_stop0(struct gspca_dev *gspca_dev)
{ {
if (!gspca_dev->present)
return;
reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
} }
......
...@@ -742,8 +742,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -742,8 +742,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_write(gspca_dev->dev, 0x02, 0x00, 0x00); 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) static void sd_stop0(struct gspca_dev *gspca_dev)
{ {
if (!gspca_dev->present)
return;
/* This maybe reset or power control */ /* This maybe reset or power control */
reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
reg_write(gspca_dev->dev, 0x03, 0x01, 0x0); reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
......
...@@ -766,10 +766,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -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) static void sd_stop0(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
if (!gspca_dev->present)
return;
if (sd->chip_revision == Rev012A) { if (sd->chip_revision == Rev012A) {
reg_w_val(gspca_dev->dev, 0x8118, 0x29); reg_w_val(gspca_dev->dev, 0x8118, 0x29);
reg_w_val(gspca_dev->dev, 0x8114, 0x08); reg_w_val(gspca_dev->dev, 0x8114, 0x08);
......
...@@ -1633,10 +1633,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -1633,10 +1633,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w(dev, 0xa0, 0x09, 0xb003); reg_w(dev, 0xa0, 0x09, 0xb003);
} }
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev)
{ {
struct usb_device *dev = gspca_dev->dev; struct usb_device *dev = gspca_dev->dev;
if (!gspca_dev->present)
return;
reg_w(dev, 0x89, 0xffff, 0xffff); reg_w(dev, 0x89, 0xffff, 0xffff);
} }
......
...@@ -7336,10 +7336,13 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -7336,10 +7336,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
return 0; return 0;
} }
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
if (!gspca_dev->present)
return;
send_unknown(gspca_dev->dev, sd->sensor); 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