Merge tag 'sound-4.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[platform/kernel/linux-exynos.git] / sound / firewire / packets-buffer.c
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/export.h>
10 #include <linux/slab.h>
11 #include "packets-buffer.h"
12
13 /**
14  * iso_packets_buffer_init - allocates the memory for packets
15  * @b: the buffer structure to initialize
16  * @unit: the device at the other end of the stream
17  * @count: the number of packets
18  * @packet_size: the (maximum) size of a packet, in bytes
19  * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE
20  */
21 int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit,
22                             unsigned int count, unsigned int packet_size,
23                             enum dma_data_direction direction)
24 {
25         unsigned int packets_per_page, pages;
26         unsigned int i, page_index, offset_in_page;
27         void *p;
28         int err;
29
30         b->packets = kmalloc(count * sizeof(*b->packets), GFP_KERNEL);
31         if (!b->packets) {
32                 err = -ENOMEM;
33                 goto error;
34         }
35
36         packet_size = L1_CACHE_ALIGN(packet_size);
37         packets_per_page = PAGE_SIZE / packet_size;
38         if (WARN_ON(!packets_per_page)) {
39                 err = -EINVAL;
40                 goto error;
41         }
42         pages = DIV_ROUND_UP(count, packets_per_page);
43
44         err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card,
45                                  pages, direction);
46         if (err < 0)
47                 goto err_packets;
48
49         for (i = 0; i < count; ++i) {
50                 page_index = i / packets_per_page;
51                 p = page_address(b->iso_buffer.pages[page_index]);
52                 offset_in_page = (i % packets_per_page) * packet_size;
53                 b->packets[i].buffer = p + offset_in_page;
54                 b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page;
55         }
56
57         return 0;
58
59 err_packets:
60         kfree(b->packets);
61 error:
62         return err;
63 }
64 EXPORT_SYMBOL(iso_packets_buffer_init);
65
66 /**
67  * iso_packets_buffer_destroy - frees packet buffer resources
68  * @b: the buffer structure to free
69  * @unit: the device at the other end of the stream
70  */
71 void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
72                                 struct fw_unit *unit)
73 {
74         fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
75         kfree(b->packets);
76 }
77 EXPORT_SYMBOL(iso_packets_buffer_destroy);