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>
26 #include <dvb_demux.h>
27 #include <dvb_frontend.h>
31 #include <highlevel.h>
33 #include <ieee1394_hotplug.h>
39 #include "firesat-ci.h"
40 #include "firesat-rc.h"
42 #define MATCH_FLAGS IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
43 IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION
44 #define DIGITAL_EVERYWHERE_OUI 0x001287
46 static struct ieee1394_device_id firesat_id_table
[] = {
49 /* FloppyDTV S/CI and FloppyDTV S2 */
50 .match_flags
= MATCH_FLAGS
,
51 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
53 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
54 .version
= AVC_SW_VERSION_ENTRY
,
57 .match_flags
= MATCH_FLAGS
,
58 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
60 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
61 .version
= AVC_SW_VERSION_ENTRY
,
64 .match_flags
= MATCH_FLAGS
,
65 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
67 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
68 .version
= AVC_SW_VERSION_ENTRY
,
70 /* FireDTV S/CI and FloppyDTV S2 */
71 .match_flags
= MATCH_FLAGS
,
72 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
74 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
75 .version
= AVC_SW_VERSION_ENTRY
,
78 .match_flags
= MATCH_FLAGS
,
79 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
81 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
82 .version
= AVC_SW_VERSION_ENTRY
,
85 .match_flags
= MATCH_FLAGS
,
86 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
88 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
89 .version
= AVC_SW_VERSION_ENTRY
,
93 MODULE_DEVICE_TABLE(ieee1394
, firesat_id_table
);
95 /* list of all firesat devices */
96 LIST_HEAD(firesat_list
);
97 DEFINE_SPINLOCK(firesat_list_lock
);
99 static void fcp_request(struct hpsb_host
*host
,
106 struct firesat
*firesat
= NULL
;
107 struct firesat
*firesat_entry
;
110 if (length
> 0 && ((data
[0] & 0xf0) >> 4) == 0) {
112 spin_lock_irqsave(&firesat_list_lock
, flags
);
113 list_for_each_entry(firesat_entry
,&firesat_list
,list
) {
114 if (firesat_entry
->ud
->ne
->host
== host
&&
115 firesat_entry
->ud
->ne
->nodeid
== nodeid
&&
116 (firesat_entry
->subunit
== (data
[1]&0x7) ||
117 (firesat_entry
->subunit
== 0 &&
118 (data
[1]&0x7) == 0x7))) {
119 firesat
=firesat_entry
;
123 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
126 avc_recv(firesat
, data
, length
);
130 const char *firedtv_model_names
[] = {
131 [FireSAT_UNKNOWN
] = "unknown type",
132 [FireSAT_DVB_S
] = "FireDTV S/CI",
133 [FireSAT_DVB_C
] = "FireDTV C/CI",
134 [FireSAT_DVB_T
] = "FireDTV T/CI",
135 [FireSAT_DVB_S2
] = "FireDTV S2 ",
138 static int firesat_probe(struct device
*dev
)
140 struct unit_directory
*ud
=
141 container_of(dev
, struct unit_directory
, device
);
142 struct firesat
*firesat
;
149 firesat
= kzalloc(sizeof(*firesat
), GFP_KERNEL
);
153 dev
->driver_data
= firesat
;
155 firesat
->subunit
= 0;
156 firesat
->isochannel
= -1;
157 firesat
->tone
= 0xff;
158 firesat
->voltage
= 0xff;
160 mutex_init(&firesat
->avc_mutex
);
161 init_waitqueue_head(&firesat
->avc_wait
);
162 firesat
->avc_reply_received
= true;
163 mutex_init(&firesat
->demux_mutex
);
164 INIT_WORK(&firesat
->remote_ctrl_work
, avc_remote_ctrl_work
);
166 /* Reading device model from ROM */
167 kv_len
= (ud
->model_name_kv
->value
.leaf
.len
- 2) * sizeof(quadlet_t
);
168 kv_str
= CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud
->model_name_kv
);
169 for (i
= ARRAY_SIZE(firedtv_model_names
); --i
;)
170 if (strlen(firedtv_model_names
[i
]) <= kv_len
&&
171 strncmp(kv_str
, firedtv_model_names
[i
], kv_len
) == 0)
176 * Work around a bug in udev's path_id script: Use the fw-host's dev
177 * instead of the unit directory's dev as parent of the input device.
179 err
= firesat_register_rc(firesat
, dev
->parent
->parent
);
183 INIT_LIST_HEAD(&firesat
->list
);
184 spin_lock_irqsave(&firesat_list_lock
, flags
);
185 list_add_tail(&firesat
->list
, &firesat_list
);
186 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
188 err
= avc_identify_subunit(firesat
);
192 err
= firesat_dvbdev_init(firesat
, dev
);
196 avc_register_remote_control(firesat
);
200 spin_lock_irqsave(&firesat_list_lock
, flags
);
201 list_del(&firesat
->list
);
202 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
203 firesat_unregister_rc(firesat
);
209 static int firesat_remove(struct device
*dev
)
211 struct firesat
*firesat
= dev
->driver_data
;
214 firesat_ca_release(firesat
);
215 dvb_unregister_frontend(&firesat
->fe
);
216 dvb_net_release(&firesat
->dvbnet
);
217 firesat
->demux
.dmx
.close(&firesat
->demux
.dmx
);
218 firesat
->demux
.dmx
.remove_frontend(&firesat
->demux
.dmx
,
220 dvb_dmxdev_release(&firesat
->dmxdev
);
221 dvb_dmx_release(&firesat
->demux
);
222 dvb_unregister_adapter(&firesat
->adapter
);
224 spin_lock_irqsave(&firesat_list_lock
, flags
);
225 list_del(&firesat
->list
);
226 spin_unlock_irqrestore(&firesat_list_lock
, flags
);
228 cancel_work_sync(&firesat
->remote_ctrl_work
);
229 firesat_unregister_rc(firesat
);
235 static int firesat_update(struct unit_directory
*ud
)
237 struct firesat
*firesat
= ud
->device
.driver_data
;
239 if (firesat
->isochannel
>= 0)
240 cmp_establish_pp_connection(firesat
, firesat
->subunit
,
241 firesat
->isochannel
);
245 static struct hpsb_protocol_driver firesat_driver
= {
248 .id_table
= firesat_id_table
,
249 .update
= firesat_update
,
252 //.name and .bus are filled in for us in more recent linux versions
254 //.bus = &ieee1394_bus_type,
255 .probe
= firesat_probe
,
256 .remove
= firesat_remove
,
260 static struct hpsb_highlevel firesat_highlevel
= {
262 .fcp_request
= fcp_request
,
265 static int __init
firesat_init(void)
269 hpsb_register_highlevel(&firesat_highlevel
);
270 ret
= hpsb_register_protocol(&firesat_driver
);
272 printk(KERN_ERR
"firedtv: failed to register protocol\n");
273 hpsb_unregister_highlevel(&firesat_highlevel
);
278 static void __exit
firesat_exit(void)
280 hpsb_unregister_protocol(&firesat_driver
);
281 hpsb_unregister_highlevel(&firesat_highlevel
);
284 module_init(firesat_init
);
285 module_exit(firesat_exit
);
287 MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
288 MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
289 MODULE_DESCRIPTION("FireDTV DVB Driver");
290 MODULE_LICENSE("GPL");
291 MODULE_SUPPORTED_DEVICE("FireDTV DVB");