4 * Copyright (c) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (c) 2007-2008 Ben Backx <ben@bbackx.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/wait.h>
16 #include <linux/module.h>
17 #include <linux/delay.h>
18 #include <linux/time.h>
19 #include <linux/errno.h>
20 #include <linux/interrupt.h>
21 #include <linux/semaphore.h>
22 #include <ieee1394_hotplug.h>
24 #include <highlevel.h>
32 #include "firesat-rc.h"
33 #include "firesat-ci.h"
35 #define FIRESAT_Vendor_ID 0x001287
37 static struct ieee1394_device_id firesat_id_table[] = {
40 /* FloppyDTV S/CI and FloppyDTV S2 */
41 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
43 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
46 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
48 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
51 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
53 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
55 /* FireDTV S/CI and FloppyDTV S2 */
56 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
58 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
61 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
63 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
66 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
68 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
72 MODULE_DEVICE_TABLE(ieee1394, firesat_id_table);
74 /* list of all firesat devices */
75 LIST_HEAD(firesat_list);
76 spinlock_t firesat_list_lock = SPIN_LOCK_UNLOCKED;
78 static void firesat_add_host(struct hpsb_host *host);
79 static void firesat_remove_host(struct hpsb_host *host);
80 static void firesat_host_reset(struct hpsb_host *host);
83 static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
87 static void fcp_request(struct hpsb_host *host,
94 static struct hpsb_highlevel firesat_highlevel = {
96 .add_host = firesat_add_host,
97 .remove_host = firesat_remove_host,
98 .host_reset = firesat_host_reset,
99 // FIXME .iso_receive = iso_receive,
100 .fcp_request = fcp_request,
103 static void firesat_add_host (struct hpsb_host *host)
105 struct ti_ohci *ohci = (struct ti_ohci *)host->hostdata;
107 /* We only work with the OHCI-1394 driver */
108 if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
111 if (!hpsb_create_hostinfo(&firesat_highlevel, host, 0)) {
112 printk(KERN_ERR "Cannot allocate hostinfo\n");
116 hpsb_set_hostinfo(&firesat_highlevel, host, ohci);
117 hpsb_set_hostinfo_key(&firesat_highlevel, host, ohci->host->id);
120 static void firesat_remove_host (struct hpsb_host *host)
125 static void firesat_host_reset(struct hpsb_host *host)
127 printk(KERN_INFO "FireSAT host_reset (nodeid = 0x%x, hosts active = %d)\n",host->node_id,host->nodes_active);
130 struct firewireheader {
133 unsigned char tcode:4;
136 unsigned char channel:6;
138 unsigned char length_l;
139 unsigned char length_h;
148 unsigned char syncbits:2;
156 unsigned char syncbits2:2;
158 unsigned long fdf:24;
160 unsigned long long val;
167 unsigned char sync; // must be 0x47
168 unsigned char transport_error_indicator:1;
169 unsigned char payload_unit_start_indicator:1;
170 unsigned char transport_priority:1;
171 unsigned short pid:13;
172 unsigned char transport_scrambling_control:2;
173 unsigned char adaption_field_control:2;
174 unsigned char continuity_counter:4;
181 static void iso_receive(struct hpsb_host *host,
186 struct firesat *firesat = NULL;
187 struct firesat *firesat_entry;
190 // printk(KERN_INFO "FireSAT iso_receive: channel %d, length = %d\n", channel, length);
193 return; // ignore empty packets
196 spin_lock_irqsave(&firesat_list_lock, flags);
197 list_for_each_entry(firesat_entry,&firesat_list,list) {
198 if(firesat_entry->host == host && firesat_entry->isochannel == channel) {
199 firesat=firesat_entry;
203 spin_unlock_irqrestore(&firesat_list_lock, flags);
206 char *buf= ((char*)data) + sizeof(struct firewireheader)+sizeof(struct CIPHeader);
207 int count = (length-sizeof(struct CIPHeader)) / 192;
209 // printk(KERN_INFO "%s: length = %u\n data[0] = %08x\n data[1] = %08x\n data[2] = %08x\n data[3] = %08x\n data[4] = %08x\n",__func__, length, data[0],data[1],data[2],data[3],data[4]);
213 if (buf[sizeof(quadlet_t) /*timestamp*/] == 0x47)
214 dvb_dmx_swfilter_packets(&firesat->demux, &buf[sizeof(quadlet_t)], 1);
216 printk("%s: invalid packet, skipping\n", __func__);
217 buf += 188 + sizeof (quadlet_t) /* timestamp */;
224 static void fcp_request(struct hpsb_host *host,
231 struct firesat *firesat = NULL;
232 struct firesat *firesat_entry;
235 if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) {
237 spin_lock_irqsave(&firesat_list_lock, flags);
238 list_for_each_entry(firesat_entry,&firesat_list,list) {
239 if (firesat_entry->host == host &&
240 firesat_entry->nodeentry->nodeid == nodeid &&
241 (firesat_entry->subunit == (data[1]&0x7) ||
242 (firesat_entry->subunit == 0 &&
243 (data[1]&0x7) == 0x7))) {
244 firesat=firesat_entry;
248 spin_unlock_irqrestore(&firesat_list_lock, flags);
251 AVCRecv(firesat,data,length);
253 printk("%s: received fcp request from unknown source, ignored\n", __func__);
257 static int firesat_probe(struct device *dev)
259 struct unit_directory *ud = container_of(dev, struct unit_directory, device);
260 struct firesat *firesat;
261 struct dvb_frontend *fe;
264 unsigned char subunitcount = 0xff, subunit;
265 struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL);
268 printk("%s: couldn't allocate memory.\n", __func__);
272 // 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);
273 printk(KERN_INFO "%s: loading device\n", __func__);
278 ud->device.driver_data = firesats;
280 for (subunit = 0; subunit < subunitcount; subunit++) {
282 if (!(firesat = kmalloc(sizeof (struct firesat), GFP_KERNEL)) ||
283 !(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) {
285 printk("%s: couldn't allocate memory.\n", __func__);
290 memset(firesat, 0, sizeof (struct firesat));
292 firesat->host = ud->ne->host;
293 firesat->guid = ud->ne->guid;
294 firesat->guid_vendor_id = ud->ne->guid_vendor_id;
295 firesat->nodeentry = ud->ne;
296 firesat->isochannel = -1;
297 firesat->tone = 0xff;
298 firesat->voltage = 0xff;
300 if (!(firesat->respfrm = kmalloc(sizeof (AVCRspFrm), GFP_KERNEL))) {
301 printk("%s: couldn't allocate memory.\n", __func__);
306 sema_init(&firesat->avc_sem, 1);
307 atomic_set(&firesat->avc_reply_received, 1);
308 sema_init(&firesat->demux_sem, 1);
309 atomic_set(&firesat->reschedule_remotecontrol, 0);
311 spin_lock_irqsave(&firesat_list_lock, flags);
312 INIT_LIST_HEAD(&firesat->list);
313 list_add_tail(&firesat->list, &firesat_list);
314 spin_unlock_irqrestore(&firesat_list_lock, flags);
317 firesat->subunit = 0x7; // 0x7 = don't care
318 if (AVCSubUnitInfo(firesat, &subunitcount)) {
319 printk("%s: AVC subunit info command failed.\n",__func__);
320 spin_lock_irqsave(&firesat_list_lock, flags);
321 list_del(&firesat->list);
322 spin_unlock_irqrestore(&firesat_list_lock, flags);
328 printk(KERN_INFO "%s: subunit count = %d\n", __func__, subunitcount);
330 firesat->subunit = subunit;
332 if (AVCIdentifySubunit(firesat, NULL, (int*)&firesat->type, &firesat->has_ci)) {
333 printk("%s: cannot identify subunit %d\n", __func__, subunit);
334 spin_lock_irqsave(&firesat_list_lock, flags);
335 list_del(&firesat->list);
336 spin_unlock_irqrestore(&firesat_list_lock, flags);
342 firesat_dvbdev_init(firesat, dev, fe);
344 firesats[subunit] = firesat;
345 } // loop for all tuners
347 //beta ;-) Disable remote control stuff to avoid crashing
349 // AVCRegisterRemoteControl(firesats[0]);
354 static int firesat_remove(struct device *dev)
356 struct unit_directory *ud = container_of(dev, struct unit_directory, device);
357 struct dvb_frontend* fe;
358 struct firesat **firesats = ud->device.driver_data;
363 for (k = 0; k < 2; k++)
365 if (firesats[k]->has_ci)
366 firesat_ca_release(firesats[k]);
369 if (!(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) {
370 fe->ops = firesat_ops;
371 fe->dvb = firesats[k]->adapter;
373 dvb_unregister_frontend(fe);
377 dvb_net_release(&firesats[k]->dvbnet);
378 firesats[k]->demux.dmx.close(&firesats[k]->demux.dmx);
379 firesats[k]->demux.dmx.remove_frontend(&firesats[k]->demux.dmx, &firesats[k]->frontend);
380 dvb_dmxdev_release(&firesats[k]->dmxdev);
381 dvb_dmx_release(&firesats[k]->demux);
382 dvb_unregister_adapter(firesats[k]->adapter);
384 spin_lock_irqsave(&firesat_list_lock, flags);
385 list_del(&firesats[k]->list);
386 spin_unlock_irqrestore(&firesat_list_lock, flags);
388 kfree(firesats[k]->adapter);
389 kfree(firesats[k]->respfrm);
394 printk("%s: can't get firesat handle\n", __func__);
396 printk(KERN_INFO "FireSAT: Removing device with vendor id 0x%x, model id 0x%x.\n",ud->vendor_id,ud->model_id);
401 static int firesat_update(struct unit_directory *ud)
403 struct firesat **firesats = ud->device.driver_data;
405 // loop over subunits
407 for (k = 0; k < 2; k++)
409 firesats[k]->nodeentry = ud->ne;
411 if (firesats[k]->isochannel >= 0)
412 try_CMPEstablishPPconnection(firesats[k], firesats[k]->subunit, firesats[k]->isochannel);
418 static struct hpsb_protocol_driver firesat_driver = {
421 .id_table = firesat_id_table,
422 .update = firesat_update,
425 //.name and .bus are filled in for us in more recent linux versions
427 //.bus = &ieee1394_bus_type,
428 .probe = firesat_probe,
429 .remove = firesat_remove,
433 static int __init firesat_init(void)
437 printk(KERN_INFO "FireSAT loaded\n");
438 hpsb_register_highlevel(&firesat_highlevel);
439 ret = hpsb_register_protocol(&firesat_driver);
441 printk(KERN_ERR "FireSAT: failed to register protocol\n");
442 hpsb_unregister_highlevel(&firesat_highlevel);
446 //Crash in this function, just disable RC for the time being...
447 //Don't forget to uncomment in firesat_exit and firesat_probe when you enable this.
448 /*if((ret=firesat_register_rc()))
449 printk("%s: firesat_register_rc return error code %d (ignored)\n", __func__, ret);*/
454 static void __exit firesat_exit(void)
456 hpsb_unregister_protocol(&firesat_driver);
457 hpsb_unregister_highlevel(&firesat_highlevel);
458 printk(KERN_INFO "FireSAT quit\n");
461 module_init(firesat_init);
462 module_exit(firesat_exit);
464 MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
465 MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
466 MODULE_DESCRIPTION("FireSAT DVB Driver");
467 MODULE_LICENSE("GPL");
468 MODULE_SUPPORTED_DEVICE("FireSAT DVB");