firewire: add isochronous multichannel reception
This adds the DMA context programming and userspace ABI for multichannel reception, i.e. for listening on multiple channel numbers by means of a single DMA context. The use case is reception of more streams than there are IR DMA units offered by the link layer. This is already implemented by the older ohci1394 + ieee1394 + raw1394 stack. And as discussed recently on linux1394-devel, this feature is occasionally used in practice. The big drawbacks of this mode are that buffer layout and interrupt generation necessarily differ from single-channel reception: Headers and trailers are not stripped from packets, packets are not aligned with buffer chunks, interrupts are per buffer chunk, not per packet. These drawbacks also cause a rather hefty code footprint to support this rarely used OHCI-1394 feature. (367 lines added, among them 94 lines of added userspace ABI documentation.) This implementation enforces that a multichannel reception context may only listen to channels to which no single-channel context on the same link layer is presently listening to. OHCI-1394 would allow to overlay single-channel contexts by the multi-channel context, but this would be a departure from the present first-come-first-served policy of IR context creation. The implementation is heavily based on an earlier one by Jay Fenlason. Thanks Jay. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
@@ -117,6 +117,23 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
|
||||
}
|
||||
EXPORT_SYMBOL(fw_iso_buffer_destroy);
|
||||
|
||||
/* Convert DMA address to offset into virtually contiguous buffer. */
|
||||
size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed)
|
||||
{
|
||||
int i;
|
||||
dma_addr_t address;
|
||||
ssize_t offset;
|
||||
|
||||
for (i = 0; i < buffer->page_count; i++) {
|
||||
address = page_private(buffer->pages[i]);
|
||||
offset = (ssize_t)completed - (ssize_t)address;
|
||||
if (offset > 0 && offset <= PAGE_SIZE)
|
||||
return (i << PAGE_SHIFT) + offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
|
||||
int type, int channel, int speed, size_t header_size,
|
||||
fw_iso_callback_t callback, void *callback_data)
|
||||
@@ -133,7 +150,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
|
||||
ctx->channel = channel;
|
||||
ctx->speed = speed;
|
||||
ctx->header_size = header_size;
|
||||
ctx->callback = callback;
|
||||
ctx->callback.sc = callback;
|
||||
ctx->callback_data = callback_data;
|
||||
|
||||
return ctx;
|
||||
@@ -142,9 +159,7 @@ EXPORT_SYMBOL(fw_iso_context_create);
|
||||
|
||||
void fw_iso_context_destroy(struct fw_iso_context *ctx)
|
||||
{
|
||||
struct fw_card *card = ctx->card;
|
||||
|
||||
card->driver->free_iso_context(ctx);
|
||||
ctx->card->driver->free_iso_context(ctx);
|
||||
}
|
||||
EXPORT_SYMBOL(fw_iso_context_destroy);
|
||||
|
||||
@@ -155,14 +170,17 @@ int fw_iso_context_start(struct fw_iso_context *ctx,
|
||||
}
|
||||
EXPORT_SYMBOL(fw_iso_context_start);
|
||||
|
||||
int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels)
|
||||
{
|
||||
return ctx->card->driver->set_iso_channels(ctx, channels);
|
||||
}
|
||||
|
||||
int fw_iso_context_queue(struct fw_iso_context *ctx,
|
||||
struct fw_iso_packet *packet,
|
||||
struct fw_iso_buffer *buffer,
|
||||
unsigned long payload)
|
||||
{
|
||||
struct fw_card *card = ctx->card;
|
||||
|
||||
return card->driver->queue_iso(ctx, packet, buffer, payload);
|
||||
return ctx->card->driver->queue_iso(ctx, packet, buffer, payload);
|
||||
}
|
||||
EXPORT_SYMBOL(fw_iso_context_queue);
|
||||
|
||||
|
Verwijs in nieuw issue
Block a user