blob: d8408cea335f7efc6fb49660416deaa852bfe423 [file] [log] [blame]
Stefan Richter87918332009-11-08 18:30:54 -03001/*
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>
Stefan Richter87918332009-11-08 18:30:54 -03009#include <linux/kernel.h>
10#include <linux/list.h>
Stefan Richtera8aeb782009-11-18 16:00:55 -030011#include <linux/mm.h>
Stefan Richter87918332009-11-08 18:30:54 -030012#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;
Stefan Richtera8aeb782009-11-18 16:00:55 -030076 char *pages[N_PAGES];
Stefan Richter87918332009-11-08 18:30:54 -030077};
78
79static int queue_iso(struct firedtv_receive_context *ctx, int index)
80{
81 struct fw_iso_packet p;
Stefan Richter87918332009-11-08 18:30:54 -030082
83 p.payload_length = MAX_PACKET_SIZE;
Stefan Richterb1d33f42009-11-18 16:01:14 -030084 p.interrupt = !(++ctx->interrupt_packet & (IRQ_INTERVAL - 1));
Stefan Richter87918332009-11-08 18:30:54 -030085 p.skip = 0;
86 p.header_length = ISO_HEADER_SIZE;
87
Stefan Richterb1d33f42009-11-18 16:01:14 -030088 return fw_iso_context_queue(ctx->context, &p, &ctx->buffer,
89 index * MAX_PACKET_SIZE);
Stefan Richter87918332009-11-08 18:30:54 -030090}
91
92static void handle_iso(struct fw_iso_context *context, u32 cycle,
93 size_t header_length, void *header, void *data)
94{
95 struct firedtv *fdtv = data;
96 struct firedtv_receive_context *ctx = fdtv->backend_data;
97 __be32 *h, *h_end;
Stefan Richtera8aeb782009-11-18 16:00:55 -030098 int length, err, i = ctx->current_packet;
Stefan Richter87918332009-11-08 18:30:54 -030099 char *p, *p_end;
100
101 for (h = header, h_end = h + header_length / 4; h < h_end; h++) {
102 length = be32_to_cpup(h) >> 16;
103 if (unlikely(length > MAX_PACKET_SIZE)) {
104 dev_err(fdtv->device, "length = %d\n", length);
105 length = MAX_PACKET_SIZE;
106 }
107
Stefan Richtera8aeb782009-11-18 16:00:55 -0300108 p = ctx->pages[i / PACKETS_PER_PAGE]
109 + (i % PACKETS_PER_PAGE) * MAX_PACKET_SIZE;
Stefan Richter87918332009-11-08 18:30:54 -0300110 p_end = p + length;
111
112 for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end;
113 p += MPEG2_TS_SOURCE_PACKET_SIZE)
114 dvb_dmx_swfilter_packets(&fdtv->demux, p, 1);
115
116 err = queue_iso(ctx, i);
117 if (unlikely(err))
118 dev_err(fdtv->device, "requeue failed\n");
119
120 i = (i + 1) & (N_PACKETS - 1);
121 }
122 ctx->current_packet = i;
123}
124
125static int start_iso(struct firedtv *fdtv)
126{
127 struct firedtv_receive_context *ctx;
128 struct fw_device *device = device_of(fdtv);
Stefan Richtera8aeb782009-11-18 16:00:55 -0300129 int i, err;
Stefan Richter87918332009-11-08 18:30:54 -0300130
131 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
132 if (!ctx)
133 return -ENOMEM;
134
135 ctx->context = fw_iso_context_create(device->card,
136 FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel,
137 device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv);
138 if (IS_ERR(ctx->context)) {
139 err = PTR_ERR(ctx->context);
140 goto fail_free;
141 }
142
143 err = fw_iso_buffer_init(&ctx->buffer, device->card,
144 N_PAGES, DMA_FROM_DEVICE);
145 if (err)
146 goto fail_context_destroy;
147
Stefan Richterb1d33f42009-11-18 16:01:14 -0300148 ctx->interrupt_packet = 0;
Stefan Richter87918332009-11-08 18:30:54 -0300149 ctx->current_packet = 0;
150
Stefan Richtera8aeb782009-11-18 16:00:55 -0300151 for (i = 0; i < N_PAGES; i++)
152 ctx->pages[i] = page_address(ctx->buffer.pages[i]);
Stefan Richter87918332009-11-08 18:30:54 -0300153
154 for (i = 0; i < N_PACKETS; i++) {
155 err = queue_iso(ctx, i);
156 if (err)
157 goto fail;
158 }
159
160 err = fw_iso_context_start(ctx->context, -1, 0,
161 FW_ISO_CONTEXT_MATCH_ALL_TAGS);
162 if (err)
163 goto fail;
164
165 fdtv->backend_data = ctx;
166
167 return 0;
168fail:
169 fw_iso_buffer_destroy(&ctx->buffer, device->card);
170fail_context_destroy:
171 fw_iso_context_destroy(ctx->context);
172fail_free:
173 kfree(ctx);
174
175 return err;
176}
177
178static void stop_iso(struct firedtv *fdtv)
179{
180 struct firedtv_receive_context *ctx = fdtv->backend_data;
181
182 fw_iso_context_stop(ctx->context);
183 fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
184 fw_iso_context_destroy(ctx->context);
185 kfree(ctx);
186}
187
188static const struct firedtv_backend backend = {
189 .lock = node_lock,
190 .read = node_read,
191 .write = node_write,
192 .start_iso = start_iso,
193 .stop_iso = stop_iso,
194};
195
196static void handle_fcp(struct fw_card *card, struct fw_request *request,
197 int tcode, int destination, int source, int generation,
198 int speed, unsigned long long offset,
199 void *payload, size_t length, void *callback_data)
200{
201 struct firedtv *f, *fdtv = NULL;
202 struct fw_device *device;
203 unsigned long flags;
204 int su;
205
206 if ((tcode != TCODE_WRITE_QUADLET_REQUEST &&
207 tcode != TCODE_WRITE_BLOCK_REQUEST) ||
208 offset != CSR_REGISTER_BASE + CSR_FCP_RESPONSE ||
209 length == 0 ||
210 (((u8 *)payload)[0] & 0xf0) != 0) {
211 fw_send_response(card, request, RCODE_TYPE_ERROR);
212 return;
213 }
214
215 su = ((u8 *)payload)[1] & 0x7;
216
217 spin_lock_irqsave(&node_list_lock, flags);
218 list_for_each_entry(f, &node_list, list) {
219 device = device_of(f);
220 if (device->generation != generation)
221 continue;
222
223 smp_rmb(); /* node_id vs. generation */
224
225 if (device->card == card &&
226 device->node_id == source &&
227 (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
228 fdtv = f;
229 break;
230 }
231 }
232 spin_unlock_irqrestore(&node_list_lock, flags);
233
234 if (fdtv) {
235 avc_recv(fdtv, payload, length);
236 fw_send_response(card, request, RCODE_COMPLETE);
237 }
238}
239
240static struct fw_address_handler fcp_handler = {
241 .length = CSR_FCP_END - CSR_FCP_RESPONSE,
242 .address_callback = handle_fcp,
243};
244
245static const struct fw_address_region fcp_region = {
246 .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
247 .end = CSR_REGISTER_BASE + CSR_FCP_END,
248};
249
250/* Adjust the template string if models with longer names appear. */
251#define MAX_MODEL_NAME_LEN ((int)DIV_ROUND_UP(sizeof("FireDTV ????"), 4))
252
253static size_t model_name(u32 *directory, __be32 *buffer)
254{
255 struct fw_csr_iterator ci;
256 int i, length, key, value, last_key = 0;
257 u32 *block = NULL;
258
259 fw_csr_iterator_init(&ci, directory);
260 while (fw_csr_iterator_next(&ci, &key, &value)) {
261 if (last_key == CSR_MODEL &&
262 key == (CSR_DESCRIPTOR | CSR_LEAF))
263 block = ci.p - 1 + value;
264 last_key = key;
265 }
266
267 if (block == NULL)
268 return 0;
269
270 length = min((int)(block[0] >> 16) - 2, MAX_MODEL_NAME_LEN);
271 if (length <= 0)
272 return 0;
273
274 /* fast-forward to text string */
275 block += 3;
276
277 for (i = 0; i < length; i++)
278 buffer[i] = cpu_to_be32(block[i]);
279
280 return length * 4;
281}
282
283static int node_probe(struct device *dev)
284{
285 struct firedtv *fdtv;
286 __be32 name[MAX_MODEL_NAME_LEN];
287 int name_len, err;
288
289 name_len = model_name(fw_unit(dev)->directory, name);
290
291 fdtv = fdtv_alloc(dev, &backend, (char *)name, name_len);
292 if (!fdtv)
293 return -ENOMEM;
294
295 err = fdtv_register_rc(fdtv, dev);
296 if (err)
297 goto fail_free;
298
299 spin_lock_irq(&node_list_lock);
300 list_add_tail(&fdtv->list, &node_list);
301 spin_unlock_irq(&node_list_lock);
302
303 err = avc_identify_subunit(fdtv);
304 if (err)
305 goto fail;
306
307 err = fdtv_dvb_register(fdtv);
308 if (err)
309 goto fail;
310
311 avc_register_remote_control(fdtv);
312
313 return 0;
314fail:
315 spin_lock_irq(&node_list_lock);
316 list_del(&fdtv->list);
317 spin_unlock_irq(&node_list_lock);
318 fdtv_unregister_rc(fdtv);
319fail_free:
320 kfree(fdtv);
321
322 return err;
323}
324
325static int node_remove(struct device *dev)
326{
327 struct firedtv *fdtv = dev_get_drvdata(dev);
328
329 fdtv_dvb_unregister(fdtv);
330
331 spin_lock_irq(&node_list_lock);
332 list_del(&fdtv->list);
333 spin_unlock_irq(&node_list_lock);
334
335 fdtv_unregister_rc(fdtv);
336
337 kfree(fdtv);
338 return 0;
339}
340
341static void node_update(struct fw_unit *unit)
342{
343 struct firedtv *fdtv = dev_get_drvdata(&unit->device);
344
345 if (fdtv->isochannel >= 0)
346 cmp_establish_pp_connection(fdtv, fdtv->subunit,
347 fdtv->isochannel);
348}
349
350static struct fw_driver fdtv_driver = {
351 .driver = {
352 .owner = THIS_MODULE,
353 .name = "firedtv",
354 .bus = &fw_bus_type,
355 .probe = node_probe,
356 .remove = node_remove,
357 },
358 .update = node_update,
359 .id_table = fdtv_id_table,
360};
361
362int __init fdtv_fw_init(void)
363{
364 int ret;
365
366 ret = fw_core_add_address_handler(&fcp_handler, &fcp_region);
367 if (ret < 0)
368 return ret;
369
370 return driver_register(&fdtv_driver.driver);
371}
372
373void fdtv_fw_exit(void)
374{
375 driver_unregister(&fdtv_driver.driver);
376 fw_core_remove_address_handler(&fcp_handler);
377}