2 * FireDTV driver (formerly known as FireSAT)
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
6 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
14 #include <linux/device.h>
15 #include <linux/errno.h>
16 #include <linux/kernel.h>
17 #include <linux/list.h>
18 #include <linux/module.h>
19 #include <linux/mutex.h>
20 #include <linux/slab.h>
21 #include <linux/spinlock.h>
22 #include <linux/string.h>
23 #include <linux/types.h>
24 #include <asm/atomic.h>
27 #include <dvb_demux.h>
28 #include <dvb_frontend.h>
32 #include <highlevel.h>
34 #include <ieee1394_hotplug.h>
40 #include "firesat-ci.h"
41 #include "firesat-rc.h"
43 #define FIRESAT_Vendor_ID 0x001287
45 static struct ieee1394_device_id firesat_id_table[] = {
48 /* FloppyDTV S/CI and FloppyDTV S2 */
49 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
51 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
54 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
56 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
59 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
61 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
63 /* FireDTV S/CI and FloppyDTV S2 */
64 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
66 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
69 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
71 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
74 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
76 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
80 MODULE_DEVICE_TABLE(ieee1394, firesat_id_table);
82 /* list of all firesat devices */
83 LIST_HEAD(firesat_list);
84 spinlock_t firesat_list_lock = SPIN_LOCK_UNLOCKED;
86 static void fcp_request(struct hpsb_host *host,
93 struct firesat *firesat = NULL;
94 struct firesat *firesat_entry;
97 if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) {
99 spin_lock_irqsave(&firesat_list_lock, flags);
100 list_for_each_entry(firesat_entry,&firesat_list,list) {
101 if (firesat_entry->host == host &&
102 firesat_entry->nodeentry->nodeid == nodeid &&
103 (firesat_entry->subunit == (data[1]&0x7) ||
104 (firesat_entry->subunit == 0 &&
105 (data[1]&0x7) == 0x7))) {
106 firesat=firesat_entry;
110 spin_unlock_irqrestore(&firesat_list_lock, flags);
113 AVCRecv(firesat,data,length);
115 printk("%s: received fcp request from unknown source, ignored\n", __func__);
118 printk("%s: received invalid fcp request, ignored\n", __func__);
121 const char *firedtv_model_names[] = {
122 [FireSAT_UNKNOWN] = "unknown type",
123 [FireSAT_DVB_S] = "FireDTV S/CI",
124 [FireSAT_DVB_C] = "FireDTV C/CI",
125 [FireSAT_DVB_T] = "FireDTV T/CI",
126 [FireSAT_DVB_S2] = "FireDTV S2 ",
129 static int firesat_probe(struct device *dev)
131 struct unit_directory *ud = container_of(dev, struct unit_directory, device);
132 struct firesat *firesat;
133 struct dvb_frontend *fe;
135 unsigned char subunitcount = 0xff, subunit;
136 struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL);
142 printk("%s: couldn't allocate memory.\n", __func__);
146 // 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);
147 printk(KERN_INFO "%s: loading device\n", __func__);
152 ud->device.driver_data = firesats;
154 for (subunit = 0; subunit < subunitcount; subunit++) {
156 if (!(firesat = kmalloc(sizeof (struct firesat), GFP_KERNEL)) ||
157 !(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) {
159 printk("%s: couldn't allocate memory.\n", __func__);
164 memset(firesat, 0, sizeof (struct firesat));
166 firesat->host = ud->ne->host;
167 firesat->guid = ud->ne->guid;
168 firesat->guid_vendor_id = ud->ne->guid_vendor_id;
169 firesat->nodeentry = ud->ne;
170 firesat->isochannel = -1;
171 firesat->tone = 0xff;
172 firesat->voltage = 0xff;
175 if (!(firesat->respfrm = kmalloc(sizeof (AVCRspFrm), GFP_KERNEL))) {
176 printk("%s: couldn't allocate memory.\n", __func__);
181 mutex_init(&firesat->avc_mutex);
182 init_waitqueue_head(&firesat->avc_wait);
183 atomic_set(&firesat->avc_reply_received, 1);
184 mutex_init(&firesat->demux_mutex);
185 INIT_WORK(&firesat->remote_ctrl_work, avc_remote_ctrl_work);
187 spin_lock_irqsave(&firesat_list_lock, flags);
188 INIT_LIST_HEAD(&firesat->list);
189 list_add_tail(&firesat->list, &firesat_list);
190 spin_unlock_irqrestore(&firesat_list_lock, flags);
193 firesat->subunit = 0x7; // 0x7 = don't care
194 if (AVCSubUnitInfo(firesat, &subunitcount)) {
195 printk("%s: AVC subunit info command failed.\n",__func__);
196 spin_lock_irqsave(&firesat_list_lock, flags);
197 list_del(&firesat->list);
198 spin_unlock_irqrestore(&firesat_list_lock, flags);
204 printk(KERN_INFO "%s: subunit count = %d\n", __func__, subunitcount);
206 firesat->subunit = subunit;
208 /* Reading device model from ROM */
209 kv_len = (ud->model_name_kv->value.leaf.len - 2) *
211 kv_buf = kmalloc((sizeof(quadlet_t) * kv_len), GFP_KERNEL);
213 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv),
215 while ((kv_buf + kv_len - 1) == '\0') kv_len--;
216 kv_buf[kv_len++] = '\0';
218 for (i = ARRAY_SIZE(firedtv_model_names); --i;)
219 if (strcmp(kv_buf, firedtv_model_names[i]) == 0)
224 if (AVCIdentifySubunit(firesat)) {
225 printk("%s: cannot identify subunit %d\n", __func__, subunit);
226 spin_lock_irqsave(&firesat_list_lock, flags);
227 list_del(&firesat->list);
228 spin_unlock_irqrestore(&firesat_list_lock, flags);
234 /* FIXME: check for error return */
235 firesat_dvbdev_init(firesat, dev, fe);
237 firesats[subunit] = firesat;
238 } // loop for all tuners
241 AVCRegisterRemoteControl(firesats[0]);
246 static int firesat_remove(struct device *dev)
248 struct unit_directory *ud = container_of(dev, struct unit_directory, device);
249 struct firesat **firesats = ud->device.driver_data;
254 for (k = 0; k < 2; k++)
256 firesat_ca_release(firesats[k]);
258 dvb_unregister_frontend(firesats[k]->fe);
259 dvb_net_release(&firesats[k]->dvbnet);
260 firesats[k]->demux.dmx.close(&firesats[k]->demux.dmx);
261 firesats[k]->demux.dmx.remove_frontend(&firesats[k]->demux.dmx, &firesats[k]->frontend);
262 dvb_dmxdev_release(&firesats[k]->dmxdev);
263 dvb_dmx_release(&firesats[k]->demux);
264 dvb_unregister_adapter(firesats[k]->adapter);
266 spin_lock_irqsave(&firesat_list_lock, flags);
267 list_del(&firesats[k]->list);
268 spin_unlock_irqrestore(&firesat_list_lock, flags);
270 cancel_work_sync(&firesats[k]->remote_ctrl_work);
272 kfree(firesats[k]->fe);
273 kfree(firesats[k]->adapter);
274 kfree(firesats[k]->respfrm);
279 printk("%s: can't get firesat handle\n", __func__);
281 printk(KERN_INFO "FireSAT: Removing device with vendor id 0x%x, model id 0x%x.\n",ud->vendor_id,ud->model_id);
286 static int firesat_update(struct unit_directory *ud)
288 struct firesat **firesats = ud->device.driver_data;
290 // loop over subunits
292 for (k = 0; k < 2; k++)
294 firesats[k]->nodeentry = ud->ne;
296 if (firesats[k]->isochannel >= 0)
297 try_CMPEstablishPPconnection(firesats[k], firesats[k]->subunit, firesats[k]->isochannel);
303 static struct hpsb_protocol_driver firesat_driver = {
306 .id_table = firesat_id_table,
307 .update = firesat_update,
310 //.name and .bus are filled in for us in more recent linux versions
312 //.bus = &ieee1394_bus_type,
313 .probe = firesat_probe,
314 .remove = firesat_remove,
318 static struct hpsb_highlevel firesat_highlevel = {
320 .fcp_request = fcp_request,
323 static int __init firesat_init(void)
327 hpsb_register_highlevel(&firesat_highlevel);
328 ret = hpsb_register_protocol(&firesat_driver);
330 printk(KERN_ERR "firedtv: failed to register protocol\n");
334 ret = firesat_register_rc();
336 printk(KERN_ERR "firedtv: failed to register input device\n");
342 hpsb_unregister_protocol(&firesat_driver);
344 hpsb_unregister_highlevel(&firesat_highlevel);
348 static void __exit firesat_exit(void)
350 firesat_unregister_rc();
351 hpsb_unregister_protocol(&firesat_driver);
352 hpsb_unregister_highlevel(&firesat_highlevel);
355 module_init(firesat_init);
356 module_exit(firesat_exit);
358 MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
359 MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
360 MODULE_DESCRIPTION("FireDTV DVB Driver");
361 MODULE_LICENSE("GPL");
362 MODULE_SUPPORTED_DEVICE("FireDTV DVB");