firedtv: cleanups and minor fixes
[linux-2.6-block.git] / drivers / media / dvb / firesat / firesat_1394.c
index a13fbe6b3a3c46d55629291f0134bd1338c9d1ab..82bd9786571d229ec159d8e596778a97552eca05 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/types.h>
-#include <asm/atomic.h>
 
 #include <dmxdev.h>
 #include <dvb_demux.h>
 #include "firesat-ci.h"
 #include "firesat-rc.h"
 
-#define FIRESAT_Vendor_ID   0x001287
+#define MATCH_FLAGS    IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
+                       IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION
+#define DIGITAL_EVERYWHERE_OUI   0x001287
 
 static struct ieee1394_device_id firesat_id_table[] = {
 
        {
                /* FloppyDTV S/CI and FloppyDTV S2 */
-               .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
-               .model_id = 0x000024,
-               .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000024,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
        },{
                /* FloppyDTV T/CI */
-               .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
-               .model_id = 0x000025,
-               .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000025,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
        },{
                /* FloppyDTV C/CI */
-               .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
-               .model_id = 0x000026,
-               .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000026,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
        },{
                /* FireDTV S/CI and FloppyDTV S2 */
-               .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
-               .model_id = 0x000034,
-               .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000034,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
        },{
                /* FireDTV T/CI */
-               .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
-               .model_id = 0x000035,
-               .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000035,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
        },{
                /* FireDTV C/CI */
-               .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
-               .model_id = 0x000036,
-               .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000036,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
        }, { }
 };
 
