fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / media / dvb / dvb-usb / dvb-usb-init.c
index ce34a55..ffdde83 100644 (file)
@@ -3,7 +3,7 @@
  *
  * dvb-usb-init.c
  *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
  *
  *     This program is free software; you can redistribute it and/or modify it
  *     under the terms of the GNU General Public License as published by the Free
 /* debug */
 int dvb_usb_debug;
 module_param_named(debug,dvb_usb_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256  (or-able))." DVB_USB_DEBUG_STATUS);
 
 int dvb_usb_disable_rc_polling;
 module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
 MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
 
+static int dvb_usb_force_pid_filter_usage;
+module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
+MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+
+static int dvb_usb_adapter_init(struct dvb_usb_device *d)
+{
+       struct dvb_usb_adapter *adap;
+       int ret,n;
+
+       for (n = 0; n < d->props.num_adapters; n++) {
+               adap = &d->adapter[n];
+               adap->dev = d;
+               adap->id  = n;
+
+               memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
+
+/* speed - when running at FULL speed we need a HW PID filter */
+               if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+                       err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
+                       return -ENODEV;
+               }
+
+               if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+                       (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+                       info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count);
+                       adap->pid_filtering  = 1;
+                       adap->max_feed_count = adap->props.pid_filter_count;
+               } else {
+                       info("will pass the complete MPEG2 transport stream to the software demuxer.");
+                       adap->pid_filtering  = 0;
+                       adap->max_feed_count = 255;
+               }
+
+               if (!adap->pid_filtering &&
+                       dvb_usb_force_pid_filter_usage &&
+                       adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+                       info("pid filter enabled by module option.");
+                       adap->pid_filtering  = 1;
+                       adap->max_feed_count = adap->props.pid_filter_count;
+               }
+
+               if (adap->props.size_of_priv > 0) {
+                       adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL);
+                       if (adap->priv == NULL) {
+                               err("no memory for priv for adapter %d.",n);
+                               return -ENOMEM;
+                       }
+               }
+
+               if ((ret = dvb_usb_adapter_stream_init(adap)) ||
+                       (ret = dvb_usb_adapter_dvb_init(adap)) ||
+                       (ret = dvb_usb_adapter_frontend_init(adap))) {
+                       return ret;
+               }
+
+               d->num_adapters_initialized++;
+               d->state |= DVB_USB_STATE_DVB;
+       }
+
+       /*
+        * when reloading the driver w/o replugging the device
+        * sometimes a timeout occures, this helps
+        */
+       if (d->props.generic_bulk_ctrl_endpoint != 0) {
+               usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+               usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+       }
+
+       return 0;
+}
+
+static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
+{
+       int n;
+       for (n = 0; n < d->num_adapters_initialized; n++) {
+               dvb_usb_adapter_frontend_exit(&d->adapter[n]);
+               dvb_usb_adapter_dvb_exit(&d->adapter[n]);
+               dvb_usb_adapter_stream_exit(&d->adapter[n]);
+               kfree(d->adapter[n].priv);
+       }
+       d->num_adapters_initialized = 0;
+       d->state &= ~DVB_USB_STATE_DVB;
+       return 0;
+}
+
+
 /* general initialization functions */
 static int dvb_usb_exit(struct dvb_usb_device *d)
 {
        deb_info("state before exiting everything: %x\n",d->state);
        dvb_usb_remote_exit(d);
-       dvb_usb_fe_exit(d);
+       dvb_usb_adapter_exit(d);
        dvb_usb_i2c_exit(d);
-       dvb_usb_dvb_exit(d);
-       dvb_usb_urb_exit(d);
        deb_info("state should be zero now: %x\n",d->state);
        d->state = DVB_USB_STATE_INIT;
        kfree(d->priv);
@@ -42,37 +126,24 @@ static int dvb_usb_init(struct dvb_usb_device *d)
 {
        int ret = 0;
 
-       sema_init(&d->usb_sem, 1);
-       sema_init(&d->i2c_sem, 1);
+       mutex_init(&d->usb_mutex);
+       mutex_init(&d->i2c_mutex);
 
        d->state = DVB_USB_STATE_INIT;
 
-/* check the capabilities and set appropriate variables */
-
-/* speed - when running at FULL speed we need a HW PID filter */
-       if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) {
-               err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
-               return -ENODEV;
-       }
-
-       if ((d->udev->speed == USB_SPEED_FULL && d->props.caps & DVB_USB_HAS_PID_FILTER) ||
-               (d->props.caps & DVB_USB_NEED_PID_FILTERING)) {
-               info("will use the device's hardware PID filter (table count: %d).",d->props.pid_filter_count);
-               d->pid_filtering = 1;
-               d->max_feed_count = d->props.pid_filter_count;
-       } else {
-               info("will pass the complete MPEG2 transport stream to the software demuxer.");
-               d->pid_filtering = 0;
-               d->max_feed_count = 255;
+       if (d->props.size_of_priv > 0) {
+               d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
+               if (d->priv == NULL) {
+                       err("no memory for priv in 'struct dvb_usb_device'");
+                       return -ENOMEM;
+               }
        }
 
-       if (d->props.power_ctrl)
-               d->props.power_ctrl(d,1);
+/* check the capabilities and set appropriate variables */
+       dvb_usb_device_power_ctrl(d, 1);
 
-       if ((ret = dvb_usb_urb_init(d)) ||
-               (ret = dvb_usb_dvb_init(d)) ||
-               (ret = dvb_usb_i2c_init(d)) ||
-               (ret = dvb_usb_fe_init(d))) {
+       if ((ret = dvb_usb_i2c_init(d)) ||
+               (ret = dvb_usb_adapter_init(d))) {
                dvb_usb_exit(d);
                return ret;
        }
@@ -80,14 +151,13 @@ static int dvb_usb_init(struct dvb_usb_device *d)
        if ((ret = dvb_usb_remote_init(d)))
                err("could not initialize remote control.");
 
-       if (d->props.power_ctrl)
-               d->props.power_ctrl(d,0);
+       dvb_usb_device_power_ctrl(d, 0);
 
        return 0;
 }
 
 /* determine the name and the state of the just found USB device */
-static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_properties *props, int *cold)
+static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold)
 {
        int i,j;
        struct dvb_usb_device_description *desc = NULL;
@@ -125,11 +195,25 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device
        return desc;
 }
 
