DVB: add firesat driver
[linux-2.6-block.git] / drivers / media / dvb / firesat / firesat_1394.c
1 /*
2  * FireSAT DVB driver
3  *
4  * Copyright (c) 2004 Andreas Monitzer <andy@monitzer.com>
5  * Copyright (c) 2007-2008 Ben Backx <ben@bbackx.com>
6  *
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.
11  */
12
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>
23 #include <nodemgr.h>
24 #include <highlevel.h>
25 #include <ohci1394.h>
26 #include <hosts.h>
27 #include <dvbdev.h>
28
29 #include "firesat.h"
30 #include "avc_api.h"
31 #include "cmp.h"
32 #include "firesat-rc.h"
33 #include "firesat-ci.h"
34
35 #define FIRESAT_Vendor_ID   0x001287
36
37 static struct ieee1394_device_id firesat_id_table[] = {
38
39         {
40                 /* FloppyDTV S/CI and FloppyDTV S2 */
41                 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
42                 .model_id = 0x000024,
43                 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
44         },{
45                 /* FloppyDTV T/CI */
46                 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
47                 .model_id = 0x000025,
48                 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
49         },{
50                 /* FloppyDTV C/CI */
51                 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
52                 .model_id = 0x000026,
53                 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
54         },{
55                 /* FireDTV S/CI and FloppyDTV S2 */
56                 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
57                 .model_id = 0x000034,
58                 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
59         },{
60                 /* FireDTV T/CI */
61                 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
62                 .model_id = 0x000035,
63                 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
64         },{
65                 /* FireDTV C/CI */
66                 .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID,
67                 .model_id = 0x000036,
68                 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
69         }, { }
70 };
71
72 MODULE_DEVICE_TABLE(ieee1394, firesat_id_table);
73
74 /* list of all firesat devices */
75 LIST_HEAD(firesat_list);
76 spinlock_t firesat_list_lock = SPIN_LOCK_UNLOCKED;
77
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);
81
82 /*
83 static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
84                         size_t length);
85 */
86
87 static void fcp_request(struct hpsb_host *host,
88                         int nodeid,
89                         int direction,
90                         int cts,
91                         u8 *data,
92                         size_t length);
93
94 static struct hpsb_highlevel firesat_highlevel = {
95         .name           = "FireSAT",
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,
101 };
102
103 static void firesat_add_host (struct hpsb_host *host)
104 {
105         struct ti_ohci *ohci = (struct ti_ohci *)host->hostdata;
106
107         /* We only work with the OHCI-1394 driver */
108         if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
109                 return;
110
111         if (!hpsb_create_hostinfo(&firesat_highlevel, host, 0)) {
112                 printk(KERN_ERR "Cannot allocate hostinfo\n");
113                 return;
114         }
115
116         hpsb_set_hostinfo(&firesat_highlevel, host, ohci);
117         hpsb_set_hostinfo_key(&firesat_highlevel, host, ohci->host->id);
118 }
119
120 static void firesat_remove_host (struct hpsb_host *host)
121 {
122
123 }
124
125 static void firesat_host_reset(struct hpsb_host *host)
126 {
127     printk(KERN_INFO "FireSAT host_reset (nodeid = 0x%x, hosts active = %d)\n",host->node_id,host->nodes_active);
128 }
129
130 struct firewireheader {
131     union {
132         struct {
133             unsigned char tcode:4;
134             unsigned char sy:4;
135             unsigned char tag:2;
136             unsigned char channel:6;
137
138             unsigned char length_l;
139             unsigned char length_h;
140         } hdr;
141         unsigned long val;
142     };
143 };
144
145 struct CIPHeader {
146     union {
147         struct {
148             unsigned char syncbits:2;
149             unsigned char sid:6;
150             unsigned char dbs;
151             unsigned char fn:2;
152             unsigned char qpc:3;
153             unsigned char sph:1;
154             unsigned char rsv:2;
155             unsigned char dbc;
156             unsigned char syncbits2:2;
157             unsigned char fmt:6;
158             unsigned long fdf:24;
159         } cip;
160         unsigned long long val;
161     };
162 };
163
164 struct MPEG2Header {
165     union {
166         struct {
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;
175         } hdr;
176         unsigned long val;
177     };
178 };
179
180 #if 0
181 static void iso_receive(struct hpsb_host *host,
182                         int channel,
183                         quadlet_t *data,
184                         size_t length)
185 {
186         struct firesat *firesat = NULL;
187         struct firesat *firesat_entry;
188         unsigned long flags;
189
190 //    printk(KERN_INFO "FireSAT iso_receive: channel %d, length = %d\n", channel, length);
191
192         if (length <= 12)
193                 return; // ignore empty packets
194         else {
195
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;
200                                 break;
201                         }
202                 }
203                 spin_unlock_irqrestore(&firesat_list_lock, flags);
204
205                 if (firesat) {
206                         char *buf= ((char*)data) + sizeof(struct firewireheader)+sizeof(struct CIPHeader);
207                         int count = (length-sizeof(struct CIPHeader)) / 192;
208
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]);
210
211                         while (count--) {
212
213                                 if (buf[sizeof(quadlet_t) /*timestamp*/] == 0x47)
214                                         dvb_dmx_swfilter_packets(&firesat->demux, &buf[sizeof(quadlet_t)], 1);
215                                 else
216                                         printk("%s: invalid packet, skipping\n", __func__);
217                                 buf += 188 + sizeof (quadlet_t) /* timestamp */;
218                         }
219                 }
220         }
221 }
222 #endif
223
224 static void fcp_request(struct hpsb_host *host,
225                         int nodeid,
226                         int direction,
227                         int cts,
228                         u8 *data,
229                         size_t length)
230 {
231         struct firesat *firesat = NULL;
232         struct firesat *firesat_entry;
233         unsigned long flags;
234
235         if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) {
236
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;
245                                 break;
246                         }
247                 }
248                 spin_unlock_irqrestore(&firesat_list_lock, flags);
249
250                 if (firesat)
251                         AVCRecv(firesat,data,length);
252                 else
253                         printk("%s: received fcp request from unknown source, ignored\n", __func__);
254         } // else ignore
255 }
256
257 static int firesat_probe(struct device *dev)
258 {
259         struct unit_directory *ud = container_of(dev, struct unit_directory, device);
260         struct firesat *firesat;
261         struct dvb_frontend *fe;
262         unsigned long flags;
263         int result;
264         unsigned char subunitcount = 0xff, subunit;
265         struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL);
266
267         if (!firesats) {
268                 printk("%s: couldn't allocate memory.\n", __func__);
269                 return -ENOMEM;
270         }
271
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__);
274
275         firesats[0] = NULL;
276         firesats[1] = NULL;
277
278         ud->device.driver_data = firesats;
279
280         for (subunit = 0; subunit < subunitcount; subunit++) {
281
282                 if (!(firesat = kmalloc(sizeof (struct firesat), GFP_KERNEL)) ||
283                     !(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) {
284
285                         printk("%s: couldn't allocate memory.\n", __func__);
286                         kfree(firesats);
287                         return -ENOMEM;
288                 }
289
290                 memset(firesat, 0, sizeof (struct firesat));
291
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;
299
300                 if (!(firesat->respfrm = kmalloc(sizeof (AVCRspFrm), GFP_KERNEL))) {
301                         printk("%s: couldn't allocate memory.\n", __func__);
302                         kfree(firesat);
303                         return -ENOMEM;
304                 }
305
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);
310
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);
315
316                 if (subunit == 0) {
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);
323                                 kfree(firesat);
324                                 return -EIO;
325                         }
326                 }
327
328                 printk(KERN_INFO "%s: subunit count = %d\n", __func__, subunitcount);
329
330                 firesat->subunit = subunit;
331
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);
337                         kfree(firesat);
338                         continue;
339                 }
340
341 // ----
342                 firesat_dvbdev_init(firesat, dev, fe);
343 // ----
344                 firesats[subunit] = firesat;
345         } // loop for all tuners
346
347         //beta ;-) Disable remote control stuff to avoid crashing
348         //if(firesats[0])
349         //      AVCRegisterRemoteControl(firesats[0]);
350
351     return 0;
352 }
353
354 static int firesat_remove(struct device *dev)
355 {
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;
359         int k;
360         unsigned long flags;
361
362         if (firesats) {
363                 for (k = 0; k < 2; k++)
364                         if (firesats[k]) {
365                                 if (firesats[k]->has_ci)
366                                         firesat_ca_release(firesats[k]);
367
368 #if 0
369                                 if (!(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) {
370                                         fe->ops = firesat_ops;
371                                         fe->dvb = firesats[k]->adapter;
372
373                                         dvb_unregister_frontend(fe);
374                                         kfree(fe);
375                                 }
376 #endif
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);
383
384                                 spin_lock_irqsave(&firesat_list_lock, flags);
385                                 list_del(&firesats[k]->list);
386                                 spin_unlock_irqrestore(&firesat_list_lock, flags);
387
388                                 kfree(firesats[k]->adapter);
389                                 kfree(firesats[k]->respfrm);
390                                 kfree(firesats[k]);
391                         }
392                 kfree(firesats);
393         } else
394                 printk("%s: can't get firesat handle\n", __func__);
395
396         printk(KERN_INFO "FireSAT: Removing device with vendor id 0x%x, model id 0x%x.\n",ud->vendor_id,ud->model_id);
397
398         return 0;
399 }
400
401 static int firesat_update(struct unit_directory *ud)
402 {
403         struct firesat **firesats = ud->device.driver_data;
404         int k;
405         // loop over subunits
406
407         for (k = 0; k < 2; k++)
408                 if (firesats[k]) {
409                         firesats[k]->nodeentry = ud->ne;
410
411                         if (firesats[k]->isochannel >= 0)
412                                 try_CMPEstablishPPconnection(firesats[k], firesats[k]->subunit, firesats[k]->isochannel);
413                 }
414
415         return 0;
416 }
417
418 static struct hpsb_protocol_driver firesat_driver = {
419
420         .name           = "FireSAT",
421         .id_table       = firesat_id_table,
422         .update         = firesat_update,
423
424         .driver         = {
425                 //.name and .bus are filled in for us in more recent linux versions
426                 //.name = "FireSAT",
427                 //.bus  = &ieee1394_bus_type,
428                 .probe  = firesat_probe,
429                 .remove = firesat_remove,
430         },
431 };
432
433 static int __init firesat_init(void)
434 {
435         int ret;
436
437         printk(KERN_INFO "FireSAT loaded\n");
438         hpsb_register_highlevel(&firesat_highlevel);
439         ret = hpsb_register_protocol(&firesat_driver);
440         if (ret) {
441                 printk(KERN_ERR "FireSAT: failed to register protocol\n");
442                 hpsb_unregister_highlevel(&firesat_highlevel);
443                 return ret;
444         }
445
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);*/
450
451         return 0;
452 }
453
454 static void __exit firesat_exit(void)
455 {
456         hpsb_unregister_protocol(&firesat_driver);
457         hpsb_unregister_highlevel(&firesat_highlevel);
458         printk(KERN_INFO "FireSAT quit\n");
459 }
460
461 module_init(firesat_init);
462 module_exit(firesat_exit);
463
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");