@@ -98,8 +111,8 @@ static void fcp_request(struct hpsb_host *host,
 
                spin_lock_irqsave(&firesat_list_lock, flags);
                list_for_each_entry(firesat_entry,&firesat_list,list) {
-                       if (firesat_entry->host == host &&
-                           firesat_entry->nodeentry->nodeid == nodeid &&
+                       if (firesat_entry->ud->ne->host == host &&
+                           firesat_entry->ud->ne->nodeid == nodeid &&
                            (firesat_entry->subunit == (data[1]&0x7) ||
                             (firesat_entry->subunit == 0 &&
                              (data[1]&0x7) == 0x7))) {
@@ -110,12 +123,8 @@ static void fcp_request(struct hpsb_host *host,
                spin_unlock_irqrestore(&firesat_list_lock, flags);
 
                if (firesat)
-                       AVCRecv(firesat,data,length);
-               else
-                       printk("%s: received fcp request from unknown source, ignored\n", __func__);
+                       avc_recv(firesat, data, length);
        }
-       else
-         printk("%s: received invalid fcp request, ignored\n", __func__);
 }
 
 const char *firedtv_model_names[] = {
@@ -128,175 +137,108 @@ const char *firedtv_model_names[] = {
 
 static int firesat_probe(struct device *dev)
 {
-       struct unit_directory *ud = container_of(dev, struct unit_directory, device);
+       struct unit_directory *ud =
+                       container_of(dev, struct unit_directory, device);
        struct firesat *firesat;
-       struct dvb_frontend *fe;
        unsigned long flags;
-       unsigned char subunitcount = 0xff, subunit;
-       struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL);
        int kv_len;
+       void *kv_str;
        int i;
-       char *kv_buf;
+       int err = -ENOMEM;
 
-       if (!firesats) {
-               printk("%s: couldn't allocate memory.\n", __func__);
+       firesat = kzalloc(sizeof(*firesat), GFP_KERNEL);
+       if (!firesat)
                return -ENOMEM;
-       }
-
-//    printk(KERN_INFO "FireSAT: Detected device with GUID %08lx%04lx%04lx\n",(unsigned long)((ud->ne->guid)>>32),(unsigned long)(ud->ne->guid & 0xFFFF),(unsigned long)ud->ne->guid_vendor_id);
-       printk(KERN_INFO "%s: loading device\n", __func__);
-
-       firesats[0] = NULL;
-       firesats[1] = NULL;
-
-       ud->device.driver_data = firesats;
-
-       for (subunit = 0; subunit < subunitcount; subunit++) {
-
-               if (!(firesat = kmalloc(sizeof (struct firesat), GFP_KERNEL)) ||
-                   !(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) {
-
-                       printk("%s: couldn't allocate memory.\n", __func__);
-                       kfree(firesats);
-                       return -ENOMEM;
-               }
-
-               memset(firesat, 0, sizeof (struct firesat));
-
-               firesat->host           = ud->ne->host;
-               firesat->guid           = ud->ne->guid;
-               firesat->guid_vendor_id = ud->ne->guid_vendor_id;
-               firesat->nodeentry      = ud->ne;
-               firesat->isochannel     = -1;
-               firesat->tone           = 0xff;
-               firesat->voltage        = 0xff;
-               firesat->fe             = fe;
-
-               if (!(firesat->respfrm = kmalloc(sizeof (AVCRspFrm), GFP_KERNEL))) {
-                       printk("%s: couldn't allocate memory.\n", __func__);
-                       kfree(firesat);
-                       return -ENOMEM;
-               }
-
-               mutex_init(&firesat->avc_mutex);
-               init_waitqueue_head(&firesat->avc_wait);
-               atomic_set(&firesat->avc_reply_received, 1);
-               mutex_init(&firesat->demux_mutex);
-               INIT_WORK(&firesat->remote_ctrl_work, avc_remote_ctrl_work);
-
-               spin_lock_irqsave(&firesat_list_lock, flags);
-               INIT_LIST_HEAD(&firesat->list);
-               list_add_tail(&firesat->list, &firesat_list);
-               spin_unlock_irqrestore(&firesat_list_lock, flags);
-
-               if (subunit == 0) {
-                       firesat->subunit = 0x7; // 0x7 = don't care
-                       if (AVCSubUnitInfo(firesat, &subunitcount)) {
-                               printk("%s: AVC subunit info command failed.\n",__func__);
-                               spin_lock_irqsave(&firesat_list_lock, flags);
-                               list_del(&firesat->list);
-                               spin_unlock_irqrestore(&firesat_list_lock, flags);
-                               kfree(firesat);
-                               return -EIO;
-                       }
-               }
-
-               printk(KERN_INFO "%s: subunit count = %d\n", __func__, subunitcount);
-
-               firesat->subunit = subunit;
-
-               /* Reading device model from ROM */
-               kv_len = (ud->model_name_kv->value.leaf.len - 2) *
-                       sizeof(quadlet_t);
-               kv_buf = kmalloc((sizeof(quadlet_t) * kv_len), GFP_KERNEL);
-               memcpy(kv_buf,
-                       CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv),
-                       kv_len);
-               while ((kv_buf + kv_len - 1) == '\0') kv_len--;
-               kv_buf[kv_len++] = '\0';
 
-               for (i = ARRAY_SIZE(firedtv_model_names); --i;)
-                       if (strcmp(kv_buf, firedtv_model_names[i]) == 0)
-                               break;
-               firesat->type = i;
-               kfree(kv_buf);
-
-               if (AVCIdentifySubunit(firesat)) {
-                       printk("%s: cannot identify subunit %d\n", __func__, subunit);
-                       spin_lock_irqsave(&firesat_list_lock, flags);
-                       list_del(&firesat->list);
-                       spin_unlock_irqrestore(&firesat_list_lock, flags);
-                       kfree(firesat);
-                       continue;
-               }
+       dev->driver_data = firesat;
+       firesat->ud             = ud;
+       firesat->subunit        = 0;
+       firesat->isochannel     = -1;
+       firesat->tone           = 0xff;
+       firesat->voltage        = 0xff;
+
+       mutex_init(&firesat->avc_mutex);
+       init_waitqueue_head(&firesat->avc_wait);
+       firesat->avc_reply_received = true;
+       mutex_init(&firesat->demux_mutex);
+       INIT_WORK(&firesat->remote_ctrl_work, avc_remote_ctrl_work);
+
+       /* Reading device model from ROM */
+       kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
+       kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
+       for (i = ARRAY_SIZE(firedtv_model_names); --i;)
+               if (strlen(firedtv_model_names[i]) <= kv_len &&
+                   strncmp(kv_str, firedtv_model_names[i], kv_len) == 0)
+                       break;
+       firesat->type = i;
+
+       /*
+        * Work around a bug in udev's path_id script:  Use the fw-host's dev
+        * instead of the unit directory's dev as parent of the input device.
+        */
+       err = firesat_register_rc(firesat, dev->parent->parent);
+       if (err)
+               goto fail_free;
+
+       INIT_LIST_HEAD(&firesat->list);
+       spin_lock_irqsave(&firesat_list_lock, flags);
+       list_add_tail(&firesat->list, &firesat_list);
+       spin_unlock_irqrestore(&firesat_list_lock, flags);
+
+       err = avc_identify_subunit(firesat);
+       if (err)
+               goto fail;
 
-// ----
-               /* FIXME: check for error return */
-               firesat_dvbdev_init(firesat, dev, fe);
-// ----
-               firesats[subunit] = firesat;
-       } // loop for all tuners
+       err = firesat_dvbdev_init(firesat, dev);
+       if (err)
+               goto fail;
 
-       if (firesats[0])
-               AVCRegisterRemoteControl(firesats[0]);
+       avc_register_remote_control(firesat);
+       return 0;
 
-    return 0;
+fail:
+       spin_lock_irqsave(&firesat_list_lock, flags);
+       list_del(&firesat->list);
+       spin_unlock_irqrestore(&firesat_list_lock, flags);
+       firesat_unregister_rc(firesat);
+fail_free:
+       kfree(firesat);
+       return err;
 }
 
 static int firesat_remove(struct device *dev)
 {
-       struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-       struct firesat **firesats = ud->device.driver_data;
-       int k;
+       struct firesat *firesat = dev->driver_data;
        unsigned long flags;
 
-       if (firesats) {
-               for (k = 0; k < 2; k++)
-                       if (firesats[k]) {
-                                       firesat_ca_release(firesats[k]);
-
-                               dvb_unregister_frontend(firesats[k]->fe);
-                               dvb_net_release(&firesats[k]->dvbnet);
-                               firesats[k]->demux.dmx.close(&firesats[k]->demux.dmx);
-                               firesats[k]->demux.dmx.remove_frontend(&firesats[k]->demux.dmx, &firesats[k]->frontend);
-                               dvb_dmxdev_release(&firesats[k]->dmxdev);
-                               dvb_dmx_release(&firesats[k]->demux);
-                               dvb_unregister_adapter(firesats[k]->adapter);
-
-                               spin_lock_irqsave(&firesat_list_lock, flags);
-                               list_del(&firesats[k]->list);
-                               spin_unlock_irqrestore(&firesat_list_lock, flags);
-
-                               cancel_work_sync(&firesats[k]->remote_ctrl_work);
-
-                               kfree(firesats[k]->fe);
-                               kfree(firesats[k]->adapter);
-                               kfree(firesats[k]->respfrm);
-                               kfree(firesats[k]);
-                       }
-               kfree(firesats);
-       } else
-               printk("%s: can't get firesat handle\n", __func__);
+       firesat_ca_release(firesat);
+       dvb_unregister_frontend(&firesat->fe);
+       dvb_net_release(&firesat->dvbnet);
+       firesat->demux.dmx.close(&firesat->demux.dmx);
+       firesat->demux.dmx.remove_frontend(&firesat->demux.dmx,
+                                          &firesat->frontend);
+       dvb_dmxdev_release(&firesat->dmxdev);
+       dvb_dmx_release(&firesat->demux);
+       dvb_unregister_adapter(&firesat->adapter);
+
+       spin_lock_irqsave(&firesat_list_lock, flags);
+       list_del(&firesat->list);
+       spin_unlock_irqrestore(&firesat_list_lock, flags);
 
-       printk(KERN_INFO "FireSAT: Removing device with vendor id 0x%x, model id 0x%x.\n",ud->vendor_id,ud->model_id);
+       cancel_work_sync(&firesat->remote_ctrl_work);
+       firesat_unregister_rc(firesat);
 
+       kfree(firesat);
        return 0;
 }
 
 static int firesat_update(struct unit_directory *ud)
 {
-       struct firesat **firesats = ud->device.driver_data;
-       int k;
-       // loop over subunits
-
-       for (k = 0; k < 2; k++)
-               if (firesats[k]) {
-                       firesats[k]->nodeentry = ud->ne;
-
-                       if (firesats[k]->isochannel >= 0)
-                               try_CMPEstablishPPconnection(firesats[k], firesats[k]->subunit, firesats[k]->isochannel);
-               }
+       struct firesat *firesat = ud->device.driver_data;
 
+       if (firesat->isochannel >= 0)
+               cmp_establish_pp_connection(firesat, firesat->subunit,
+                                           firesat->isochannel);
        return 0;
 }
 
@@ -328,26 +270,13 @@ static int __init firesat_init(void)
        ret = hpsb_register_protocol(&firesat_driver);
        if (ret) {
                printk(KERN_ERR "firedtv: failed to register protocol\n");
-               goto fail;
-       }
-
-       ret = firesat_register_rc();
-       if (ret) {
-               printk(KERN_ERR "firedtv: failed to register input device\n");
-               goto fail_rc;
+               hpsb_unregister_highlevel(&firesat_highlevel);
        }
-
-       return 0;
-fail_rc:
-       hpsb_unregister_protocol(&firesat_driver);
-fail:
-       hpsb_unregister_highlevel(&firesat_highlevel);
        return ret;
 }
 
 static void __exit firesat_exit(void)
 {
-       firesat_unregister_rc();
        hpsb_unregister_protocol(&firesat_driver);
        hpsb_unregister_highlevel(&firesat_highlevel);
 }