diff options
Diffstat (limited to 'sound/firewire/packets-buffer.c')
-rw-r--r-- | sound/firewire/packets-buffer.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c new file mode 100644 index 000000000000..1e20e60ba6a6 --- /dev/null +++ b/sound/firewire/packets-buffer.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * helpers for managing a buffer for many packets | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/firewire.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include "packets-buffer.h" | ||
11 | |||
12 | /** | ||
13 | * iso_packets_buffer_init - allocates the memory for packets | ||
14 | * @b: the buffer structure to initialize | ||
15 | * @unit: the device at the other end of the stream | ||
16 | * @count: the number of packets | ||
17 | * @packet_size: the (maximum) size of a packet, in bytes | ||
18 | * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE | ||
19 | */ | ||
20 | int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit, | ||
21 | unsigned int count, unsigned int packet_size, | ||
22 | enum dma_data_direction direction) | ||
23 | { | ||
24 | unsigned int packets_per_page, pages; | ||
25 | unsigned int i, page_index, offset_in_page; | ||
26 | void *p; | ||
27 | int err; | ||
28 | |||
29 | b->packets = kmalloc(count * sizeof(*b->packets), GFP_KERNEL); | ||
30 | if (!b->packets) { | ||
31 | err = -ENOMEM; | ||
32 | goto error; | ||
33 | } | ||
34 | |||
35 | packet_size = L1_CACHE_ALIGN(packet_size); | ||
36 | packets_per_page = PAGE_SIZE / packet_size; | ||
37 | if (WARN_ON(!packets_per_page)) { | ||
38 | err = -EINVAL; | ||
39 | goto error; | ||
40 | } | ||
41 | pages = DIV_ROUND_UP(count, packets_per_page); | ||
42 | |||
43 | err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card, | ||
44 | pages, direction); | ||
45 | if (err < 0) | ||
46 | goto err_packets; | ||
47 | |||
48 | for (i = 0; i < count; ++i) { | ||
49 | page_index = i / packets_per_page; | ||
50 | p = page_address(b->iso_buffer.pages[page_index]); | ||
51 | offset_in_page = (i % packets_per_page) * packet_size; | ||
52 | b->packets[i].buffer = p + offset_in_page; | ||
53 | b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page; | ||
54 | } | ||
55 | |||
56 | return 0; | ||
57 | |||
58 | err_packets: | ||
59 | kfree(b->packets); | ||
60 | error: | ||
61 | return err; | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * iso_packets_buffer_destroy - frees packet buffer resources | ||
66 | * @b: the buffer structure to free | ||
67 | * @unit: the device at the other end of the stream | ||
68 | */ | ||
69 | void iso_packets_buffer_destroy(struct iso_packets_buffer *b, | ||
70 | struct fw_unit *unit) | ||
71 | { | ||
72 | fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); | ||
73 | kfree(b->packets); | ||
74 | } | ||