2 * FireDTV driver -- firewire I/O backend
5 #include <linux/device.h>
6 #include <linux/errno.h>
7 #include <linux/firewire.h>
8 #include <linux/firewire-constants.h>
9 #include <linux/kernel.h>
10 #include <linux/list.h>
12 #include <linux/mod_devicetable.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/slab.h>
16 #include <linux/spinlock.h>
17 #include <linux/string.h>
18 #include <linux/types.h>
19 #include <linux/wait.h>
20 #include <linux/workqueue.h>
24 #include <dvb_demux.h>
28 static LIST_HEAD(node_list
);
29 static DEFINE_SPINLOCK(node_list_lock
);
31 static inline struct fw_device
*device_of(struct firedtv
*fdtv
)
33 return fw_device(fdtv
->device
->parent
);
36 static int node_req(struct firedtv
*fdtv
, u64 addr
, void *data
, size_t len
,
39 struct fw_device
*device
= device_of(fdtv
);
40 int rcode
, generation
= device
->generation
;
42 smp_rmb(); /* node_id vs. generation */
44 rcode
= fw_run_transaction(device
->card
, tcode
, device
->node_id
,
45 generation
, device
->max_speed
, addr
, data
, len
);
47 return rcode
!= RCODE_COMPLETE
? -EIO
: 0;
50 int fdtv_lock(struct firedtv
*fdtv
, u64 addr
, void *data
)
52 return node_req(fdtv
, addr
, data
, 8, TCODE_LOCK_COMPARE_SWAP
);
55 int fdtv_read(struct firedtv
*fdtv
, u64 addr
, void *data
)
57 return node_req(fdtv
, addr
, data
, 4, TCODE_READ_QUADLET_REQUEST
);
60 int fdtv_write(struct firedtv
*fdtv
, u64 addr
, void *data
, size_t len
)
62 return node_req(fdtv
, addr
, data
, len
, TCODE_WRITE_BLOCK_REQUEST
);
65 #define ISO_HEADER_SIZE 4
66 #define CIP_HEADER_SIZE 8
67 #define MPEG2_TS_HEADER_SIZE 4
68 #define MPEG2_TS_SOURCE_PACKET_SIZE (4 + 188)
70 #define MAX_PACKET_SIZE 1024 /* 776, rounded up to 2^n */
71 #define PACKETS_PER_PAGE (PAGE_SIZE / MAX_PACKET_SIZE)
72 #define N_PACKETS 64 /* buffer size */
73 #define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
74 #define IRQ_INTERVAL 16
76 struct fdtv_ir_context
{
77 struct fw_iso_context
*context
;
78 struct fw_iso_buffer buffer
;
84 static int queue_iso(struct fdtv_ir_context
*ctx
, int index
)
86 struct fw_iso_packet p
;
88 p
.payload_length
= MAX_PACKET_SIZE
;
89 p
.interrupt
= !(++ctx
->interrupt_packet
& (IRQ_INTERVAL
- 1));
91 p
.header_length
= ISO_HEADER_SIZE
;
93 return fw_iso_context_queue(ctx
->context
, &p
, &ctx
->buffer
,
94 index
* MAX_PACKET_SIZE
);
97 static void handle_iso(struct fw_iso_context
*context
, u32 cycle
,
98 size_t header_length
, void *header
, void *data
)
100 struct firedtv
*fdtv
= data
;
101 struct fdtv_ir_context
*ctx
= fdtv
->ir_context
;
103 int length
, err
, i
= ctx
->current_packet
;
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
;
113 p
= ctx
->pages
[i
/ PACKETS_PER_PAGE
]
114 + (i
% PACKETS_PER_PAGE
) * MAX_PACKET_SIZE
;
117 for (p
+= CIP_HEADER_SIZE
+ MPEG2_TS_HEADER_SIZE
; p
< p_end
;
118 p
+= MPEG2_TS_SOURCE_PACKET_SIZE
)
119 dvb_dmx_swfilter_packets(&fdtv
->demux
, p
, 1);
121 err
= queue_iso(ctx
, i
);
123 dev_err(fdtv
->device
, "requeue failed\n");
125 i
= (i
+ 1) & (N_PACKETS
- 1);
127 fw_iso_context_queue_flush(ctx
->context
);
128 ctx
->current_packet
= i
;
131 int fdtv_start_iso(struct firedtv
*fdtv
)
133 struct fdtv_ir_context
*ctx
;
134 struct fw_device
*device
= device_of(fdtv
);
137 ctx
= kmalloc(sizeof(*ctx
), GFP_KERNEL
);
141 ctx
->context
= fw_iso_context_create(device
->card
,
142 FW_ISO_CONTEXT_RECEIVE
, fdtv
->isochannel
,
143 device
->max_speed
, ISO_HEADER_SIZE
, handle_iso
, fdtv
);
144 if (IS_ERR(ctx
->context
)) {
145 err
= PTR_ERR(ctx
->context
);
149 err
= fw_iso_buffer_init(&ctx
->buffer
, device
->card
,
150 N_PAGES
, DMA_FROM_DEVICE
);
152 goto fail_context_destroy
;
154 ctx
->interrupt_packet
= 0;
155 ctx
->current_packet
= 0;
157 for (i
= 0; i
< N_PAGES
; i
++)
158 ctx
->pages
[i
] = page_address(ctx
->buffer
.pages
[i
]);
160 for (i
= 0; i
< N_PACKETS
; i
++) {
161 err
= queue_iso(ctx
, i
);
166 err
= fw_iso_context_start(ctx
->context
, -1, 0,
167 FW_ISO_CONTEXT_MATCH_ALL_TAGS
);
171 fdtv
->ir_context
= ctx
;
175 fw_iso_buffer_destroy(&ctx
->buffer
, device
->card
);
176 fail_context_destroy
:
177 fw_iso_context_destroy(ctx
->context
);
184 void fdtv_stop_iso(struct firedtv
*fdtv
)
186 struct fdtv_ir_context
*ctx
= fdtv
->ir_context
;
188 fw_iso_context_stop(ctx
->context
);
189 fw_iso_buffer_destroy(&ctx
->buffer
, device_of(fdtv
)->card
);
190 fw_iso_context_destroy(ctx
->context
);
194 static void handle_fcp(struct fw_card
*card
, struct fw_request
*request
,
195 int tcode
, int destination
, int source
, int generation
,
196 unsigned long long offset
, void *payload
, size_t length
,
199 struct firedtv
*f
, *fdtv
= NULL
;
200 struct fw_device
*device
;
204 if (length
< 2 || (((u8
*)payload
)[0] & 0xf0) != 0)
207 su
= ((u8
*)payload
)[1] & 0x7;
209 spin_lock_irqsave(&node_list_lock
, flags
);
210 list_for_each_entry(f
, &node_list
, list
) {
211 device
= device_of(f
);
212 if (device
->generation
!= generation
)
215 smp_rmb(); /* node_id vs. generation */
217 if (device
->card
== card
&&
218 device
->node_id
== source
&&
219 (f
->subunit
== su
|| (f
->subunit
== 0 && su
== 0x7))) {
224 spin_unlock_irqrestore(&node_list_lock
, flags
);
227 avc_recv(fdtv
, payload
, length
);
230 static struct fw_address_handler fcp_handler
= {
231 .length
= CSR_FCP_END
- CSR_FCP_RESPONSE
,
232 .address_callback
= handle_fcp
,
235 static const struct fw_address_region fcp_region
= {
236 .start
= CSR_REGISTER_BASE
+ CSR_FCP_RESPONSE
,
237 .end
= CSR_REGISTER_BASE
+ CSR_FCP_END
,
240 static const char * const model_names
[] = {
241 [FIREDTV_UNKNOWN
] = "unknown type",
242 [FIREDTV_DVB_S
] = "FireDTV S/CI",
243 [FIREDTV_DVB_C
] = "FireDTV C/CI",
244 [FIREDTV_DVB_T
] = "FireDTV T/CI",
245 [FIREDTV_DVB_S2
] = "FireDTV S2 ",
248 /* Adjust the template string if models with longer names appear. */
249 #define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
251 static int node_probe(struct fw_unit
*unit
, const struct ieee1394_device_id
*id
)
253 struct firedtv
*fdtv
;
254 char name
[MAX_MODEL_NAME_LEN
];
255 int name_len
, i
, err
;
257 fdtv
= kzalloc(sizeof(*fdtv
), GFP_KERNEL
);
261 dev_set_drvdata(&unit
->device
, fdtv
);
262 fdtv
->device
= &unit
->device
;
263 fdtv
->isochannel
= -1;
264 fdtv
->voltage
= 0xff;
267 mutex_init(&fdtv
->avc_mutex
);
268 init_waitqueue_head(&fdtv
->avc_wait
);
269 mutex_init(&fdtv
->demux_mutex
);
270 INIT_WORK(&fdtv
->remote_ctrl_work
, avc_remote_ctrl_work
);
272 name_len
= fw_csr_string(unit
->directory
, CSR_MODEL
,
274 for (i
= ARRAY_SIZE(model_names
); --i
; )
275 if (strlen(model_names
[i
]) <= name_len
&&
276 strncmp(name
, model_names
[i
], name_len
) == 0)
280 err
= fdtv_register_rc(fdtv
, &unit
->device
);
284 spin_lock_irq(&node_list_lock
);
285 list_add_tail(&fdtv
->list
, &node_list
);
286 spin_unlock_irq(&node_list_lock
);
288 err
= avc_identify_subunit(fdtv
);
292 err
= fdtv_dvb_register(fdtv
, model_names
[fdtv
->type
]);
296 avc_register_remote_control(fdtv
);
300 spin_lock_irq(&node_list_lock
);
301 list_del(&fdtv
->list
);
302 spin_unlock_irq(&node_list_lock
);
303 fdtv_unregister_rc(fdtv
);
310 static void node_remove(struct fw_unit
*unit
)
312 struct firedtv
*fdtv
= dev_get_drvdata(&unit
->device
);
314 fdtv_dvb_unregister(fdtv
);
316 spin_lock_irq(&node_list_lock
);
317 list_del(&fdtv
->list
);
318 spin_unlock_irq(&node_list_lock
);
320 fdtv_unregister_rc(fdtv
);
325 static void node_update(struct fw_unit
*unit
)
327 struct firedtv
*fdtv
= dev_get_drvdata(&unit
->device
);
329 if (fdtv
->isochannel
>= 0)
330 cmp_establish_pp_connection(fdtv
, fdtv
->subunit
,
334 #define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
335 IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
337 #define DIGITAL_EVERYWHERE_OUI 0x001287
338 #define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
339 #define AVC_SW_VERSION_ENTRY 0x010001
341 static const struct ieee1394_device_id fdtv_id_table
[] = {
343 /* FloppyDTV S/CI and FloppyDTV S2 */
344 .match_flags
= MATCH_FLAGS
,
345 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
346 .model_id
= 0x000024,
347 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
348 .version
= AVC_SW_VERSION_ENTRY
,
351 .match_flags
= MATCH_FLAGS
,
352 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
353 .model_id
= 0x000025,
354 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
355 .version
= AVC_SW_VERSION_ENTRY
,
358 .match_flags
= MATCH_FLAGS
,
359 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
360 .model_id
= 0x000026,
361 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
362 .version
= AVC_SW_VERSION_ENTRY
,
364 /* FireDTV S/CI and FloppyDTV S2 */
365 .match_flags
= MATCH_FLAGS
,
366 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
367 .model_id
= 0x000034,
368 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
369 .version
= AVC_SW_VERSION_ENTRY
,
372 .match_flags
= MATCH_FLAGS
,
373 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
374 .model_id
= 0x000035,
375 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
376 .version
= AVC_SW_VERSION_ENTRY
,
379 .match_flags
= MATCH_FLAGS
,
380 .vendor_id
= DIGITAL_EVERYWHERE_OUI
,
381 .model_id
= 0x000036,
382 .specifier_id
= AVC_UNIT_SPEC_ID_ENTRY
,
383 .version
= AVC_SW_VERSION_ENTRY
,
386 MODULE_DEVICE_TABLE(ieee1394
, fdtv_id_table
);
388 static struct fw_driver fdtv_driver
= {
390 .owner
= THIS_MODULE
,
395 .update
= node_update
,
396 .remove
= node_remove
,
397 .id_table
= fdtv_id_table
,
400 static int __init
fdtv_init(void)
404 ret
= fw_core_add_address_handler(&fcp_handler
, &fcp_region
);
408 ret
= driver_register(&fdtv_driver
.driver
);
410 fw_core_remove_address_handler(&fcp_handler
);
415 static void __exit
fdtv_exit(void)
417 driver_unregister(&fdtv_driver
.driver
);
418 fw_core_remove_address_handler(&fcp_handler
);
421 module_init(fdtv_init
);
422 module_exit(fdtv_exit
);
424 MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
425 MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
426 MODULE_DESCRIPTION("FireDTV DVB Driver");
427 MODULE_LICENSE("GPL");
428 MODULE_SUPPORTED_DEVICE("FireDTV DVB");