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/init.h>
15 #include <linux/slab.h>
16 #include <linux/wait.h>
17 #include <linux/module.h>
18 #include <linux/delay.h>
19 #include <linux/time.h>
20 #include <linux/errno.h>
21 #include <linux/interrupt.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
);
82 static void fcp_request(struct hpsb_host
*host
,
89 static struct hpsb_highlevel firesat_highlevel
= {
91 .add_host
= firesat_add_host
,
92 .remove_host
= firesat_remove_host
,
93 .host_reset
= firesat_host_reset
,
94 .fcp_request
= fcp_request
,
97 static void firesat_add_host (struct hpsb_host
*host
)
99 struct ti_ohci
*ohci
= (struct ti_ohci
*)host
->hostdata
;
101 /* We only work with the OHCI-1394 driver */
102 if (strcmp(host
->driver
->name
, OHCI1394_DRIVER_NAME
))
105 if (!hpsb_create_hostinfo(&firesat_highlevel
, host
, 0)) {
106 printk(KERN_ERR
"Cannot allocate hostinfo\n");
110 hpsb_set_hostinfo(&firesat_highlevel
, host
, ohci
);
111 hpsb_set_hostinfo_key(&firesat_highlevel
, host
, ohci
->host
->id
);
114 static void firesat_remove_host (struct hpsb_host
*host
)
119 static void firesat_host_reset(struct hpsb_host
*host
)
121 printk(KERN_INFO
"FireSAT host_reset (nodeid = 0x%x, hosts active = %d)\n",host
->node_id
,host
->nodes_active
);
124 static void fcp_request(struct hpsb_host
*host
,
131 struct firesat
*firesat
= NULL
;
132 struct firesat
*firesat_entry
;
135 if (length
> 0 && ((data
[0] & 0xf0) >> 4) == 0) {
137 spin_lock_irqsave(&firesat_list_lock
, flags
);
138 list_for_each_entry(firesat_entry
,&firesat_list
,list
) {
139 if (firesat_entry
->host
== host
&&
140 firesat_entry
->nodeentry
->nodeid
== nodeid
&&
141 (firesat_entry
->subunit
== (data
[1]&0x7) ||
142 (firesat_entry
->subunit
== 0 &&
143 (data
[1]&0x7) == 0x7))) {
144 firesat
=firesat_entry
;
148 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
151 AVCRecv(firesat
,data
,length
);
153 printk("%s: received fcp request from unknown source, ignored\n", __func__
);
156 printk("%s: received invalid fcp request, ignored\n", __func__
);
159 static int firesat_probe(struct device
*dev
)
161 struct unit_directory
*ud
= container_of(dev
, struct unit_directory
, device
);
162 struct firesat
*firesat
;
163 struct dvb_frontend
*fe
;
165 unsigned char subunitcount
= 0xff, subunit
;
166 struct firesat
**firesats
= kmalloc(sizeof (void*) * 2,GFP_KERNEL
);
171 printk("%s: couldn't allocate memory.\n", __func__
);
175 // 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);
176 printk(KERN_INFO
"%s: loading device\n", __func__
);
181 ud
->device
.driver_data
= firesats
;
183 for (subunit
= 0; subunit
< subunitcount
; subunit
++) {
185 if (!(firesat
= kmalloc(sizeof (struct firesat
), GFP_KERNEL
)) ||
186 !(fe
= kmalloc(sizeof (struct dvb_frontend
), GFP_KERNEL
))) {
188 printk("%s: couldn't allocate memory.\n", __func__
);
193 memset(firesat
, 0, sizeof (struct firesat
));
195 firesat
->host
= ud
->ne
->host
;
196 firesat
->guid
= ud
->ne
->guid
;
197 firesat
->guid_vendor_id
= ud
->ne
->guid_vendor_id
;
198 firesat
->nodeentry
= ud
->ne
;
199 firesat
->isochannel
= -1;
200 firesat
->tone
= 0xff;
201 firesat
->voltage
= 0xff;
204 if (!(firesat
->respfrm
= kmalloc(sizeof (AVCRspFrm
), GFP_KERNEL
))) {
205 printk("%s: couldn't allocate memory.\n", __func__
);
210 sema_init(&firesat
->avc_sem
, 1);
211 atomic_set(&firesat
->avc_reply_received
, 1);
212 sema_init(&firesat
->demux_sem
, 1);
213 atomic_set(&firesat
->reschedule_remotecontrol
, 0);
215 spin_lock_irqsave(&firesat_list_lock
, flags
);
216 INIT_LIST_HEAD(&firesat
->list
);
217 list_add_tail(&firesat
->list
, &firesat_list
);
218 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
221 firesat
->subunit
= 0x7; // 0x7 = don't care
222 if (AVCSubUnitInfo(firesat
, &subunitcount
)) {
223 printk("%s: AVC subunit info command failed.\n",__func__
);
224 spin_lock_irqsave(&firesat_list_lock
, flags
);
225 list_del(&firesat
->list
);
226 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
232 printk(KERN_INFO
"%s: subunit count = %d\n", __func__
, subunitcount
);
234 firesat
->subunit
= subunit
;
236 /* Reading device model from ROM */
237 kv_len
= (ud
->model_name_kv
->value
.leaf
.len
- 2) *
239 kv_buf
= kmalloc((sizeof(quadlet_t
) * kv_len
), GFP_KERNEL
);
241 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud
->model_name_kv
),
243 while ((kv_buf
+ kv_len
- 1) == '\0') kv_len
--;
244 kv_buf
[kv_len
++] = '\0';
246 /* Determining the device model */
247 if (strcmp(kv_buf
, "FireDTV S/CI") == 0) {
248 printk(KERN_INFO
"%s: found DVB/S\n", __func__
);
250 } else if (strcmp(kv_buf
, "FireDTV C/CI") == 0) {
251 printk(KERN_INFO
"%s: found DVB/C\n", __func__
);
253 } else if (strcmp(kv_buf
, "FireDTV T/CI") == 0) {
254 printk(KERN_INFO
"%s: found DVB/T\n", __func__
);
256 } else if (strcmp(kv_buf
, "FireDTV S2 ") == 0) {
257 printk(KERN_INFO
"%s: found DVB/S2\n", __func__
);
262 if (AVCIdentifySubunit(firesat
, NULL
, (int*)&firesat
->type
)) {
263 printk("%s: cannot identify subunit %d\n", __func__
, subunit
);
264 spin_lock_irqsave(&firesat_list_lock
, flags
);
265 list_del(&firesat
->list
);
266 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
272 firesat_dvbdev_init(firesat
, dev
, fe
);
274 firesats
[subunit
] = firesat
;
275 } // loop for all tuners
277 //beta ;-) Disable remote control stuff to avoid crashing
279 // AVCRegisterRemoteControl(firesats[0]);
284 static int firesat_remove(struct device
*dev
)
286 struct unit_directory
*ud
= container_of(dev
, struct unit_directory
, device
);
287 struct firesat
**firesats
= ud
->device
.driver_data
;
292 for (k
= 0; k
< 2; k
++)
294 firesat_ca_release(firesats
[k
]);
296 dvb_unregister_frontend(firesats
[k
]->fe
);
297 dvb_net_release(&firesats
[k
]->dvbnet
);
298 firesats
[k
]->demux
.dmx
.close(&firesats
[k
]->demux
.dmx
);
299 firesats
[k
]->demux
.dmx
.remove_frontend(&firesats
[k
]->demux
.dmx
, &firesats
[k
]->frontend
);
300 dvb_dmxdev_release(&firesats
[k
]->dmxdev
);
301 dvb_dmx_release(&firesats
[k
]->demux
);
302 dvb_unregister_adapter(firesats
[k
]->adapter
);
304 spin_lock_irqsave(&firesat_list_lock
, flags
);
305 list_del(&firesats
[k
]->list
);
306 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
308 kfree(firesats
[k
]->fe
);
309 kfree(firesats
[k
]->adapter
);
310 kfree(firesats
[k
]->respfrm
);
315 printk("%s: can't get firesat handle\n", __func__
);
317 printk(KERN_INFO
"FireSAT: Removing device with vendor id 0x%x, model id 0x%x.\n",ud
->vendor_id
,ud
->model_id
);
322 static int firesat_update(struct unit_directory
*ud
)
324 struct firesat
**firesats
= ud
->device
.driver_data
;
326 // loop over subunits
328 for (k
= 0; k
< 2; k
++)
330 firesats
[k
]->nodeentry
= ud
->ne
;
332 if (firesats
[k
]->isochannel
>= 0)
333 try_CMPEstablishPPconnection(firesats
[k
], firesats
[k
]->subunit
, firesats
[k
]->isochannel
);
339 static struct hpsb_protocol_driver firesat_driver
= {
342 .id_table
= firesat_id_table
,
343 .update
= firesat_update
,
346 //.name and .bus are filled in for us in more recent linux versions
348 //.bus = &ieee1394_bus_type,
349 .probe
= firesat_probe
,
350 .remove
= firesat_remove
,
354 static int __init
firesat_init(void)
358 printk(KERN_INFO
"FireSAT loaded\n");
359 hpsb_register_highlevel(&firesat_highlevel
);
360 ret
= hpsb_register_protocol(&firesat_driver
);
362 printk(KERN_ERR
"FireSAT: failed to register protocol\n");
363 hpsb_unregister_highlevel(&firesat_highlevel
);
367 //Crash in this function, just disable RC for the time being...
368 //Don't forget to uncomment in firesat_exit and firesat_probe when you enable this.
369 /*if((ret=firesat_register_rc()))
370 printk("%s: firesat_register_rc return error code %d (ignored)\n", __func__, ret);*/
375 static void __exit
firesat_exit(void)
377 hpsb_unregister_protocol(&firesat_driver
);
378 hpsb_unregister_highlevel(&firesat_highlevel
);
379 printk(KERN_INFO
"FireSAT quit\n");
382 module_init(firesat_init
);
383 module_exit(firesat_exit
);
385 MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
386 MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
387 MODULE_DESCRIPTION("FireSAT DVB Driver");
388 MODULE_LICENSE("GPL");
389 MODULE_SUPPORTED_DEVICE("FireSAT DVB");