From 31ef9134eb52636d383a7d0626cbbd345cb94f2f Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 15 Mar 2011 07:53:21 +0100 Subject: ALSA: add LaCie FireWire Speakers/Griffin FireWave Surround driver Add a driver for two playback-only FireWire devices based on the OXFW970 chip. v2: better AMDTP API abstraction; fix fw_unit leak; small fixes v3: cache the iPCR value v4: FireWave constraints; fix fw_device reference counting; fix PCR caching; small changes and fixes v5: volume/mute support; fix crashing due to pcm stop races v6: fix build; one-channel volume for LaCie v7: use signed values to make volume (range checks) work; fix function block IDs for volume/mute; always use channel 0 for LaCie volume Signed-off-by: Clemens Ladisch Acked-by: Stefan Richter Tested-by: Jay Fenlason Signed-off-by: Takashi Iwai --- sound/firewire/packets-buffer.c | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 sound/firewire/packets-buffer.c (limited to 'sound/firewire/packets-buffer.c') diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c new file mode 100644 index 00000000000..1e20e60ba6a --- /dev/null +++ b/sound/firewire/packets-buffer.c @@ -0,0 +1,74 @@ +/* + * helpers for managing a buffer for many packets + * + * Copyright (c) Clemens Ladisch + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include +#include +#include "packets-buffer.h" + +/** + * iso_packets_buffer_init - allocates the memory for packets + * @b: the buffer structure to initialize + * @unit: the device at the other end of the stream + * @count: the number of packets + * @packet_size: the (maximum) size of a packet, in bytes + * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE + */ +int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, + unsigned int count, unsigned int packet_size, + enum dma_data_direction direction) +{ + unsigned int packets_per_page, pages; + unsigned int i, page_index, offset_in_page; + void *p; + int err; + + b->packets = kmalloc(count * sizeof(*b->packets), GFP_KERNEL); + if (!b->packets) { + err = -ENOMEM; + goto error; + } + + packet_size = L1_CACHE_ALIGN(packet_size); + packets_per_page = PAGE_SIZE / packet_size; + if (WARN_ON(!packets_per_page)) { + err = -EINVAL; + goto error; + } + pages = DIV_ROUND_UP(count, packets_per_page); + + err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card, + pages, direction); + if (err < 0) + goto err_packets; + + for (i = 0; i < count; ++i) { + page_index = i / packets_per_page; + p = page_address(b->iso_buffer.pages[page_index]); + offset_in_page = (i % packets_per_page) * packet_size; + b->packets[i].buffer = p + offset_in_page; + b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page; + } + + return 0; + +err_packets: + kfree(b->packets); +error: + return err; +} + +/** + * iso_packets_buffer_destroy - frees packet buffer resources + * @b: the buffer structure to free + * @unit: the device at the other end of the stream + */ +void iso_packets_buffer_destroy(struct iso_packets_buffer *b, + struct fw_unit *unit) +{ + fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); + kfree(b->packets); +} -- cgit v1.2.3