Skip to content

Commit

Permalink
[media] au8028: Fix cleanup on kzalloc fail
Browse files Browse the repository at this point in the history
Free what was allocated if there is a failure allocating
transfer buffers.

Stop the feed on a start feed error.  The stop feed is not always called
if start feed fails.  If the feed is not stopped on error, then the driver
will be stuck so that it can never start feeding again.

[m.chehab@samsung.com: CodingStyle cleanup]
Signed-off-by: Tim Mester <tmester@ieee.org>
Acked-by: Devin Heitmueller <dheitmueller@kernellabs.com>

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
  • Loading branch information
Tim Mester authored and Mauro Carvalho Chehab committed Jan 13, 2014
1 parent bbd8f3f commit 4609981
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 19 deletions.
71 changes: 52 additions & 19 deletions drivers/media/usb/au0828/au0828-dvb.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,11 @@ static int stop_urb_transfer(struct au0828_dev *dev)

dev->urb_streaming = 0;
for (i = 0; i < URB_COUNT; i++) {
usb_kill_urb(dev->urbs[i]);
kfree(dev->urbs[i]->transfer_buffer);
usb_free_urb(dev->urbs[i]);
if (dev->urbs[i]) {
usb_kill_urb(dev->urbs[i]);
kfree(dev->urbs[i]->transfer_buffer);
usb_free_urb(dev->urbs[i]);
}
}

return 0;
Expand Down Expand Up @@ -185,6 +187,9 @@ static int start_urb_transfer(struct au0828_dev *dev)
if (!purb->transfer_buffer) {
usb_free_urb(purb);
dev->urbs[i] = NULL;
printk(KERN_ERR
"%s: failed big buffer allocation, err = %d\n",
__func__, ret);
goto err;
}

Expand Down Expand Up @@ -217,6 +222,27 @@ static int start_urb_transfer(struct au0828_dev *dev)
return ret;
}

static void au0828_start_transport(struct au0828_dev *dev)
{
au0828_write(dev, 0x608, 0x90);
au0828_write(dev, 0x609, 0x72);
au0828_write(dev, 0x60a, 0x71);
au0828_write(dev, 0x60b, 0x01);

}

static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
{
if (full_stop) {
au0828_write(dev, 0x608, 0x00);
au0828_write(dev, 0x609, 0x00);
au0828_write(dev, 0x60a, 0x00);
}
au0828_write(dev, 0x60b, 0x00);
}



static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
Expand All @@ -231,13 +257,17 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)

if (dvb) {
mutex_lock(&dvb->lock);
dvb->start_count++;
dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
dvb->start_count, dvb->stop_count);
if (dvb->feeding++ == 0) {
/* Start transport */
au0828_write(dev, 0x608, 0x90);
au0828_write(dev, 0x609, 0x72);
au0828_write(dev, 0x60a, 0x71);
au0828_write(dev, 0x60b, 0x01);
au0828_start_transport(dev);
ret = start_urb_transfer(dev);
if (ret < 0) {
au0828_stop_transport(dev, 0);
dvb->feeding--; /* We ran out of memory... */
}
}
mutex_unlock(&dvb->lock);
}
Expand All @@ -256,10 +286,16 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)

if (dvb) {
mutex_lock(&dvb->lock);
if (--dvb->feeding == 0) {
/* Stop transport */
ret = stop_urb_transfer(dev);
au0828_write(dev, 0x60b, 0x00);
dvb->stop_count++;
dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
dvb->start_count, dvb->stop_count);
if (dvb->feeding > 0) {
dvb->feeding--;
if (dvb->feeding == 0) {
/* Stop transport */
ret = stop_urb_transfer(dev);
au0828_stop_transport(dev, 0);
}
}
mutex_unlock(&dvb->lock);
}
Expand All @@ -282,16 +318,10 @@ static void au0828_restart_dvb_streaming(struct work_struct *work)

/* Stop transport */
stop_urb_transfer(dev);
au0828_write(dev, 0x608, 0x00);
au0828_write(dev, 0x609, 0x00);
au0828_write(dev, 0x60a, 0x00);
au0828_write(dev, 0x60b, 0x00);
au0828_stop_transport(dev, 1);

/* Start transport */
au0828_write(dev, 0x608, 0x90);
au0828_write(dev, 0x609, 0x72);
au0828_write(dev, 0x60a, 0x71);
au0828_write(dev, 0x60b, 0x01);
au0828_start_transport(dev);
start_urb_transfer(dev);

mutex_unlock(&dvb->lock);
Expand Down Expand Up @@ -375,6 +405,9 @@ static int dvb_register(struct au0828_dev *dev)

/* register network adapter */
dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);

dvb->start_count = 0;
dvb->stop_count = 0;
return 0;

fail_fe_conn:
Expand Down
2 changes: 2 additions & 0 deletions drivers/media/usb/au0828/au0828.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ struct au0828_dvb {
struct dmx_frontend fe_mem;
struct dvb_net net;
int feeding;
int start_count;
int stop_count;
};

enum au0828_stream_state {
Expand Down

0 comments on commit 4609981

Please sign in to comment.