+int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       if (onoff)
+               d->powered++;
+       else
+               d->powered--;
+
+       if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1
+               deb_info("power control: %d\n", onoff);
+               if (d->props.power_ctrl)
+                       return d->props.power_ctrl(d, onoff);
+       }
+       return 0;
+}
+
 /*
  * USB
  */
-
-int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
+int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_device_properties
                *props, struct module *owner,struct dvb_usb_device **du)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
@@ -149,7 +233,7 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
        if (cold) {
                info("found a '%s' in cold state, will try to load a firmware",desc->name);
                ret = dvb_usb_download_firmware(udev,props);
-               if (!props->no_reconnect)
+               if (!props->no_reconnect || ret != 0)
                        return ret;
        }
 
@@ -161,19 +245,10 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
        }
 
        d->udev = udev;
-       memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
+       memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties));
        d->desc = desc;
        d->owner = owner;
 
-       if (d->props.size_of_priv > 0) {
-                       d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
-               if (d->priv == NULL) {
-                       err("no memory for priv in 'struct dvb_usb_device'");
-                       kfree(d);
-                       return -ENOMEM;
-               }
-       }
-
        usb_set_intfdata(intf, d);
 
        if (du != NULL)
@@ -204,7 +279,7 @@ void dvb_usb_device_exit(struct usb_interface *intf)
 }
 EXPORT_SYMBOL(dvb_usb_device_exit);
 
-MODULE_VERSION("0.3");
+MODULE_VERSION("1.0");
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
 MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
 MODULE_LICENSE("GPL");