diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/firewire/packets-buffer.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'sound/firewire/packets-buffer.c')
-rw-r--r-- | sound/firewire/packets-buffer.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c new file mode 100644 index 000000000000..3c61ca2e6152 --- /dev/null +++ b/sound/firewire/packets-buffer.c | |||
@@ -0,0 +1,76 @@ | |||
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 | EXPORT_SYMBOL(iso_packets_buffer_init); | ||
64 | |||
65 | /** | ||
66 | * iso_packets_buffer_destroy - frees packet buffer resources | ||
67 | * @b: the buffer structure to free | ||
68 | * @unit: the device at the other end of the stream | ||
69 | */ | ||
70 | void iso_packets_buffer_destroy(struct iso_packets_buffer *b, | ||
71 | struct fw_unit *unit) | ||
72 | { | ||
73 | fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card); | ||
74 | kfree(b->packets); | ||
75 | } | ||
76 | EXPORT_SYMBOL(iso_packets_buffer_destroy); | ||