diff options
Diffstat (limited to 'drivers/media/dvb/firewire/firedtv-1394.c')
-rw-r--r-- | drivers/media/dvb/firewire/firedtv-1394.c | 332 |
1 files changed, 163 insertions, 169 deletions
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c index 953618246e8e..4e207658c5d9 100644 --- a/drivers/media/dvb/firewire/firedtv-1394.c +++ b/drivers/media/dvb/firewire/firedtv-1394.c | |||
@@ -15,162 +15,181 @@ | |||
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/list.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> | 18 | #include <linux/spinlock.h> |
22 | #include <linux/string.h> | ||
23 | #include <linux/types.h> | 19 | #include <linux/types.h> |
24 | 20 | ||
25 | #include <dmxdev.h> | 21 | #include <dma.h> |
26 | #include <dvb_demux.h> | ||
27 | #include <dvb_frontend.h> | ||
28 | #include <dvbdev.h> | ||
29 | |||
30 | #include <csr1212.h> | 22 | #include <csr1212.h> |
31 | #include <highlevel.h> | 23 | #include <highlevel.h> |
32 | #include <hosts.h> | 24 | #include <hosts.h> |
33 | #include <ieee1394_hotplug.h> | 25 | #include <ieee1394.h> |
26 | #include <iso.h> | ||
34 | #include <nodemgr.h> | 27 | #include <nodemgr.h> |
35 | 28 | ||
36 | #include "avc.h" | ||
37 | #include "cmp.h" | ||
38 | #include "firedtv.h" | 29 | #include "firedtv.h" |
39 | #include "firedtv-ci.h" | ||
40 | #include "firedtv-rc.h" | ||
41 | |||
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 | ||
45 | |||
46 | static struct ieee1394_device_id fdtv_id_table[] = { | ||
47 | |||
48 | { | ||
49 | /* FloppyDTV S/CI and FloppyDTV S2 */ | ||
50 | .match_flags = MATCH_FLAGS, | ||
51 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
52 | .model_id = 0x000024, | ||
53 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
54 | .version = AVC_SW_VERSION_ENTRY, | ||
55 | },{ | ||
56 | /* FloppyDTV T/CI */ | ||
57 | .match_flags = MATCH_FLAGS, | ||
58 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
59 | .model_id = 0x000025, | ||
60 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
61 | .version = AVC_SW_VERSION_ENTRY, | ||
62 | },{ | ||
63 | /* FloppyDTV C/CI */ | ||
64 | .match_flags = MATCH_FLAGS, | ||
65 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
66 | .model_id = 0x000026, | ||
67 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
68 | .version = AVC_SW_VERSION_ENTRY, | ||
69 | },{ | ||
70 | /* FireDTV S/CI and FloppyDTV S2 */ | ||
71 | .match_flags = MATCH_FLAGS, | ||
72 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
73 | .model_id = 0x000034, | ||
74 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
75 | .version = AVC_SW_VERSION_ENTRY, | ||
76 | },{ | ||
77 | /* FireDTV T/CI */ | ||
78 | .match_flags = MATCH_FLAGS, | ||
79 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
80 | .model_id = 0x000035, | ||
81 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
82 | .version = AVC_SW_VERSION_ENTRY, | ||
83 | },{ | ||
84 | /* FireDTV C/CI */ | ||
85 | .match_flags = MATCH_FLAGS, | ||
86 | .vendor_id = DIGITAL_EVERYWHERE_OUI, | ||
87 | .model_id = 0x000036, | ||
88 | .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, | ||
89 | .version = AVC_SW_VERSION_ENTRY, | ||
90 | }, { } | ||
91 | }; | ||
92 | 30 | ||
93 | MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); | 31 | static LIST_HEAD(node_list); |
32 | static DEFINE_SPINLOCK(node_list_lock); | ||
94 | 33 | ||
95 | /* list of all firedtv devices */ | 34 | #define FIREWIRE_HEADER_SIZE 4 |
96 | LIST_HEAD(fdtv_list); | 35 | #define CIP_HEADER_SIZE 8 |
97 | DEFINE_SPINLOCK(fdtv_list_lock); | ||
98 | 36 | ||
99 | static void fcp_request(struct hpsb_host *host, | 37 | static void rawiso_activity_cb(struct hpsb_iso *iso) |
100 | int nodeid, | ||
101 | int direction, | ||
102 | int cts, | ||
103 | u8 *data, | ||
104 | size_t length) | ||
105 | { | 38 | { |
106 | struct firedtv *fdtv = NULL; | 39 | struct firedtv *f, *fdtv = NULL; |
107 | struct firedtv *fdtv_entry; | 40 | unsigned int i, num, packet; |
41 | unsigned char *buf; | ||
108 | unsigned long flags; | 42 | unsigned long flags; |
43 | int count; | ||
44 | |||
45 | spin_lock_irqsave(&node_list_lock, flags); | ||
46 | list_for_each_entry(f, &node_list, list) | ||
47 | if (f->backend_data == iso) { | ||
48 | fdtv = f; | ||
49 | break; | ||
50 | } | ||
51 | spin_unlock_irqrestore(&node_list_lock, flags); | ||
52 | |||
53 | packet = iso->first_packet; | ||
54 | num = hpsb_iso_n_ready(iso); | ||
55 | |||
56 | if (!fdtv) { | ||
57 | dev_err(fdtv->device, "received at unknown iso channel\n"); | ||
58 | goto out; | ||
59 | } | ||
109 | 60 | ||
110 | if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) { | 61 | for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) { |
111 | 62 | buf = dma_region_i(&iso->data_buf, unsigned char, | |
112 | spin_lock_irqsave(&fdtv_list_lock, flags); | 63 | iso->infos[packet].offset + CIP_HEADER_SIZE); |
113 | list_for_each_entry(fdtv_entry,&fdtv_list,list) { | 64 | count = (iso->infos[packet].len - CIP_HEADER_SIZE) / |
114 | if (fdtv_entry->ud->ne->host == host && | 65 | (188 + FIREWIRE_HEADER_SIZE); |
115 | fdtv_entry->ud->ne->nodeid == nodeid && | 66 | |
116 | (fdtv_entry->subunit == (data[1]&0x7) || | 67 | /* ignore empty packet */ |
117 | (fdtv_entry->subunit == 0 && | 68 | if (iso->infos[packet].len <= CIP_HEADER_SIZE) |
118 | (data[1]&0x7) == 0x7))) { | 69 | continue; |
119 | fdtv=fdtv_entry; | 70 | |
120 | break; | 71 | while (count--) { |
121 | } | 72 | if (buf[FIREWIRE_HEADER_SIZE] == 0x47) |
73 | dvb_dmx_swfilter_packets(&fdtv->demux, | ||
74 | &buf[FIREWIRE_HEADER_SIZE], 1); | ||
75 | else | ||
76 | dev_err(fdtv->device, | ||
77 | "skipping invalid packet\n"); | ||
78 | buf += 188 + FIREWIRE_HEADER_SIZE; | ||
122 | } | 79 | } |
123 | spin_unlock_irqrestore(&fdtv_list_lock, flags); | 80 | } |
81 | out: | ||
82 | hpsb_iso_recv_release_packets(iso, num); | ||
83 | } | ||
84 | |||
85 | static inline struct node_entry *node_of(struct firedtv *fdtv) | ||
86 | { | ||
87 | return container_of(fdtv->device, struct unit_directory, device)->ne; | ||
88 | } | ||
89 | |||
90 | static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg) | ||
91 | { | ||
92 | return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data, | ||
93 | (__force quadlet_t)arg); | ||
94 | } | ||
95 | |||
96 | static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len) | ||
97 | { | ||
98 | return hpsb_node_read(node_of(fdtv), addr, data, len); | ||
99 | } | ||
100 | |||
101 | static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) | ||
102 | { | ||
103 | return hpsb_node_write(node_of(fdtv), addr, data, len); | ||
104 | } | ||
105 | |||
106 | #define FDTV_ISO_BUFFER_PACKETS 256 | ||
107 | #define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200) | ||
108 | |||
109 | static int start_iso(struct firedtv *fdtv) | ||
110 | { | ||
111 | struct hpsb_iso *iso_handle; | ||
112 | int ret; | ||
113 | |||
114 | iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host, | ||
115 | FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS, | ||
116 | fdtv->isochannel, HPSB_ISO_DMA_DEFAULT, | ||
117 | -1, /* stat.config.irq_interval */ | ||
118 | rawiso_activity_cb); | ||
119 | if (iso_handle == NULL) { | ||
120 | dev_err(fdtv->device, "cannot initialize iso receive\n"); | ||
121 | return -ENOMEM; | ||
122 | } | ||
123 | fdtv->backend_data = iso_handle; | ||
124 | |||
125 | ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0); | ||
126 | if (ret != 0) { | ||
127 | dev_err(fdtv->device, "cannot start iso receive\n"); | ||
128 | hpsb_iso_shutdown(iso_handle); | ||
129 | fdtv->backend_data = NULL; | ||
130 | } | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static void stop_iso(struct firedtv *fdtv) | ||
135 | { | ||
136 | struct hpsb_iso *iso_handle = fdtv->backend_data; | ||
124 | 137 | ||
125 | if (fdtv) | 138 | if (iso_handle != NULL) { |
126 | avc_recv(fdtv, data, length); | 139 | hpsb_iso_stop(iso_handle); |
140 | hpsb_iso_shutdown(iso_handle); | ||
127 | } | 141 | } |
142 | fdtv->backend_data = NULL; | ||
128 | } | 143 | } |
129 | 144 | ||
130 | const char *fdtv_model_names[] = { | 145 | static const struct firedtv_backend fdtv_1394_backend = { |
131 | [FIREDTV_UNKNOWN] = "unknown type", | 146 | .lock = node_lock, |
132 | [FIREDTV_DVB_S] = "FireDTV S/CI", | 147 | .read = node_read, |
133 | [FIREDTV_DVB_C] = "FireDTV C/CI", | 148 | .write = node_write, |
134 | [FIREDTV_DVB_T] = "FireDTV T/CI", | 149 | .start_iso = start_iso, |
135 | [FIREDTV_DVB_S2] = "FireDTV S2 ", | 150 | .stop_iso = stop_iso, |
136 | }; | 151 | }; |
137 | 152 | ||
138 | static int fdtv_probe(struct device *dev) | 153 | static void fcp_request(struct hpsb_host *host, int nodeid, int direction, |
154 | int cts, u8 *data, size_t length) | ||
139 | { | 155 | { |
140 | struct unit_directory *ud = | 156 | struct firedtv *f, *fdtv = NULL; |
141 | container_of(dev, struct unit_directory, device); | ||
142 | struct firedtv *fdtv; | ||
143 | unsigned long flags; | 157 | unsigned long flags; |
144 | int kv_len; | 158 | int su; |
145 | void *kv_str; | ||
146 | int i; | ||
147 | int err = -ENOMEM; | ||
148 | 159 | ||
149 | fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); | 160 | if (length == 0 || (data[0] & 0xf0) != 0) |
150 | if (!fdtv) | 161 | return; |
151 | return -ENOMEM; | ||
152 | 162 | ||
153 | dev->driver_data = fdtv; | 163 | su = data[1] & 0x7; |
154 | fdtv->ud = ud; | 164 | |
155 | fdtv->subunit = 0; | 165 | spin_lock_irqsave(&node_list_lock, flags); |
156 | fdtv->isochannel = -1; | 166 | list_for_each_entry(f, &node_list, list) |
157 | fdtv->tone = 0xff; | 167 | if (node_of(f)->host == host && |
158 | fdtv->voltage = 0xff; | 168 | node_of(f)->nodeid == nodeid && |
169 | (f->subunit == su || (f->subunit == 0 && su == 0x7))) { | ||
170 | fdtv = f; | ||
171 | break; | ||
172 | } | ||
173 | spin_unlock_irqrestore(&node_list_lock, flags); | ||
159 | 174 | ||
160 | mutex_init(&fdtv->avc_mutex); | 175 | if (fdtv) |
161 | init_waitqueue_head(&fdtv->avc_wait); | 176 | avc_recv(fdtv, data, length); |
162 | fdtv->avc_reply_received = true; | 177 | } |
163 | mutex_init(&fdtv->demux_mutex); | 178 | |
164 | INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); | 179 | static int node_probe(struct device *dev) |
180 | { | ||
181 | struct unit_directory *ud = | ||
182 | container_of(dev, struct unit_directory, device); | ||
183 | struct firedtv *fdtv; | ||
184 | int kv_len, err; | ||
185 | void *kv_str; | ||
165 | 186 | ||
166 | /* Reading device model from ROM */ | ||
167 | kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t); | 187 | 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); | 188 | kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv); |
169 | for (i = ARRAY_SIZE(fdtv_model_names); --i;) | 189 | |
170 | if (strlen(fdtv_model_names[i]) <= kv_len && | 190 | fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len); |
171 | strncmp(kv_str, fdtv_model_names[i], kv_len) == 0) | 191 | if (!fdtv) |
172 | break; | 192 | return -ENOMEM; |
173 | fdtv->type = i; | ||
174 | 193 | ||
175 | /* | 194 | /* |
176 | * Work around a bug in udev's path_id script: Use the fw-host's dev | 195 | * Work around a bug in udev's path_id script: Use the fw-host's dev |
@@ -180,50 +199,39 @@ static int fdtv_probe(struct device *dev) | |||
180 | if (err) | 199 | if (err) |
181 | goto fail_free; | 200 | goto fail_free; |
182 | 201 | ||
183 | INIT_LIST_HEAD(&fdtv->list); | 202 | spin_lock_irq(&node_list_lock); |
184 | spin_lock_irqsave(&fdtv_list_lock, flags); | 203 | list_add_tail(&fdtv->list, &node_list); |
185 | list_add_tail(&fdtv->list, &fdtv_list); | 204 | spin_unlock_irq(&node_list_lock); |
186 | spin_unlock_irqrestore(&fdtv_list_lock, flags); | ||
187 | 205 | ||
188 | err = avc_identify_subunit(fdtv); | 206 | err = avc_identify_subunit(fdtv); |
189 | if (err) | 207 | if (err) |
190 | goto fail; | 208 | goto fail; |
191 | 209 | ||
192 | err = fdtv_dvbdev_init(fdtv, dev); | 210 | err = fdtv_dvb_register(fdtv); |
193 | if (err) | 211 | if (err) |
194 | goto fail; | 212 | goto fail; |
195 | 213 | ||
196 | avc_register_remote_control(fdtv); | 214 | avc_register_remote_control(fdtv); |
197 | return 0; | 215 | return 0; |
198 | |||
199 | fail: | 216 | fail: |
200 | spin_lock_irqsave(&fdtv_list_lock, flags); | 217 | spin_lock_irq(&node_list_lock); |
201 | list_del(&fdtv->list); | 218 | list_del(&fdtv->list); |
202 | spin_unlock_irqrestore(&fdtv_list_lock, flags); | 219 | spin_unlock_irq(&node_list_lock); |
203 | fdtv_unregister_rc(fdtv); | 220 | fdtv_unregister_rc(fdtv); |
204 | fail_free: | 221 | fail_free: |
205 | kfree(fdtv); | 222 | kfree(fdtv); |
206 | return err; | 223 | return err; |
207 | } | 224 | } |
208 | 225 | ||
209 | static int fdtv_remove(struct device *dev) | 226 | static int node_remove(struct device *dev) |
210 | { | 227 | { |
211 | struct firedtv *fdtv = dev->driver_data; | 228 | struct firedtv *fdtv = dev->driver_data; |
212 | unsigned long flags; | ||
213 | 229 | ||
214 | fdtv_ca_release(fdtv); | 230 | fdtv_dvb_unregister(fdtv); |
215 | dvb_unregister_frontend(&fdtv->fe); | 231 | |
216 | dvb_net_release(&fdtv->dvbnet); | 232 | spin_lock_irq(&node_list_lock); |
217 | fdtv->demux.dmx.close(&fdtv->demux.dmx); | ||
218 | fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, | ||
219 | &fdtv->frontend); | ||
220 | dvb_dmxdev_release(&fdtv->dmxdev); | ||
221 | dvb_dmx_release(&fdtv->demux); | ||
222 | dvb_unregister_adapter(&fdtv->adapter); | ||
223 | |||
224 | spin_lock_irqsave(&fdtv_list_lock, flags); | ||
225 | list_del(&fdtv->list); | 233 | list_del(&fdtv->list); |
226 | spin_unlock_irqrestore(&fdtv_list_lock, flags); | 234 | spin_unlock_irq(&node_list_lock); |
227 | 235 | ||
228 | cancel_work_sync(&fdtv->remote_ctrl_work); | 236 | cancel_work_sync(&fdtv->remote_ctrl_work); |
229 | fdtv_unregister_rc(fdtv); | 237 | fdtv_unregister_rc(fdtv); |
@@ -232,7 +240,7 @@ static int fdtv_remove(struct device *dev) | |||
232 | return 0; | 240 | return 0; |
233 | } | 241 | } |
234 | 242 | ||
235 | static int fdtv_update(struct unit_directory *ud) | 243 | static int node_update(struct unit_directory *ud) |
236 | { | 244 | { |
237 | struct firedtv *fdtv = ud->device.driver_data; | 245 | struct firedtv *fdtv = ud->device.driver_data; |
238 | 246 | ||
@@ -243,17 +251,11 @@ static int fdtv_update(struct unit_directory *ud) | |||
243 | } | 251 | } |
244 | 252 | ||
245 | static struct hpsb_protocol_driver fdtv_driver = { | 253 | static struct hpsb_protocol_driver fdtv_driver = { |
246 | |||
247 | .name = "firedtv", | 254 | .name = "firedtv", |
248 | .id_table = fdtv_id_table, | 255 | .update = node_update, |
249 | .update = fdtv_update, | ||
250 | |||
251 | .driver = { | 256 | .driver = { |
252 | //.name and .bus are filled in for us in more recent linux versions | 257 | .probe = node_probe, |
253 | //.name = "FireDTV", | 258 | .remove = node_remove, |
254 | //.bus = &ieee1394_bus_type, | ||
255 | .probe = fdtv_probe, | ||
256 | .remove = fdtv_remove, | ||
257 | }, | 259 | }, |
258 | }; | 260 | }; |
259 | 261 | ||
@@ -262,11 +264,12 @@ static struct hpsb_highlevel fdtv_highlevel = { | |||
262 | .fcp_request = fcp_request, | 264 | .fcp_request = fcp_request, |
263 | }; | 265 | }; |
264 | 266 | ||
265 | static int __init fdtv_init(void) | 267 | int __init fdtv_1394_init(struct ieee1394_device_id id_table[]) |
266 | { | 268 | { |
267 | int ret; | 269 | int ret; |
268 | 270 | ||
269 | hpsb_register_highlevel(&fdtv_highlevel); | 271 | hpsb_register_highlevel(&fdtv_highlevel); |
272 | fdtv_driver.id_table = id_table; | ||
270 | ret = hpsb_register_protocol(&fdtv_driver); | 273 | ret = hpsb_register_protocol(&fdtv_driver); |
271 | if (ret) { | 274 | if (ret) { |
272 | printk(KERN_ERR "firedtv: failed to register protocol\n"); | 275 | printk(KERN_ERR "firedtv: failed to register protocol\n"); |
@@ -275,17 +278,8 @@ static int __init fdtv_init(void) | |||
275 | return ret; | 278 | return ret; |
276 | } | 279 | } |
277 | 280 | ||
278 | static void __exit fdtv_exit(void) | 281 | void __exit fdtv_1394_exit(void) |
279 | { | 282 | { |
280 | hpsb_unregister_protocol(&fdtv_driver); | 283 | hpsb_unregister_protocol(&fdtv_driver); |
281 | hpsb_unregister_highlevel(&fdtv_highlevel); | 284 | hpsb_unregister_highlevel(&fdtv_highlevel); |
282 | } | 285 | } |
283 | |||
284 | module_init(fdtv_init); | ||
285 | module_exit(fdtv_exit); | ||
286 | |||
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"); | ||