[media] au8028: Fix cleanup on kzalloc fail
[cascardo/linux.git] / drivers / media / usb / au0828 / au0828-dvb.c
index 9a6f156..3c718db 100644 (file)
@@ -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;
@@ -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;
                }
 
@@ -217,6 +222,27 @@ err:
        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;
@@ -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);
        }
@@ -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);
        }
@@ -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);
@@ -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: