vserver 2.0 rc7
[linux-2.6.git] / drivers / media / dvb / dibusb / dvb-dibusb-usb.c
index 656a011..642f059 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices 
+ * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
  * based on reference design made by DiBcom (http://www.dibcom.fr/)
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
  * see dvb-dibusb-core.c for more copyright details.
  *
- * This file contains functions for initializing and handling the 
+ * This file contains functions for initializing and handling the
  * usb specific stuff.
  */
 #include "dvb-dibusb.h"
@@ -25,18 +25,12 @@ int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
        if ((ret = down_interruptible(&dib->usb_sem)))
                return ret;
 
-       if (dib->feedcount && 
-               wbuf[0] == DIBUSB_REQ_I2C_WRITE && 
-               dib->dibdev->dev_cl->id == DIBUSB1_1)
-               deb_err("BUG: writing to i2c, while TS-streaming destroys the stream."
-                               "(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
-                       
        debug_dump(wbuf,wlen);
 
        ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
                        dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen,
                        DIBUSB_I2C_TIMEOUT);
-               
+
        if (ret)
                err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
        else
@@ -55,7 +49,7 @@ int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
                        debug_dump(rbuf,actlen);
                }
        }
-       
+
        up(&dib->usb_sem);
        return ret;
 }
@@ -63,15 +57,18 @@ int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
 /*
  * Cypress controls
  */
+int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
+{
+       return dibusb_readwrite_usb(dib,buf,len,NULL,0);
+}
 
 #if 0
-/* 
- * #if 0'ing the following functions as they are not in use _now_, 
+/*
+ * #if 0'ing the following functions as they are not in use _now_,
  * but probably will be sometime.
  */
-
 /*
- * do not use this, just a workaround for a bug, 
+ * do not use this, just a workaround for a bug,
  * which will hopefully never occur :).
  */
 int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
@@ -79,15 +76,10 @@ int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
        u8 b[1] = { DIBUSB_REQ_INTR_READ };
        return dibusb_write_usb(dib,b,1);
 }
-
-#endif 
-static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
-{
-       return dibusb_readwrite_usb(dib,buf,len,NULL,0);
-}
+#endif
 
 /*
- * ioctl for the firmware 
+ * ioctl for the firmware
  */
 static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
 {
@@ -111,11 +103,18 @@ int dibusb_hw_wakeup(struct dvb_frontend *fe)
        struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
        u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
        deb_info("dibusb-device is getting up.\n");
-       dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-       
+
+       switch (dib->dibdev->dev_cl->id) {
+               case DTT200U:
+                       break;
+               default:
+                       dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+                       break;
+       }
+
        if (dib->fe_init)
                return dib->fe_init(fe);
-       
+
        return 0;
 }
 
@@ -124,11 +123,19 @@ int dibusb_hw_sleep(struct dvb_frontend *fe)
        struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
        u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
        deb_info("dibusb-device is going to bed.\n");
-       dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
-
+       /* workaround, something is wrong, when dibusb 1.1 device are going to bed too late */
+       switch (dib->dibdev->dev_cl->id) {
+               case DIBUSB1_1:
+               case NOVAT_USB2:
+               case DTT200U:
+                       break;
+               default:
+                       dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+                       break;
+       }
        if (dib->fe_sleep)
                return dib->fe_sleep(fe);
-       
+
        return 0;
 }
 
@@ -138,18 +145,57 @@ int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode)
        return dibusb_readwrite_usb(dib,b,2,NULL,0);
 }
 
+static int dibusb_urb_kill(struct usb_dibusb *dib)
+{
+       int i;
+deb_info("trying to kill urbs\n");
+       if (dib->init_state & DIBUSB_STATE_URB_SUBMIT) {
+               for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
+                       deb_info("killing URB no. %d.\n",i);
+
+                       /* stop the URB */
+                       usb_kill_urb(dib->urb_list[i]);
+               }
+       } else
+       deb_info(" URBs not killed.\n");
+       dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
+       return 0;
+}
+
+static int dibusb_urb_submit(struct usb_dibusb *dib)
+{
+       int i,ret;
+       if (dib->init_state & DIBUSB_STATE_URB_INIT) {
+               for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
+                       deb_info("submitting URB no. %d\n",i);
+                       if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
+                               err("could not submit buffer urb no. %d - get them all back\n",i);
+                               dibusb_urb_kill(dib);
+                               return ret;
+                       }
+                       dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
+               }
+       }
+       return 0;
+}
+
 int dibusb_streaming(struct usb_dibusb *dib,int onoff)
 {
+       if (onoff)
+               dibusb_urb_submit(dib);
+       else
+               dibusb_urb_kill(dib);
+
        switch (dib->dibdev->dev_cl->id) {
                case DIBUSB2_0:
+               case DIBUSB2_0B:
+               case NOVAT_USB2:
+               case UMT2_0:
                        if (onoff)
                                return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
                        else
                                return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
                        break;
-               case UMT2_0: 
-                       return dibusb_set_streaming_mode(dib,onoff);
-                       break;
                default:
                        break;
        }
@@ -158,10 +204,10 @@ int dibusb_streaming(struct usb_dibusb *dib,int onoff)
 
 int dibusb_urb_init(struct usb_dibusb *dib)
 {
-       int ret,i,bufsize,def_pid_parse = 1;
-       
+       int i,bufsize,def_pid_parse = 1;
+
        /*
-        * when reloading the driver w/o replugging the device 
+        * when reloading the driver w/o replugging the device
         * a timeout occures, this helps
         */
        usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
@@ -175,7 +221,7 @@ int dibusb_urb_init(struct usb_dibusb *dib)
        memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
 
        dib->init_state |= DIBUSB_STATE_URB_LIST;
-       
+
        bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
        deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
        /* allocate the actual buffer for the URBs */
@@ -185,7 +231,7 @@ int dibusb_urb_init(struct usb_dibusb *dib)
        }
        deb_info("allocation complete\n");
        memset(dib->buffer,0,bufsize);
-       
+
        dib->init_state |= DIBUSB_STATE_URB_BUF;
 
        /* allocate and submit the URBs */
@@ -193,55 +239,49 @@ int dibusb_urb_init(struct usb_dibusb *dib)
                if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
                        return -ENOMEM;
                }
-               deb_info("submitting URB no. %d\n",i);
-               
-               usb_fill_bulk_urb( dib->urb_list[i], dib->udev, 
+
+               usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
                                usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
-                               &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size], 
-                               dib->dibdev->dev_cl->urb_buffer_size, 
+                               &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size],
+                               dib->dibdev->dev_cl->urb_buffer_size,
                                dibusb_urb_complete, dib);
-               
+
                dib->urb_list[i]->transfer_flags = 0;
 
-               if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
-                       err("could not submit buffer urb no. %d\n",i);
-                       return ret;
-               }
-               dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
+               dib->init_state |= DIBUSB_STATE_URB_INIT;
        }
 
        /* dib->pid_parse here contains the value of the module parameter */
        /* decide if pid parsing can be deactivated:
-        * is possible (by speed) and wanted (by user)
+        * is possible (by device type) and wanted (by user)
         */
        switch (dib->dibdev->dev_cl->id) {
                case DIBUSB2_0:
+               case DIBUSB2_0B:
                        if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) {
                                def_pid_parse = 0;
                                info("running at HIGH speed, will deliver the complete TS.");
                        } else
                                info("will use pid_parsing.");
                        break;
-               default: 
+               default:
                        break;
        }
        /* from here on it contains the device and user decision */
        dib->pid_parse = def_pid_parse;
-       
+
        return 0;
 }
 
 int dibusb_urb_exit(struct usb_dibusb *dib)
 {
        int i;
+
+       dibusb_urb_kill(dib);
+
        if (dib->init_state & DIBUSB_STATE_URB_LIST) {
                for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
                        if (dib->urb_list[i] != NULL) {
-                               deb_info("killing URB no. %d.\n",i);
-
-                               /* stop the URBs */
-                               usb_kill_urb(dib->urb_list[i]);
-                               
                                deb_info("freeing URB no. %d.\n",i);
                                /* free the URBs */
                                usb_free_urb(dib->urb_list[i]);
@@ -249,7 +289,6 @@ int dibusb_urb_exit(struct usb_dibusb *dib)
                }
                /* free the urb array */
                kfree(dib->urb_list);
-               dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
                dib->init_state &= ~DIBUSB_STATE_URB_LIST;
        }
 
@@ -259,5 +298,6 @@ int dibusb_urb_exit(struct usb_dibusb *dib)
                        dib->buffer,dib->dma_handle);
 
        dib->init_state &= ~DIBUSB_STATE_URB_BUF;
+       dib->init_state &= ~DIBUSB_STATE_URB_INIT;
        return 0;
 }