Blame view

sound/core/memalloc.c 13.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
2
   *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   *                   Takashi Iwai <tiwai@suse.de>
   * 
   *  Generic memory allocators
   *
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
  #include <linux/module.h>
  #include <linux/proc_fs.h>
  #include <linux/init.h>
  #include <linux/pci.h>
  #include <linux/slab.h>
  #include <linux/mm.h>
ccec6e2c4   Takashi Iwai   Convert snd-page-...
29
  #include <linux/seq_file.h>
b6a969155   Takashi Iwai   [ALSA] Add write ...
30
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include <linux/dma-mapping.h>
  #include <linux/moduleparam.h>
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
33
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <sound/memalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
36
  MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
  MODULE_DESCRIPTION("Memory allocator for ALSA system.");
  MODULE_LICENSE("GPL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  /*
   */
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
41
  static DEFINE_MUTEX(list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
51
52
  static LIST_HEAD(mem_list_head);
  
  /* buffer preservation list */
  struct snd_mem_list {
  	struct snd_dma_buffer buffer;
  	unsigned int id;
  	struct list_head list;
  };
  
  /* id for pre-allocated buffers */
  #define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
   *
   *  Generic memory allocators
   *
   */
  
  static long snd_allocated_pages; /* holding the number of allocated pages */
  
  static inline void inc_snd_pages(int order)
  {
  	snd_allocated_pages += 1 << order;
  }
  
  static inline void dec_snd_pages(int order)
  {
  	snd_allocated_pages -= 1 << order;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
77
78
  /**
   * snd_malloc_pages - allocate pages with the given size
   * @size: the size to allocate in bytes
   * @gfp_flags: the allocation conditions, GFP_XXX
   *
   * Allocates the physically contiguous pages with the given size.
   *
   * Returns the pointer of the buffer, or NULL if no enoguh memory.
   */
1ef64e670   Al Viro   [PATCH] gfp_t: sound
79
  void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
  {
  	int pg;
  	void *res;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
83
84
85
86
  	if (WARN_ON(!size))
  		return NULL;
  	if (WARN_ON(!gfp_flags))
  		return NULL;
f3d48f037   Hugh Dickins   [PATCH] unpaged: ...
87
  	gfp_flags |= __GFP_COMP;	/* compound page lets parts be mapped */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  	pg = get_order(size);
2ba8c15c7   Takashi Iwai   [ALSA] Removed un...
89
  	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  		inc_snd_pages(pg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  	return res;
  }
  
  /**
   * snd_free_pages - release the pages
   * @ptr: the buffer pointer to release
   * @size: the allocated buffer size
   *
   * Releases the buffer allocated via snd_malloc_pages().
   */
  void snd_free_pages(void *ptr, size_t size)
  {
  	int pg;
  
  	if (ptr == NULL)
  		return;
  	pg = get_order(size);
  	dec_snd_pages(pg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
113
114
115
116
  	free_pages((unsigned long) ptr, pg);
  }
  
  /*
   *
   *  Bus-specific memory allocators
   *
   */
8f11551b1   Takashi Iwai   [ALSA] Fix build ...
117
  #ifdef CONFIG_HAS_DMA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
  /* allocate the coherent DMA pages */
  static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
  {
  	int pg;
  	void *res;
1ef64e670   Al Viro   [PATCH] gfp_t: sound
123
  	gfp_t gfp_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124

7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
125
126
  	if (WARN_ON(!dma))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
  	pg = get_order(size);
  	gfp_flags = GFP_KERNEL
f3d48f037   Hugh Dickins   [PATCH] unpaged: ...
129
  		| __GFP_COMP	/* compound page lets parts be mapped */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
  		| __GFP_NORETRY /* don't trigger OOM-killer */
  		| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
  	res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
2ba8c15c7   Takashi Iwai   [ALSA] Removed un...
133
  	if (res != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  		inc_snd_pages(pg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  
  	return res;
  }
  
  /* free the coherent DMA pages */
  static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
  			       dma_addr_t dma)
  {
  	int pg;
  
  	if (ptr == NULL)
  		return;
  	pg = get_order(size);
  	dec_snd_pages(pg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
  	dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
  }
8f11551b1   Takashi Iwai   [ALSA] Fix build ...
151
  #endif /* CONFIG_HAS_DMA */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  /*
   *
   *  ALSA generic memory management
   *
   */
  
  
  /**
   * snd_dma_alloc_pages - allocate the buffer area according to the given type
   * @type: the DMA buffer type
   * @device: the device pointer
   * @size: the buffer size to allocate
   * @dmab: buffer allocation record to store the allocated data
   *
   * Calls the memory-allocator function for the corresponding
   * buffer type.
   * 
bfb9035c9   Joe Perches   treewide: Correct...
170
   * Returns zero if the buffer with the given size is allocated successfully,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
175
   * other a negative value at error.
   */
  int snd_dma_alloc_pages(int type, struct device *device, size_t size,
  			struct snd_dma_buffer *dmab)
  {
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
176
177
178
179
  	if (WARN_ON(!size))
  		return -ENXIO;
  	if (WARN_ON(!dmab))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
  
  	dmab->dev.type = type;
  	dmab->dev.dev = device;
  	dmab->bytes = 0;
  	switch (type) {
  	case SNDRV_DMA_TYPE_CONTINUOUS:
fea952e5c   Clemens Ladisch   ALSA: core: spars...
186
187
  		dmab->area = snd_malloc_pages(size,
  					(__force gfp_t)(unsigned long)device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
  		dmab->addr = 0;
  		break;
8f11551b1   Takashi Iwai   [ALSA] Fix build ...
190
  #ifdef CONFIG_HAS_DMA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
  	case SNDRV_DMA_TYPE_DEV:
  		dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
  		break;
cc6a8acde   Takashi Iwai   ALSA: Fix SG-buff...
194
195
  #endif
  #ifdef CONFIG_SND_DMA_SGBUF
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
  	case SNDRV_DMA_TYPE_DEV_SG:
  		snd_malloc_sgbuf_pages(device, size, dmab, NULL);
  		break;
8f11551b1   Takashi Iwai   [ALSA] Fix build ...
199
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  	default:
  		printk(KERN_ERR "snd-malloc: invalid device type %d
  ", type);
  		dmab->area = NULL;
  		dmab->addr = 0;
  		return -ENXIO;
  	}
  	if (! dmab->area)
  		return -ENOMEM;
  	dmab->bytes = size;
  	return 0;
  }
  
  /**
   * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback
   * @type: the DMA buffer type
   * @device: the device pointer
   * @size: the buffer size to allocate
   * @dmab: buffer allocation record to store the allocated data
   *
   * Calls the memory-allocator function for the corresponding
   * buffer type.  When no space is left, this function reduces the size and
   * tries to allocate again.  The size actually allocated is stored in
   * res_size argument.
   * 
bfb9035c9   Joe Perches   treewide: Correct...
225
   * Returns zero if the buffer with the given size is allocated successfully,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
   * other a negative value at error.
   */
  int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
  				 struct snd_dma_buffer *dmab)
  {
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  	while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
4e184f8fc   Takashi Iwai   ALSA: Fix allocat...
233
  		size_t aligned_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
  		if (err != -ENOMEM)
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
  		if (size <= PAGE_SIZE)
  			return -ENOMEM;
4e184f8fc   Takashi Iwai   ALSA: Fix allocat...
238
239
240
241
242
  		aligned_size = PAGE_SIZE << get_order(size);
  		if (size != aligned_size)
  			size = aligned_size;
  		else
  			size >>= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  	}
  	if (! dmab->area)
  		return -ENOMEM;
  	return 0;
  }
  
  
  /**
   * snd_dma_free_pages - release the allocated buffer
   * @dmab: the buffer allocation record to release
   *
   * Releases the allocated buffer via snd_dma_alloc_pages().
   */
  void snd_dma_free_pages(struct snd_dma_buffer *dmab)
  {
  	switch (dmab->dev.type) {
  	case SNDRV_DMA_TYPE_CONTINUOUS:
  		snd_free_pages(dmab->area, dmab->bytes);
  		break;
8f11551b1   Takashi Iwai   [ALSA] Fix build ...
262
  #ifdef CONFIG_HAS_DMA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
  	case SNDRV_DMA_TYPE_DEV:
  		snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
  		break;
cc6a8acde   Takashi Iwai   ALSA: Fix SG-buff...
266
267
  #endif
  #ifdef CONFIG_SND_DMA_SGBUF
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
  	case SNDRV_DMA_TYPE_DEV_SG:
  		snd_free_sgbuf_pages(dmab);
  		break;
8f11551b1   Takashi Iwai   [ALSA] Fix build ...
271
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  	default:
  		printk(KERN_ERR "snd-malloc: invalid device type %d
  ", dmab->dev.type);
  	}
  }
  
  
  /**
   * snd_dma_get_reserved - get the reserved buffer for the given device
   * @dmab: the buffer allocation record to store
   * @id: the buffer id
   *
   * Looks for the reserved-buffer list and re-uses if the same buffer
   * is found in the list.  When the buffer is found, it's removed from the free list.
   *
   * Returns the size of buffer if the buffer is found, or zero if not found.
   */
  size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  	struct snd_mem_list *mem;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
292
293
  	if (WARN_ON(!dmab))
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294

1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
295
  	mutex_lock(&list_mutex);
9244b2c30   Johannes Berg   [ALSA] alsa core:...
296
  	list_for_each_entry(mem, &mem_list_head, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  		if (mem->id == id &&
b6a969155   Takashi Iwai   [ALSA] Add write ...
298
299
300
  		    (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
  		     ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
  			struct device *dev = dmab->dev.dev;
9244b2c30   Johannes Berg   [ALSA] alsa core:...
301
  			list_del(&mem->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  			*dmab = mem->buffer;
b6a969155   Takashi Iwai   [ALSA] Add write ...
303
304
  			if (dmab->dev.dev == NULL)
  				dmab->dev.dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  			kfree(mem);
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
306
  			mutex_unlock(&list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
  			return dmab->bytes;
  		}
  	}
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
310
  	mutex_unlock(&list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  	return 0;
  }
  
  /**
   * snd_dma_reserve_buf - reserve the buffer
   * @dmab: the buffer to reserve
   * @id: the buffer id
   *
   * Reserves the given buffer as a reserved buffer.
   * 
   * Returns zero if successful, or a negative code at error.
   */
  int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
  {
  	struct snd_mem_list *mem;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
326
327
  	if (WARN_ON(!dmab))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
  	mem = kmalloc(sizeof(*mem), GFP_KERNEL);
  	if (! mem)
  		return -ENOMEM;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
331
  	mutex_lock(&list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
  	mem->buffer = *dmab;
  	mem->id = id;
  	list_add_tail(&mem->list, &mem_list_head);
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
335
  	mutex_unlock(&list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
344
345
  	return 0;
  }
  
  /*
   * purge all reserved buffers
   */
  static void free_all_reserved_pages(void)
  {
  	struct list_head *p;
  	struct snd_mem_list *mem;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
346
  	mutex_lock(&list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
350
351
352
353
  	while (! list_empty(&mem_list_head)) {
  		p = mem_list_head.next;
  		mem = list_entry(p, struct snd_mem_list, list);
  		list_del(p);
  		snd_dma_free_pages(&mem->buffer);
  		kfree(mem);
  	}
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
354
  	mutex_unlock(&list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
359
  #ifdef CONFIG_PROC_FS
  /*
   * proc file interface
   */
b6a969155   Takashi Iwai   [ALSA] Add write ...
360
  #define SND_MEM_PROC_FILE	"driver/snd-page-alloc"
a53fc188e   Clemens Ladisch   [ALSA] make local...
361
  static struct proc_dir_entry *snd_mem_proc;
b6a969155   Takashi Iwai   [ALSA] Add write ...
362

ccec6e2c4   Takashi Iwai   Convert snd-page-...
363
  static int snd_mem_proc_read(struct seq_file *seq, void *offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  	long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
  	struct snd_mem_list *mem;
  	int devno;
759ee81be   David S. Miller   alsa: Remove spec...
368
  	static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369

1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
370
  	mutex_lock(&list_mutex);
ccec6e2c4   Takashi Iwai   Convert snd-page-...
371
372
373
  	seq_printf(seq, "pages  : %li bytes (%li pages per %likB)
  ",
  		   pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  	devno = 0;
9244b2c30   Johannes Berg   [ALSA] alsa core:...
375
  	list_for_each_entry(mem, &mem_list_head, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  		devno++;
ccec6e2c4   Takashi Iwai   Convert snd-page-...
377
378
379
380
381
382
383
  		seq_printf(seq, "buffer %d : ID %08x : type %s
  ",
  			   devno, mem->id, types[mem->buffer.dev.type]);
  		seq_printf(seq, "  addr = 0x%lx, size = %d bytes
  ",
  			   (unsigned long)mem->buffer.addr,
  			   (int)mem->buffer.bytes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  	}
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
385
  	mutex_unlock(&list_mutex);
ccec6e2c4   Takashi Iwai   Convert snd-page-...
386
387
388
389
390
391
  	return 0;
  }
  
  static int snd_mem_proc_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, snd_mem_proc_read, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  }
b6a969155   Takashi Iwai   [ALSA] Add write ...
393
394
395
396
397
  
  /* FIXME: for pci only - other bus? */
  #ifdef CONFIG_PCI
  #define gettoken(bufp) strsep(bufp, " \t
  ")
ccec6e2c4   Takashi Iwai   Convert snd-page-...
398
399
  static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer,
  				  size_t count, loff_t * ppos)
b6a969155   Takashi Iwai   [ALSA] Add write ...
400
401
402
  {
  	char buf[128];
  	char *token, *p;
ccec6e2c4   Takashi Iwai   Convert snd-page-...
403
404
  	if (count > sizeof(buf) - 1)
  		return -EINVAL;
b6a969155   Takashi Iwai   [ALSA] Add write ...
405
406
  	if (copy_from_user(buf, buffer, count))
  		return -EFAULT;
ccec6e2c4   Takashi Iwai   Convert snd-page-...
407
  	buf[count] = '\0';
b6a969155   Takashi Iwai   [ALSA] Add write ...
408
409
410
411
  
  	p = buf;
  	token = gettoken(&p);
  	if (! token || *token == '#')
ccec6e2c4   Takashi Iwai   Convert snd-page-...
412
  		return count;
b6a969155   Takashi Iwai   [ALSA] Add write ...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  	if (strcmp(token, "add") == 0) {
  		char *endp;
  		int vendor, device, size, buffers;
  		long mask;
  		int i, alloced;
  		struct pci_dev *pci;
  
  		if ((token = gettoken(&p)) == NULL ||
  		    (vendor = simple_strtol(token, NULL, 0)) <= 0 ||
  		    (token = gettoken(&p)) == NULL ||
  		    (device = simple_strtol(token, NULL, 0)) <= 0 ||
  		    (token = gettoken(&p)) == NULL ||
  		    (mask = simple_strtol(token, NULL, 0)) < 0 ||
  		    (token = gettoken(&p)) == NULL ||
  		    (size = memparse(token, &endp)) < 64*1024 ||
  		    size > 16*1024*1024 /* too big */ ||
  		    (token = gettoken(&p)) == NULL ||
  		    (buffers = simple_strtol(token, NULL, 0)) <= 0 ||
  		    buffers > 4) {
  			printk(KERN_ERR "snd-page-alloc: invalid proc write format
  ");
ccec6e2c4   Takashi Iwai   Convert snd-page-...
434
  			return count;
b6a969155   Takashi Iwai   [ALSA] Add write ...
435
436
437
438
439
440
  		}
  		vendor &= 0xffff;
  		device &= 0xffff;
  
  		alloced = 0;
  		pci = NULL;
0dd119f70   Jiri Slaby   [ALSA] pci_find_d...
441
  		while ((pci = pci_get_device(vendor, device, pci)) != NULL) {
b6a969155   Takashi Iwai   [ALSA] Add write ...
442
443
444
445
446
  			if (mask > 0 && mask < 0xffffffff) {
  				if (pci_set_dma_mask(pci, mask) < 0 ||
  				    pci_set_consistent_dma_mask(pci, mask) < 0) {
  					printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x
  ", mask, vendor, device);
df1deb675   Julia Lawall   [ALSA] sound/core...
447
  					pci_dev_put(pci);
ccec6e2c4   Takashi Iwai   Convert snd-page-...
448
  					return count;
b6a969155   Takashi Iwai   [ALSA] Add write ...
449
450
451
452
453
454
455
456
457
  				}
  			}
  			for (i = 0; i < buffers; i++) {
  				struct snd_dma_buffer dmab;
  				memset(&dmab, 0, sizeof(dmab));
  				if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
  							size, &dmab) < 0) {
  					printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)
  ", size);
0dd119f70   Jiri Slaby   [ALSA] pci_find_d...
458
  					pci_dev_put(pci);
ccec6e2c4   Takashi Iwai   Convert snd-page-...
459
  					return count;
b6a969155   Takashi Iwai   [ALSA] Add write ...
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  				}
  				snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
  			}
  			alloced++;
  		}
  		if (! alloced) {
  			for (i = 0; i < buffers; i++) {
  				struct snd_dma_buffer dmab;
  				memset(&dmab, 0, sizeof(dmab));
  				/* FIXME: We can allocate only in ZONE_DMA
  				 * without a device pointer!
  				 */
  				if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL,
  							size, &dmab) < 0) {
  					printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)
  ", size);
  					break;
  				}
  				snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device));
  			}
  		}
  	} else if (strcmp(token, "erase") == 0)
  		/* FIXME: need for releasing each buffer chunk? */
  		free_all_reserved_pages();
  	else
  		printk(KERN_ERR "snd-page-alloc: invalid proc cmd
  ");
ccec6e2c4   Takashi Iwai   Convert snd-page-...
487
  	return count;
b6a969155   Takashi Iwai   [ALSA] Add write ...
488
489
  }
  #endif /* CONFIG_PCI */
ccec6e2c4   Takashi Iwai   Convert snd-page-...
490
491
492
493
494
495
496
497
498
499
500
  
  static const struct file_operations snd_mem_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= snd_mem_proc_open,
  	.read		= seq_read,
  #ifdef CONFIG_PCI
  	.write		= snd_mem_proc_write,
  #endif
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
505
506
507
508
509
  #endif /* CONFIG_PROC_FS */
  
  /*
   * module entry
   */
  
  static int __init snd_mem_init(void)
  {
  #ifdef CONFIG_PROC_FS
7bf4e6d3e   Denis V. Lunev   sound: use non-ra...
510
511
  	snd_mem_proc = proc_create(SND_MEM_PROC_FILE, 0644, NULL,
  				   &snd_mem_proc_fops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
516
517
  	return 0;
  }
  
  static void __exit snd_mem_exit(void)
  {
e0be4d32b   Takashi Iwai   [ALSA] Fix compil...
518
  	remove_proc_entry(SND_MEM_PROC_FILE, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  	free_all_reserved_pages();
  	if (snd_allocated_pages > 0)
  		printk(KERN_ERR "snd-malloc: Memory leak?  pages not freed = %li
  ", snd_allocated_pages);
  }
  
  
  module_init(snd_mem_init)
  module_exit(snd_mem_exit)
  
  
  /*
   * exports
   */
  EXPORT_SYMBOL(snd_dma_alloc_pages);
  EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
  EXPORT_SYMBOL(snd_dma_free_pages);
  
  EXPORT_SYMBOL(snd_dma_get_reserved_buf);
  EXPORT_SYMBOL(snd_dma_reserve_buf);
  
  EXPORT_SYMBOL(snd_malloc_pages);
  EXPORT_SYMBOL(snd_free_pages);