aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2009-11-08 16:30:54 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:41:42 -0500
commit87918334792a4d8a73b0511466b77bd6aa055db3 (patch)
tree56f9e71c5d88cb0bf3a027a56588fb33c232f733 /drivers/media/dvb
parent6e25abb522e055beeaf887f50a49cb370acc62b6 (diff)
V4L/DVB (13400): firedtv: port to new firewire core
The firedtv DVB driver will now work not only on top of the old ieee1394 driver stack but also on the new firewire driver stack. Alongside to the firedtv-1394.c backend for driver binding and I/O, the firedtv-fw.c backend is added. Depending on which of the two 1394 stacks is configured, one or the other or both backends will be built into the firedtv driver. This has been tested with a DVB-T and a DVB-C box on x86-64 and x86-32 together with a few different controllers (Agere FW323, a NEC chip, TI TSB82AA2, TSB43AB22/A, VIA VT6306). Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb')
-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);