aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/dvb/firewire/Kconfig7
-rw-r--r--drivers/media/dvb/firewire/Makefile1
-rw-r--r--drivers/media/dvb/firewire/firedtv-1394.c6
-rw-r--r--drivers/media/dvb/firewire/firedtv-dvb.c15
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c385
-rw-r--r--drivers/media/dvb/firewire/firedtv.h15
6 files changed, 420 insertions, 9 deletions
diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig
index 69028253e984..4afa29256df1 100644
--- a/drivers/media/dvb/firewire/Kconfig
+++ b/drivers/media/dvb/firewire/Kconfig
@@ -1,6 +1,6 @@
1config DVB_FIREDTV 1config DVB_FIREDTV
2 tristate "FireDTV and FloppyDTV" 2 tristate "FireDTV and FloppyDTV"
3 depends on DVB_CORE && IEEE1394 3 depends on DVB_CORE && (FIREWIRE || IEEE1394)
4 help 4 help
5 Support for DVB receivers from Digital Everywhere 5 Support for DVB receivers from Digital Everywhere
6 which are connected via IEEE 1394 (FireWire). 6 which are connected via IEEE 1394 (FireWire).
@@ -13,8 +13,11 @@ config DVB_FIREDTV
13 13
14if DVB_FIREDTV 14if DVB_FIREDTV
15 15
16config DVB_FIREDTV_FIREWIRE
17 def_bool FIREWIRE = y || (FIREWIRE = m && DVB_FIREDTV = m)
18
16config DVB_FIREDTV_IEEE1394 19config DVB_FIREDTV_IEEE1394
17 def_bool IEEE1394 20 def_bool IEEE1394 = y || (IEEE1394 = m && DVB_FIREDTV = m)
18 21
19config DVB_FIREDTV_INPUT 22config DVB_FIREDTV_INPUT
20 def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m) 23 def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile
index 2034695ba194..da84203d51c6 100644
--- a/drivers/media/dvb/firewire/Makefile
+++ b/drivers/media/dvb/firewire/Makefile
@@ -1,6 +1,7 @@
1obj-$(CONFIG_DVB_FIREDTV) += firedtv.o 1obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
2 2
3firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o 3firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o
4firedtv-$(CONFIG_DVB_FIREDTV_FIREWIRE) += firedtv-fw.o
4firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o 5firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o
5firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o 6firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o
6 7
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
index 82b576a4774d..ed98fdb650c5 100644
--- a/drivers/media/dvb/firewire/firedtv-1394.c
+++ b/drivers/media/dvb/firewire/firedtv-1394.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * FireDTV driver (formerly known as FireSAT) 2 * FireDTV driver -- ieee1394 I/O backend
3 * 3 *
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> 4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com> 5 * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
@@ -261,6 +261,7 @@ static int node_update(struct unit_directory *ud)
261 261
262static struct hpsb_protocol_driver fdtv_driver = { 262static struct hpsb_protocol_driver fdtv_driver = {
263 .name = "firedtv", 263 .name = "firedtv",
264 .id_table = fdtv_id_table,
264 .update = node_update, 265 .update = node_update,
265 .driver = { 266 .driver = {
266 .probe = node_probe, 267 .probe = node_probe,
@@ -273,12 +274,11 @@ static struct hpsb_highlevel fdtv_highlevel = {
273 .fcp_request = fcp_request, 274 .fcp_request = fcp_request,
274}; 275};
275 276
276int __init fdtv_1394_init(struct ieee1394_device_id id_table[]) 277int __init fdtv_1394_init(void)
277{ 278{
278 int ret; 279 int ret;
279 280
280 hpsb_register_highlevel(&fdtv_highlevel); 281 hpsb_register_highlevel(&fdtv_highlevel);
281 fdtv_driver.id_table = id_table;
282 ret = hpsb_register_protocol(&fdtv_driver); 282 ret = hpsb_register_protocol(&fdtv_driver);
283 if (ret) { 283 if (ret) {
284 printk(KERN_ERR "firedtv: failed to register protocol\n"); 284 printk(KERN_ERR "firedtv: failed to register protocol\n");
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
index 5742fde79d99..fc9996c13e13 100644
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ b/drivers/media/dvb/firewire/firedtv-dvb.c
@@ -297,7 +297,7 @@ struct firedtv *fdtv_alloc(struct device *dev,
297#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d 297#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
298#define AVC_SW_VERSION_ENTRY 0x010001 298#define AVC_SW_VERSION_ENTRY 0x010001
299 299
300static struct ieee1394_device_id fdtv_id_table[] = { 300const struct ieee1394_device_id fdtv_id_table[] = {
301 { 301 {
302 /* FloppyDTV S/CI and FloppyDTV S2 */ 302 /* FloppyDTV S/CI and FloppyDTV S2 */
303 .match_flags = MATCH_FLAGS, 303 .match_flags = MATCH_FLAGS,
@@ -346,12 +346,23 @@ MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
346 346
347static int __init fdtv_init(void) 347static int __init fdtv_init(void)
348{ 348{
349 return fdtv_1394_init(fdtv_id_table); 349 int ret;
350
351 ret = fdtv_fw_init();
352 if (ret < 0)
353 return ret;
354
355 ret = fdtv_1394_init();
356 if (ret < 0)
357 fdtv_fw_exit();
358
359 return ret;
350} 360}
351 361
352static void __exit fdtv_exit(void) 362static void __exit fdtv_exit(void)
353{ 363{
354 fdtv_1394_exit(); 364 fdtv_1394_exit();
365 fdtv_fw_exit();
355} 366}
356 367
357module_init(fdtv_init); 368module_init(fdtv_init);
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
new file mode 100644
index 000000000000..208e5b59e830
--- /dev/null
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -0,0 +1,385 @@
1/*
2 * FireDTV driver -- firewire I/O backend
3 */
4
5#include <linux/device.h>
6#include <linux/errno.h>
7#include <linux/firewire.h>
8#include <linux/firewire-constants.h>
9#include <linux/highmem.h>
10#include <linux/kernel.h>
11#include <linux/list.h>
12#include <linux/slab.h>
13#include <linux/spinlock.h>
14#include <linux/types.h>
15
16#include <asm/page.h>
17
18#include <dvb_demux.h>
19
20#include "firedtv.h"
21
22static LIST_HEAD(node_list);
23static DEFINE_SPINLOCK(node_list_lock);
24
25static inline struct fw_device *device_of(struct firedtv *fdtv)
26{
27 return fw_device(fdtv->device->parent);
28}
29
30static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
31 int tcode)
32{
33 struct fw_device *device = device_of(fdtv);
34 int rcode, generation = device->generation;
35
36 smp_rmb(); /* node_id vs. generation */
37
38 rcode = fw_run_transaction(device->card, tcode, device->node_id,
39 generation, device->max_speed, addr, data, len);
40
41 return rcode != RCODE_COMPLETE ? -EIO : 0;
42}
43
44static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
45{
46 return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
47}
48
49static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len)
50{
51 return node_req(fdtv, addr, data, len, len == 4 ?
52 TCODE_READ_QUADLET_REQUEST : TCODE_READ_BLOCK_REQUEST);
53}
54
55static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
56{
57 return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST);
58}
59
60#define ISO_HEADER_SIZE 4
61#define CIP_HEADER_SIZE 8
62#define MPEG2_TS_HEADER_SIZE 4
63#define MPEG2_TS_SOURCE_PACKET_SIZE (4 + 188)
64
65#define MAX_PACKET_SIZE 1024 /* 776, rounded up to 2^n */
66#define PACKETS_PER_PAGE (PAGE_SIZE / MAX_PACKET_SIZE)
67#define N_PACKETS 64 /* buffer size */
68#define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
69#define IRQ_INTERVAL 16
70
71struct firedtv_receive_context {
72 struct fw_iso_context *context;
73 struct fw_iso_buffer buffer;
74 int interrupt_packet;
75 int current_packet;
76 char *packets[N_PACKETS];
77};
78
79static int queue_iso(struct firedtv_receive_context *ctx, int index)
80{
81 struct fw_iso_packet p;
82 int err;
83
84 p.payload_length = MAX_PACKET_SIZE;
85 p.interrupt = !(ctx->interrupt_packet & (IRQ_INTERVAL - 1));
86 p.skip = 0;
87 p.header_length = ISO_HEADER_SIZE;
88
89 err = fw_iso_context_queue(ctx->context, &p, &ctx->buffer,
90 index * MAX_PACKET_SIZE);
91 if (!err)
92 ctx->interrupt_packet++;
93
94 return err;
95}
96
97static void handle_iso(struct fw_iso_context *context, u32 cycle,
98 size_t header_length, void *header, void *data)
99{
100 struct firedtv *fdtv = data;
101 struct firedtv_receive_context *ctx = fdtv->backend_data;
102 __be32 *h, *h_end;
103 int i = ctx->current_packet, length, err;
104 char *p, *p_end;
105
106 for (h = header, h_end = h + header_length / 4; h < h_end; h++) {
107 length = be32_to_cpup(h) >> 16;
108 if (unlikely(length > MAX_PACKET_SIZE)) {
109 dev_err(fdtv->device, "length = %d\n", length);
110 length = MAX_PACKET_SIZE;
111 }
112
113 p = ctx->packets[i];
114 p_end = p + length;
115
116 for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end;
117 p += MPEG2_TS_SOURCE_PACKET_SIZE)
118 dvb_dmx_swfilter_packets(&fdtv->demux, p, 1);
119
120 err = queue_iso(ctx, i);
121 if (unlikely(err))
122 dev_err(fdtv->device, "requeue failed\n");
123
124 i = (i + 1) & (N_PACKETS - 1);
125 }
126 ctx->current_packet = i;
127}
128
129static int start_iso(struct firedtv *fdtv)
130{
131 struct firedtv_receive_context *ctx;
132 struct fw_device *device = device_of(fdtv);
133 char *p;
134 int i, j, k, err;
135
136 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
137 if (!ctx)
138 return -ENOMEM;
139
140 ctx->context = fw_iso_context_create(device->card,
141 FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel,
142 device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv);
143 if (IS_ERR(ctx->context)) {
144 err = PTR_ERR(ctx->context);
145 goto fail_free;
146 }
147
148 err = fw_iso_buffer_init(&ctx->buffer, device->card,
149 N_PAGES, DMA_FROM_DEVICE);
150 if (err)
151 goto fail_context_destroy;
152
153 ctx->interrupt_packet = 1;
154 ctx->current_packet = 0;
155
156 for (i = 0, k = 0; k < N_PAGES; k++) {
157 p = kmap(ctx->buffer.pages[k]);
158 for (j = 0; j < PACKETS_PER_PAGE && i < N_PACKETS; j++, i++)
159 ctx->packets[i] = p + j * MAX_PACKET_SIZE;
160 }
161
162 for (i = 0; i < N_PACKETS; i++) {
163 err = queue_iso(ctx, i);
164 if (err)
165 goto fail;
166 }
167
168 err = fw_iso_context_start(ctx->context, -1, 0,
169 FW_ISO_CONTEXT_MATCH_ALL_TAGS);
170 if (err)
171 goto fail;
172
173 fdtv->backend_data = ctx;
174
175 return 0;
176fail:
177 fw_iso_buffer_destroy(&ctx->buffer, device->card);
178fail_context_destroy:
179 fw_iso_context_destroy(ctx->context);
180fail_free:
181 kfree(ctx);
182
183 return err;
184}
185
186static void stop_iso(struct firedtv *fdtv)
187{
188 struct firedtv_receive_context *ctx = fdtv->backend_data;
189
190 fw_iso_context_stop(ctx->context);
191 fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
192 fw_iso_context_destroy(ctx->context);
193 kfree(ctx);
194}
195
196static const struct firedtv_backend backend = {
197 .lock = node_lock,
198 .read = node_read,
199 .write = node_write,
200 .start_iso = start_iso,
201 .stop_iso = stop_iso,
202};
203
204static void handle_fcp(struct fw_card *card, struct fw_request *request,
205 int tcode, int destination, int source, int generation,
206 int speed, unsigned long long offset,
207 void *payload, size_t length, void *callback_data)
208{
209 struct firedtv *f, *fdtv = NULL;
210 struct fw_device *device;
211 unsigned long flags;
212 int su;
213
214 if ((tcode != TCODE_WRITE_QUADLET_REQUEST &&
215 tcode != TCODE_WRITE_BLOCK_REQUEST) ||
216 offset != CSR_REGISTER_BASE + CSR_FCP_RESPONSE ||
217 length == 0 ||
218 (((u8 *)payload)[0] & 0xf0) != 0) {
219 fw_send_response(card, request, RCODE_TYPE_ERROR);
220 return;
221 }
222
223 su = ((u8 *)payload)[1] & 0x7;
224
225 spin_lock_irqsave(&node_list_lock, flags);
226 list_for_each_entry(f, &node_list, list) {
227 device = device_of(f);
228 if (device->generation != generation)
229 continue;
230
231 smp_rmb(); /* node_id vs. generation */
232
233 if (device->card == card &&
234 device->node_id == source &&
235 (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
236 fdtv = f;
237 break;
238 }
239 }
240 spin_unlock_irqrestore(&node_list_lock, flags);
241
242 if (fdtv) {
243 avc_recv(fdtv, payload, length);
244 fw_send_response(card, request, RCODE_COMPLETE);
245 }
246}
247
248static struct fw_address_handler fcp_handler = {
249 .length = CSR_FCP_END - CSR_FCP_RESPONSE,
250 .address_callback = handle_fcp,
251};
252
253static const struct fw_address_region fcp_region = {
254 .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
255 .end = CSR_REGISTER_BASE + CSR_FCP_END,
256};
257
258/* Adjust the template string if models with longer names appear. */
259#define MAX_MODEL_NAME_LEN ((int)DIV_ROUND_UP(sizeof("FireDTV ????"), 4))
260
261static size_t model_name(u32 *directory, __be32 *buffer)
262{
263 struct fw_csr_iterator ci;
264 int i, length, key, value, last_key = 0;
265 u32 *block = NULL;
266
267 fw_csr_iterator_init(&ci, directory);
268 while (fw_csr_iterator_next(&ci, &key, &value)) {
269 if (last_key == CSR_MODEL &&
270 key == (CSR_DESCRIPTOR | CSR_LEAF))
271 block = ci.p - 1 + value;
272 last_key = key;
273 }
274
275 if (block == NULL)
276 return 0;
277
278 length = min((int)(block[0] >> 16) - 2, MAX_MODEL_NAME_LEN);
279 if (length <= 0)
280 return 0;
281
282 /* fast-forward to text string */
283 block += 3;
284
285 for (i = 0; i < length; i++)
286 buffer[i] = cpu_to_be32(block[i]);
287
288 return length * 4;
289}
290
291static int node_probe(struct device *dev)
292{
293 struct firedtv *fdtv;
294 __be32 name[MAX_MODEL_NAME_LEN];
295 int name_len, err;
296
297 name_len = model_name(fw_unit(dev)->directory, name);
298
299 fdtv = fdtv_alloc(dev, &backend, (char *)name, name_len);
300 if (!fdtv)
301 return -ENOMEM;
302
303 err = fdtv_register_rc(fdtv, dev);
304 if (err)
305 goto fail_free;
306
307 spin_lock_irq(&node_list_lock);
308 list_add_tail(&fdtv->list, &node_list);
309 spin_unlock_irq(&node_list_lock);
310
311 err = avc_identify_subunit(fdtv);
312 if (err)
313 goto fail;
314
315 err = fdtv_dvb_register(fdtv);
316 if (err)
317 goto fail;
318
319 avc_register_remote_control(fdtv);
320
321 return 0;
322fail:
323 spin_lock_irq(&node_list_lock);
324 list_del(&fdtv->list);
325 spin_unlock_irq(&node_list_lock);
326 fdtv_unregister_rc(fdtv);
327fail_free:
328 kfree(fdtv);
329
330 return err;
331}
332
333static int node_remove(struct device *dev)
334{
335 struct firedtv *fdtv = dev_get_drvdata(dev);
336
337 fdtv_dvb_unregister(fdtv);
338
339 spin_lock_irq(&node_list_lock);
340 list_del(&fdtv->list);
341 spin_unlock_irq(&node_list_lock);
342
343 fdtv_unregister_rc(fdtv);
344
345 kfree(fdtv);
346 return 0;
347}
348
349static void node_update(struct fw_unit *unit)
350{
351 struct firedtv *fdtv = dev_get_drvdata(&unit->device);
352
353 if (fdtv->isochannel >= 0)
354 cmp_establish_pp_connection(fdtv, fdtv->subunit,
355 fdtv->isochannel);
356}
357
358static struct fw_driver fdtv_driver = {
359 .driver = {
360 .owner = THIS_MODULE,
361 .name = "firedtv",
362 .bus = &fw_bus_type,
363 .probe = node_probe,
364 .remove = node_remove,
365 },
366 .update = node_update,
367 .id_table = fdtv_id_table,
368};
369
370int __init fdtv_fw_init(void)
371{
372 int ret;
373
374 ret = fw_core_add_address_handler(&fcp_handler, &fcp_region);
375 if (ret < 0)
376 return ret;
377
378 return driver_register(&fdtv_driver.driver);
379}
380
381void fdtv_fw_exit(void)
382{
383 driver_unregister(&fdtv_driver.driver);
384 fw_core_remove_address_handler(&fcp_handler);
385}
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
index 1b99660a8397..f7b5c030bedf 100644
--- a/drivers/media/dvb/firewire/firedtv.h
+++ b/drivers/media/dvb/firewire/firedtv.h
@@ -16,6 +16,7 @@
16#include <linux/dvb/dmx.h> 16#include <linux/dvb/dmx.h>
17#include <linux/dvb/frontend.h> 17#include <linux/dvb/frontend.h>
18#include <linux/list.h> 18#include <linux/list.h>
19#include <linux/mod_devicetable.h>
19#include <linux/mutex.h> 20#include <linux/mutex.h>
20#include <linux/spinlock_types.h> 21#include <linux/spinlock_types.h>
21#include <linux/types.h> 22#include <linux/types.h>
@@ -119,10 +120,10 @@ struct firedtv {
119 120
120/* firedtv-1394.c */ 121/* firedtv-1394.c */
121#ifdef CONFIG_DVB_FIREDTV_IEEE1394 122#ifdef CONFIG_DVB_FIREDTV_IEEE1394
122int fdtv_1394_init(struct ieee1394_device_id id_table[]); 123int fdtv_1394_init(void);
123void fdtv_1394_exit(void); 124void fdtv_1394_exit(void);
124#else 125#else
125static inline int fdtv_1394_init(struct ieee1394_device_id it[]) { return 0; } 126static inline int fdtv_1394_init(void) { return 0; }
126static inline void fdtv_1394_exit(void) {} 127static inline void fdtv_1394_exit(void) {}
127#endif 128#endif
128 129
@@ -163,10 +164,20 @@ struct firedtv *fdtv_alloc(struct device *dev,
163 const struct firedtv_backend *backend, 164 const struct firedtv_backend *backend,
164 const char *name, size_t name_len); 165 const char *name, size_t name_len);
165extern const char *fdtv_model_names[]; 166extern const char *fdtv_model_names[];
167extern const struct ieee1394_device_id fdtv_id_table[];
166 168
167/* firedtv-fe.c */ 169/* firedtv-fe.c */
168void fdtv_frontend_init(struct firedtv *fdtv); 170void fdtv_frontend_init(struct firedtv *fdtv);
169 171
172/* firedtv-fw.c */
173#ifdef CONFIG_DVB_FIREDTV_FIREWIRE
174int fdtv_fw_init(void);
175void fdtv_fw_exit(void);
176#else
177static inline int fdtv_fw_init(void) { return 0; }
178static inline void fdtv_fw_exit(void) {}
179#endif
180
170/* firedtv-rc.c */ 181/* firedtv-rc.c */
171#ifdef CONFIG_DVB_FIREDTV_INPUT 182#ifdef CONFIG_DVB_FIREDTV_INPUT
172int fdtv_register_rc(struct firedtv *fdtv, struct device *dev); 183int fdtv_register_rc(struct firedtv *fdtv, struct device *dev);