aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/dvb/firesat/firesat_1394.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/firesat/firesat_1394.c')
-rw-r--r--drivers/media/dvb/firesat/firesat_1394.c301
1 files changed, 115 insertions, 186 deletions
diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c
index a13fbe6b3a3..82bd9786571 100644
--- a/drivers/media/dvb/firesat/firesat_1394.c
+++ b/drivers/media/dvb/firesat/firesat_1394.c
@@ -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>
@@ -40,40 +39,54 @@
#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);
}