~ubuntu-branches/ubuntu/maverick/linux-backports-modules-2.6.32/maverick

« back to all changes in this revision

Viewing changes to updates/alsa-driver/alsa-kernel/core/sgbuf.c

  • Committer: Bazaar Package Importer
  • Author(s): Andy Whitcroft, Andy Whitcroft
  • Date: 2010-02-04 23:15:51 UTC
  • Revision ID: james.westby@ubuntu.com-20100204231551-vjz5pkvxclukjxm1
Tags: 2.6.32-12.1
[ Andy Whitcroft ]

* initial LBM for lucid
* drop generated files
* printchanges -- rebase tree does not have stable tags use changelog
* printenv -- add revisions to printenv output
* formally rename compat-wireless to linux-backports-modules-wireless
* Update to compat-wireless-2.6.33-rc5
* update nouveau to mainline 2.6.33-rc4
* add new LBM package for nouveau
* nouveau -- fix major numbers and proc entry names
* fix up firmware installs for -wireless
* clean up UPDATE-NOVEAU
* update Nouveau to v2.6.33-rc6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Scatter-Gather buffer
 
3
 *
 
4
 *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
19
 *
 
20
 */
 
21
 
 
22
#include <linux/slab.h>
 
23
#include <linux/mm.h>
 
24
#include <linux/vmalloc.h>
 
25
#include <sound/memalloc.h>
 
26
 
 
27
 
 
28
/* table entries are align to 32 */
 
29
#define SGBUF_TBL_ALIGN         32
 
30
#define sgbuf_align_table(tbl)  ALIGN((tbl), SGBUF_TBL_ALIGN)
 
31
 
 
32
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
 
33
{
 
34
        struct snd_sg_buf *sgbuf = dmab->private_data;
 
35
        struct snd_dma_buffer tmpb;
 
36
        int i;
 
37
 
 
38
        if (! sgbuf)
 
39
                return -EINVAL;
 
40
 
 
41
        if (dmab->area)
 
42
                vunmap(dmab->area);
 
43
        dmab->area = NULL;
 
44
 
 
45
        tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
 
46
        tmpb.dev.dev = sgbuf->dev;
 
47
        for (i = 0; i < sgbuf->pages; i++) {
 
48
                if (!(sgbuf->table[i].addr & ~PAGE_MASK))
 
49
                        continue; /* continuous pages */
 
50
                tmpb.area = sgbuf->table[i].buf;
 
51
                tmpb.addr = sgbuf->table[i].addr & PAGE_MASK;
 
52
                tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
 
53
                snd_dma_free_pages(&tmpb);
 
54
        }
 
55
 
 
56
        kfree(sgbuf->table);
 
57
        kfree(sgbuf->page_table);
 
58
        kfree(sgbuf);
 
59
        dmab->private_data = NULL;
 
60
        
 
61
        return 0;
 
62
}
 
63
 
 
64
#define MAX_ALLOC_PAGES         32
 
65
 
 
66
void *snd_malloc_sgbuf_pages(struct device *device,
 
67
                             size_t size, struct snd_dma_buffer *dmab,
 
68
                             size_t *res_size)
 
69
{
 
70
        struct snd_sg_buf *sgbuf;
 
71
        unsigned int i, pages, chunk, maxpages;
 
72
        struct snd_dma_buffer tmpb;
 
73
        struct snd_sg_page *table;
 
74
        struct page **pgtable;
 
75
 
 
76
        dmab->area = NULL;
 
77
        dmab->addr = 0;
 
78
        dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
 
79
        if (! sgbuf)
 
80
                return NULL;
 
81
        sgbuf->dev = device;
 
82
        pages = snd_sgbuf_aligned_pages(size);
 
83
        sgbuf->tblsize = sgbuf_align_table(pages);
 
84
        table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
 
85
        if (!table)
 
86
                goto _failed;
 
87
        sgbuf->table = table;
 
88
        pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL);
 
89
        if (!pgtable)
 
90
                goto _failed;
 
91
        sgbuf->page_table = pgtable;
 
92
 
 
93
        /* allocate pages */
 
94
        maxpages = MAX_ALLOC_PAGES;
 
95
        while (pages > 0) {
 
96
                chunk = pages;
 
97
                /* don't be too eager to take a huge chunk */
 
98
                if (chunk > maxpages)
 
99
                        chunk = maxpages;
 
100
                chunk <<= PAGE_SHIFT;
 
101
                if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
 
102
                                                 chunk, &tmpb) < 0) {
 
103
                        if (!sgbuf->pages)
 
104
                                return NULL;
 
105
                        if (!res_size)
 
106
                                goto _failed;
 
107
                        size = sgbuf->pages * PAGE_SIZE;
 
108
                        break;
 
109
                }
 
110
                chunk = tmpb.bytes >> PAGE_SHIFT;
 
111
                for (i = 0; i < chunk; i++) {
 
112
                        table->buf = tmpb.area;
 
113
                        table->addr = tmpb.addr;
 
114
                        if (!i)
 
115
                                table->addr |= chunk; /* mark head */
 
116
                        table++;
 
117
                        *pgtable++ = virt_to_page(tmpb.area);
 
118
                        tmpb.area += PAGE_SIZE;
 
119
                        tmpb.addr += PAGE_SIZE;
 
120
                }
 
121
                sgbuf->pages += chunk;
 
122
                pages -= chunk;
 
123
                if (chunk < maxpages)
 
124
                        maxpages = chunk;
 
125
        }
 
126
 
 
127
        sgbuf->size = size;
 
128
        dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
 
129
        if (! dmab->area)
 
130
                goto _failed;
 
131
        if (res_size)
 
132
                *res_size = sgbuf->size;
 
133
        return dmab->area;
 
134
 
 
135
 _failed:
 
136
        snd_free_sgbuf_pages(dmab); /* free the table */
 
137
        return NULL;
 
138
}