2 * Scatter-Gather buffer
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/slab.h>
24 #include <linux/vmalloc.h>
25 #include <sound/memalloc.h>
28 /* table entries are align to 32 */
29 #define SGBUF_TBL_ALIGN 32
30 #define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
32 int snd_free_sgbuf_pages(struct snd_dma_buffer
*dmab
)
34 struct snd_sg_buf
*sgbuf
= dmab
->private_data
;
35 struct snd_dma_buffer tmpb
;
41 tmpb
.dev
.type
= SNDRV_DMA_TYPE_DEV
;
42 tmpb
.dev
.dev
= sgbuf
->dev
;
43 for (i
= 0; i
< sgbuf
->pages
; i
++) {
44 tmpb
.area
= sgbuf
->table
[i
].buf
;
45 tmpb
.addr
= sgbuf
->table
[i
].addr
;
46 tmpb
.bytes
= PAGE_SIZE
;
47 snd_dma_free_pages(&tmpb
);
54 kfree(sgbuf
->page_table
);
56 dmab
->private_data
= NULL
;
61 void *snd_malloc_sgbuf_pages(struct device
*device
,
62 size_t size
, struct snd_dma_buffer
*dmab
,
65 struct snd_sg_buf
*sgbuf
;
66 unsigned int i
, pages
;
67 struct snd_dma_buffer tmpb
;
71 dmab
->private_data
= sgbuf
= kzalloc(sizeof(*sgbuf
), GFP_KERNEL
);
75 pages
= snd_sgbuf_aligned_pages(size
);
76 sgbuf
->tblsize
= sgbuf_align_table(pages
);
77 sgbuf
->table
= kcalloc(sgbuf
->tblsize
, sizeof(*sgbuf
->table
), GFP_KERNEL
);
80 sgbuf
->page_table
= kcalloc(sgbuf
->tblsize
, sizeof(*sgbuf
->page_table
), GFP_KERNEL
);
81 if (! sgbuf
->page_table
)
84 /* allocate each page */
85 for (i
= 0; i
< pages
; i
++) {
86 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
, device
, PAGE_SIZE
, &tmpb
) < 0) {
89 *res_size
= size
= sgbuf
->pages
* PAGE_SIZE
;
92 sgbuf
->table
[i
].buf
= tmpb
.area
;
93 sgbuf
->table
[i
].addr
= tmpb
.addr
;
94 sgbuf
->page_table
[i
] = virt_to_page(tmpb
.area
);
99 dmab
->area
= vmap(sgbuf
->page_table
, sgbuf
->pages
, VM_MAP
, PAGE_KERNEL
);
105 snd_free_sgbuf_pages(dmab
); /* free the table */