|
@@ -21,7 +21,6 @@
|
|
#include <linux/spinlock.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/string.h>
|
|
#include <linux/string.h>
|
|
#include <linux/types.h>
|
|
#include <linux/types.h>
|
|
-#include <asm/atomic.h>
|
|
|
|
|
|
|
|
#include <dmxdev.h>
|
|
#include <dmxdev.h>
|
|
#include <dvb_demux.h>
|
|
#include <dvb_demux.h>
|
|
@@ -40,40 +39,54 @@
|
|
#include "firesat-ci.h"
|
|
#include "firesat-ci.h"
|
|
#include "firesat-rc.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[] = {
|
|
static struct ieee1394_device_id firesat_id_table[] = {
|
|
|
|
|
|
{
|
|
{
|
|
/* FloppyDTV S/CI and FloppyDTV S2 */
|
|
/* 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 */
|
|
/* 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 */
|
|
/* 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 */
|
|
/* 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 */
|
|
/* 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 */
|
|
/* 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);
|
|
spin_lock_irqsave(&firesat_list_lock, flags);
|
|
list_for_each_entry(firesat_entry,&firesat_list,list) {
|
|
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 == (data[1]&0x7) ||
|
|
(firesat_entry->subunit == 0 &&
|
|
(firesat_entry->subunit == 0 &&
|
|
(data[1]&0x7) == 0x7))) {
|
|
(data[1]&0x7) == 0x7))) {
|
|
@@ -110,12 +123,8 @@ static void fcp_request(struct hpsb_host *host,
|
|
spin_unlock_irqrestore(&firesat_list_lock, flags);
|
|
spin_unlock_irqrestore(&firesat_list_lock, flags);
|
|
|
|
|
|
if (firesat)
|
|
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[] = {
|
|
const char *firedtv_model_names[] = {
|
|
@@ -128,175 +137,108 @@ const char *firedtv_model_names[] = {
|
|
|
|
|
|
static int firesat_probe(struct device *dev)
|
|
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 firesat *firesat;
|
|
- struct dvb_frontend *fe;
|
|
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
- unsigned char subunitcount = 0xff, subunit;
|
|
|
|
- struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL);
|
|
|
|
int kv_len;
|
|
int kv_len;
|
|
|
|
+ void *kv_str;
|
|
int i;
|
|
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;
|
|
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)
|
|
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;
|
|
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;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int firesat_update(struct unit_directory *ud)
|
|
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;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -328,26 +270,13 @@ static int __init firesat_init(void)
|
|
ret = hpsb_register_protocol(&firesat_driver);
|
|
ret = hpsb_register_protocol(&firesat_driver);
|
|
if (ret) {
|
|
if (ret) {
|
|
printk(KERN_ERR "firedtv: failed to register protocol\n");
|
|
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;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static void __exit firesat_exit(void)
|
|
static void __exit firesat_exit(void)
|
|
{
|
|
{
|
|
- firesat_unregister_rc();
|
|
|
|
hpsb_unregister_protocol(&firesat_driver);
|
|
hpsb_unregister_protocol(&firesat_driver);
|
|
hpsb_unregister_highlevel(&firesat_highlevel);
|
|
hpsb_unregister_highlevel(&firesat_highlevel);
|
|
}
|
|
}
|