Update of /cvsroot/alsa/alsa-kernel/core
In directory sc8-pr-cvs1:/tmp/cvs-serv30086/core

Modified Files:
        Makefile init.c memory.c pcm.c pcm_lib.c pcm_memory.c sound.c 
        wrappers.c 
Added Files:
        memalloc.c memory_wrapper.c sgbuf.c 
Removed Files:
        pcm_sgbuf.c 
Log Message:
more unified DMA allocation
- memory allocator is put into a separte independent module, snd-alloc-pages.
  it can be kept after other snd* modules unloaded, so that the big
  continuous pages can be held after reload.
- use size_t for the size type.



--- NEW FILE: memalloc.c ---
/*
 *  Copyright (c) by Jaroslav Kysela <[EMAIL PROTECTED]>
 *                   Takashi Iwai <[EMAIL PROTECTED]>
 * 
 *  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
 *
 */

#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/semaphore.h>
#include <sound/memalloc.h>


MODULE_AUTHOR("Takashi Iwai <[EMAIL PROTECTED]>, Jaroslav Kysela <[EMAIL PROTECTED]>");
MODULE_DESCRIPTION("Memory allocator for ALSA system.");
MODULE_LICENSE("GPL");


/*
 */

static DECLARE_MUTEX(list_mutex);
static LIST_HEAD(mem_list_head);

/* buffer preservation list */
struct snd_mem_list {
        struct snd_dma_device dev;
        struct snd_dma_buffer buffer;
        int used;
        struct list_head list;
};


#ifdef CONFIG_SND_DEBUG
#define __ASTRING__(x) #x
#define snd_assert(expr, args...) do {\
        if (!(expr)) {\
                printk(KERN_ERR "snd-malloc: BUG? (%s) (called from %p)\n", 
__ASTRING__(expr), __builtin_return_address(0));\
                args;\
        }\
} while (0)
#else
#define snd_assert(expr, args...) /**/
#endif

/* redefine pci_alloc_consistent for some architectures */
#ifdef HACK_PCI_ALLOC_CONSISTENT
#undef pci_alloc_consistent
#define pci_alloc_consistent snd_pci_hack_alloc_consistent
#endif


/*
 * compare the two devices
 * returns non-zero if matched.
 */
static int compare_device(const struct snd_dma_device *a, const struct snd_dma_device 
*b)
{
        if (a->type != b->type)
                return 0;
        if (a->id != b->id)
                return 0;
        switch (a->type) {
        case SNDRV_DMA_TYPE_CONTINUOUS:
#ifdef CONFIG_ISA
        case SNDRV_DMA_TYPE_ISA:
#endif
                return a->dev.flags == b->dev.flags;
#ifdef CONFIG_PCI
        case SNDRV_DMA_TYPE_PCI:
                return a->dev.pci == b->dev.pci;
#endif
#ifdef CONFIG_SBUS
        case SNDRV_DMA_TYPE_SBUS:
                return a->dev.sbus == b->dev.sbus;
#endif
        }
        return 0;
}

/**
 * snd_dma_alloc_pages - allocate the buffer area according to the given type
 * @dev: the buffer device info
 * @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.
 * 
 * Returns zero if the buffer with the given size is allocated successfuly,
 * other a negative value at error.
 */
int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size,
                        struct snd_dma_buffer *dmab)
{
        snd_assert(dev != NULL, return -ENXIO);
        snd_assert(size > 0, return -ENXIO);
        snd_assert(dmab != NULL, return -ENXIO);

        dmab->bytes = 0;
        switch (dev->type) {
        case SNDRV_DMA_TYPE_CONTINUOUS:
                dmab->area = snd_malloc_pages(size, dev->dev.flags);
                dmab->addr = 0;
                break;
#ifdef CONFIG_ISA
        case SNDRV_DMA_TYPE_ISA:
                dmab->area = snd_malloc_isa_pages(size, &dmab->addr);
                break;
#endif
#ifdef CONFIG_PCI
        case SNDRV_DMA_TYPE_PCI:
                dmab->area = snd_malloc_pci_pages(dev->dev.pci, size, &dmab->addr);
                break;
        case SNDRV_DMA_TYPE_PCI_SG:
                snd_malloc_sgbuf_pages(dev->dev.pci, size, dmab);
                break;
#endif
#ifdef CONFIG_SBUS
        case SNDRV_DMA_TYPE_SBUS:
                dmab->area = snd_malloc_pci_pages(dev->dev.sbus, size, &dmab->addr);
                break;
#endif
        default:
                printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type);
                dmab->area = NULL;
                dmab->addr = 0;
                return -ENXIO;
        }
        if (dmab->area)
                dmab->bytes = size;
        return 0;
}


/**
 * snd_dma_free_pages - release the allocated buffer
 * @dev: the buffer device info
 * @dmbab: the buffer allocation record to release
 *
 * Releases the allocated buffer via snd_dma_alloc_pages().
 */
void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab)
{
        switch (dev->type) {
        case SNDRV_DMA_TYPE_CONTINUOUS:
                snd_free_pages(dmab->area, dmab->bytes);
                break;
#ifdef CONFIG_ISA
        case SNDRV_DMA_TYPE_ISA:
                snd_free_isa_pages(dmab->bytes, dmab->area, dmab->addr);
                break;
#endif
#ifdef CONFIG_PCI
        case SNDRV_DMA_TYPE_PCI:
                snd_free_pci_pages(dev->dev.pci, dmab->bytes, dmab->area, dmab->addr);
                break;
        case SNDRV_DMA_TYPE_PCI_SG:
                snd_free_sgbuf_pages(dmab);
                break;
#endif
#ifdef CONFIG_SBUS
        case SNDRV_DMA_TYPE_SBUS:
                snd_free_sbus_pages(dev->dev.sbus, dmab->size, dmab->are, dmab->addr);
                break;
#endif
        default:
                printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type);
        }
}


/*
 * search for the device
 */
static struct snd_mem_list *mem_list_find(const struct snd_dma_device *dev)
{
        struct list_head *p;
        struct snd_mem_list *mem;

        list_for_each(p, &mem_list_head) {
                mem = list_entry(p, struct snd_mem_list, list);
                if (compare_device(&mem->dev, dev))
                        return mem;
        }
        return NULL;
}

/**
 * snd_dma_get_reserved - get the reserved buffer for the given device
 * @dev: the buffer device info
 * @dmab: the buffer allocation record to store
 *
 * 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 marked as used.
 * For unmarking the buffer, call snd_dma_free_reserved().
 *
 * Returns the size of buffer if the buffer is found, or zero if not found.
 */
size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer 
*dmab)
{
        struct snd_mem_list *mem;

        snd_assert(dev && dmab, return 0);

        down(&list_mutex);
        mem = mem_list_find(dev);
        if (mem) {
                mem->used = 1;
                *dmab = mem->buffer;
                up(&list_mutex);
                return dmab->bytes;
        }
        up(&list_mutex);
        return 0;
}

/**
 * snd_dma_free_reserved - unmark the reserved buffer
 * @dev: the buffer device info
 *
 * Looks for the matching reserved buffer and erases the mark on it
 * if found.
 *
 * Returns zero.
 */
int snd_dma_free_reserved(const struct snd_dma_device *dev)
{
        struct snd_mem_list *mem;

        snd_assert(dev, return -EINVAL);
        down(&list_mutex);
        mem = mem_list_find(dev);
        if (mem)
                mem->used = 0;
        up(&list_mutex);
        return 0;
}

/**
 * snd_dma_set_reserved - reserve the buffer
 * @dev: the buffer device info
 * @dmab: the buffer to reserve
 *
 * Reserves the given buffer as a reserved buffer.
 * When an old reserved buffer already exists, the old one is released
 * and replaced with the new one.
 *
 * When NULL buffer pointer or zero buffer size is given, the existing
 * release buffer is released and the entry is removed.
 * 
 * Returns zero if successful, or a negative code at error.
 */
int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab)
{
        struct snd_mem_list *mem;

        snd_assert(dev, return -EINVAL);
        down(&list_mutex);
        mem = mem_list_find(dev);
        if (mem) {
                snd_dma_free_pages(dev, &mem->buffer);
                if (! dmab || ! dmab->bytes) {
                        /* remove the entry */
                        list_del(&mem->list);
                        kfree(mem);
                        up(&list_mutex);
                        return 0;
                }
        } else {
                if (! dmab || ! dmab->bytes) {
                        up(&list_mutex);
                        return 0;
                }
                mem = kmalloc(sizeof(*mem), GFP_KERNEL);
                mem->dev = *dev;
                list_add(&mem->list, &mem_list_head);
        }
        /* store the entry */
        mem->used = 1;
        mem->buffer = *dmab;
        up(&list_mutex);
        return 0;
}

/*
 * purge all reserved buffers
 */
static void free_all_reserved_pages(void)
{
        struct list_head *p;
        struct snd_mem_list *mem;

        down(&list_mutex);
        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->dev, &mem->buffer);
                kfree(mem);
        }
        up(&list_mutex);
}


/*
 *
 *  Generic memory allocators
 *
 */

static long snd_allocated_pages; /* holding the number of allocated pages */

static void mark_pages(void *res, int order)
{
        struct page *page = virt_to_page(res);
        struct page *last_page = page + (1 << order);
        while (page < last_page)
                SetPageReserved(page++);
        snd_allocated_pages += 1 << order;
}

static void unmark_pages(void *res, int order)
{
        struct page *page = virt_to_page(res);
        struct page *last_page = page + (1 << order);
        while (page < last_page)
                ClearPageReserved(page++);
        snd_allocated_pages -= 1 << order;
}

/**
 * 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.
 */
void *snd_malloc_pages(size_t size, unsigned int gfp_flags)
{
        int pg;
        void *res;

        snd_assert(size > 0, return NULL);
        snd_assert(gfp_flags != 0, return NULL);
        for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
        if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) {
                mark_pages(res, pg);
        }
        return res;
}

/**
 * snd_malloc_pages_fallback - allocate pages with the given size with fallback
 * @size: the requested size to allocate in bytes
 * @gfp_flags: the allocation conditions, GFP_XXX
 * @res_size: the pointer to store the size of buffer actually allocated
 *
 * Allocates the physically contiguous pages with the given request
 * size.  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.
 *
 * Returns the pointer of the buffer, or NULL if no enoguh memory.
 */
void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size)
{
        void *res;

        snd_assert(size > 0, return NULL);
        snd_assert(res_size != NULL, return NULL);
        do {
                if ((res = snd_malloc_pages(size, gfp_flags)) != NULL) {
                        *res_size = size;
                        return res;
                }
                size >>= 1;
        } while (size >= PAGE_SIZE);
        return NULL;
}

/**
 * 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;
        for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
        unmark_pages(ptr, pg);
        free_pages((unsigned long) ptr, pg);
}

#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)

/**
 * snd_malloc_isa_pages - allocate pages for ISA bus with the given size
 * @size: the size to allocate in bytes
 * @dma_addr: the pointer to store the physical address of the buffer
 *
 * Allocates the physically contiguous pages with the given size for
 * ISA bus.
 *
 * Returns the pointer of the buffer, or NULL if no enoguh memory.
 */
void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr)
{
        void *dma_area;
        dma_area = snd_malloc_pages(size, GFP_ATOMIC|GFP_DMA);
        *dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
        return dma_area;
}

/**
 * snd_malloc_isa_pages_fallback - allocate pages with the given size with fallback 
for ISA bus
 * @size: the requested size to allocate in bytes
 * @dma_addr: the pointer to store the physical address of the buffer
 * @res_size: the pointer to store the size of buffer actually allocated
 *
 * Allocates the physically contiguous pages with the given request
 * size for PCI bus.  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.
 *
 * Returns the pointer of the buffer, or NULL if no enoguh memory.
 */
void *snd_malloc_isa_pages_fallback(size_t size,
                                    dma_addr_t *dma_addr,
                                    size_t *res_size)
{
        void *dma_area;
        dma_area = snd_malloc_pages_fallback(size, GFP_ATOMIC|GFP_DMA, res_size);
        *dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
        return dma_area;
}

#endif /* CONFIG_ISA && !CONFIG_PCI */

#ifdef CONFIG_PCI

/**
 * snd_malloc_pci_pages - allocate pages for PCI bus with the given size
 * @pci: the pci device pointer
 * @size: the size to allocate in bytes
 * @dma_addr: the pointer to store the physical address of the buffer
 *
 * Allocates the physically contiguous pages with the given size for
 * PCI bus.
 *
 * Returns the pointer of the buffer, or NULL if no enoguh memory.
 */
void *snd_malloc_pci_pages(struct pci_dev *pci,
                           size_t size,
                           dma_addr_t *dma_addr)
{
        int pg;
        void *res;

        snd_assert(size > 0, return NULL);
        snd_assert(dma_addr != NULL, return NULL);
        for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
        res = pci_alloc_consistent(pci, PAGE_SIZE * (1 << pg), dma_addr);
        if (res != NULL) {
                mark_pages(res, pg);
        }
        return res;
}

/**
 * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback 
for PCI bus
 * @pci: pci device pointer
 * @size: the requested size to allocate in bytes
 * @dma_addr: the pointer to store the physical address of the buffer
 * @res_size: the pointer to store the size of buffer actually allocated
 *
 * Allocates the physically contiguous pages with the given request
 * size for PCI bus.  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.
 *
 * Returns the pointer of the buffer, or NULL if no enoguh memory.
 */
void *snd_malloc_pci_pages_fallback(struct pci_dev *pci,
                                    size_t size,
                                    dma_addr_t *dma_addr,
                                    size_t *res_size)
{
        void *res;

        snd_assert(res_size != NULL, return NULL);
        do {
                if ((res = snd_malloc_pci_pages(pci, size, dma_addr)) != NULL) {
                        *res_size = size;
                        return res;
                }
                size >>= 1;
        } while (size >= PAGE_SIZE);
        return NULL;
}

/**
 * snd_free_pci_pages - release the pages
 * @pci: pci device pointer
 * @size: the allocated buffer size
 * @ptr: the buffer pointer to release
 * @dma_addr: the physical address of the buffer
 *
 * Releases the buffer allocated via snd_malloc_pci_pages().
 */
void snd_free_pci_pages(struct pci_dev *pci,
                        size_t size,
                        void *ptr,
                        dma_addr_t dma_addr)
{
        int pg;

        if (ptr == NULL)
                return;
        for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
        unmark_pages(ptr, pg);
        pci_free_consistent(pci, PAGE_SIZE * (1 << pg), ptr, dma_addr);
}


#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(__i386__)
/*
 * on ix86, we allocate a page with GFP_KERNEL to assure the
 * allocation.  the code is almost same with kernel/i386/pci-dma.c but
 * it allocates only a single page and checks the validity of the
 * page address with the given pci dma mask.
 */

/**
 * snd_malloc_pci_page - allocate a page in the valid pci dma mask
 * @pci: pci device pointer
 * @addrp: the pointer to store the physical address of the buffer
 *
 * Allocates a single page for the given PCI device and returns
 * the virtual address and stores the physical address on addrp.
 * 
 * This function cannot be called from interrupt handlers or
 * within spinlocks.
 */
void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
{
        void *ptr;
        dma_addr_t addr;
        unsigned long rmask;

        rmask = ~(unsigned long)(pci ? pci->dma_mask : 0x00ffffff);
        ptr = (void *)__get_free_page(GFP_KERNEL);
        if (ptr) {
                addr = virt_to_phys(ptr);
                if (((unsigned long)addr + PAGE_SIZE - 1) & rmask) {
                        /* try to reallocate with the GFP_DMA */
                        free_page((unsigned long)ptr);
                        /* use GFP_ATOMIC for the DMA zone to avoid stall */
                        ptr = (void *)__get_free_page(GFP_ATOMIC | GFP_DMA);
                        if (ptr) /* ok, the address must be within lower 16MB... */
                                addr = virt_to_phys(ptr);
                        else
                                addr = 0;
                }
        } else
                addr = 0;
        if (ptr) {
                memset(ptr, 0, PAGE_SIZE);
                mark_pages(ptr, 0);
        }
        *addrp = addr;
        return ptr;
}
#else

/* on other architectures, call snd_malloc_pci_pages() helper function
 * which uses pci_alloc_consistent().
 */
void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
{
        return snd_malloc_pci_pages(pci, PAGE_SIZE, addrp);
}

#endif

#if 0 /* for kernel-doc */
/**
 * snd_free_pci_page - release a page
 * @pci: pci device pointer
 * @ptr: the buffer pointer to release
 * @dma_addr: the physical address of the buffer
 *
 * Releases the buffer allocated via snd_malloc_pci_page().
 */
void snd_free_pci_page(struct pci_dev *pci, void *ptr, dma_addr_t dma_addr);
#endif /* for kernel-doc */

#endif /* CONFIG_PCI */

#ifdef CONFIG_SBUS

/**
 * snd_malloc_sbus_pages - allocate pages for SBUS with the given size
 * @sdev: sbus device pointer
 * @size: the size to allocate in bytes
 * @dma_addr: the pointer to store the physical address of the buffer
 *
 * Allocates the physically contiguous pages with the given size for
 * SBUS.
 *
 * Returns the pointer of the buffer, or NULL if no enoguh memory.
 */
void *snd_malloc_sbus_pages(struct sbus_dev *sdev,
                            size_t size,
                            dma_addr_t *dma_addr)
{
        int pg;
        void *res;

        snd_assert(size > 0, return NULL);
        snd_assert(dma_addr != NULL, return NULL);
        for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
        res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
        if (res != NULL) {
                mark_pages(res, pg);
        }
        return res;
}

/**
 * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback 
for SBUS
 * @sdev: sbus device pointer
 * @size: the requested size to allocate in bytes
 * @dma_addr: the pointer to store the physical address of the buffer
 * @res_size: the pointer to store the size of buffer actually allocated
 *
 * Allocates the physically contiguous pages with the given request
 * size for SBUS.  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.
 *
 * Returns the pointer of the buffer, or NULL if no enoguh memory.
 */
void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev,
                                     size_t size,
                                     dma_addr_t *dma_addr,
                                     size_t *res_size)
{
        void *res;

        snd_assert(res_size != NULL, return NULL);
        do {
                if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) {
                        *res_size = size;
                        return res;
                }
                size >>= 1;
        } while (size >= PAGE_SIZE);
        return NULL;
}

/**
 * snd_free_sbus_pages - release the pages
 * @sdev: sbus device pointer
 * @size: the allocated buffer size
 * @ptr: the buffer pointer to release
 * @dma_addr: the physical address of the buffer
 *
 * Releases the buffer allocated via snd_malloc_pci_pages().
 */
void snd_free_sbus_pages(struct sbus_dev *sdev,
                         size_t size,
                         void *ptr,
                         dma_addr_t dma_addr)
{
        int pg;

        if (ptr == NULL)
                return;
        for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
        unmark_pages(ptr, pg);
        sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
}

#endif /* CONFIG_SBUS */


#ifdef CONFIG_PROC_FS
/*
 * proc file interface
 */
static int snd_mem_proc_read(char *page, char **start, off_t off,
                             int count, int *eof, void *data)
{
        int len = 0;
        long pages = snd_allocated_pages >> (PAGE_SHIFT-12);

        len += sprintf(page + len, "pages  : %li bytes (%li pages per %likB)\n",
                       pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
        return len;
}
#endif /* CONFIG_PROC_FS */

/*
 * module entry
 */

static int __init snd_mem_init(void)
{
        if (! create_proc_read_entry("driver/snd-page-alloc", 0, 0,
                                     snd_mem_proc_read, NULL))
                return -EIO;
        return 0;
}

static void __exit snd_mem_exit(void)
{
        remove_proc_entry("driver/snd-page-alloc", NULL);
        free_all_reserved_pages();
        if (snd_allocated_pages > 0)
                printk(KERN_ERR "snd-malloc: Memory leak?  pages not freed = %li\n", 
snd_allocated_pages);
}


module_init(snd_mem_init)
module_exit(snd_mem_exit)


/*
 * exports
 */
EXPORT_SYMBOL(snd_dma_alloc_pages);
EXPORT_SYMBOL(snd_dma_free_pages);
EXPORT_SYMBOL(snd_dma_get_reserved);
EXPORT_SYMBOL(snd_dma_free_reserved);
EXPORT_SYMBOL(snd_dma_set_reserved);

EXPORT_SYMBOL(snd_malloc_pages);
EXPORT_SYMBOL(snd_malloc_pages_fallback);
EXPORT_SYMBOL(snd_free_pages);
#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
EXPORT_SYMBOL(snd_malloc_isa_pages);
EXPORT_SYMBOL(snd_malloc_isa_pages_fallback);
#endif
#ifdef CONFIG_PCI
EXPORT_SYMBOL(snd_malloc_pci_pages);
EXPORT_SYMBOL(snd_malloc_pci_pages_fallback);
EXPORT_SYMBOL(snd_malloc_pci_page);
EXPORT_SYMBOL(snd_free_pci_pages);
EXPORT_SYMBOL(snd_malloc_sgbuf_pages);
EXPORT_SYMBOL(snd_free_sgbuf_pages);
#ifdef HACK_PCI_ALLOC_CONSISTENT
EXPORT_SYMBOL(snd_pci_hack_alloc_consistent);
#endif 
#endif
#ifdef CONFIG_SBUS
EXPORT_SYMBOL(snd_malloc_sbus_pages);
EXPORT_SYMBOL(snd_malloc_sbus_pages_fallback);
EXPORT_SYMBOL(snd_free_sbus_pages);
#endif

--- NEW FILE: memory_wrapper.c ---
/*
 *  Copyright (c) by Jaroslav Kysela <[EMAIL PROTECTED]>
 *                   Takashi Iwai <[EMAIL PROTECTED]>
 * 
 *   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
 *
 */

#include <linux/config.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <sound/memalloc.h>


#ifdef HACK_PCI_ALLOC_CONSISTENT
/*
 * A dirty hack... when the kernel code is fixed this should be removed.
 *
 * since pci_alloc_consistent always tries GFP_DMA when the requested
 * pci memory region is below 32bit, it happens quite often that even
 * 2 order of pages cannot be allocated.
 *
 * so in the following, we allocate at first without dma_mask, so that
 * allocation will be done without GFP_DMA.  if the area doesn't match
 * with the requested region, then realloate with the original dma_mask
 * again.
 */

void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
                                    dma_addr_t *dma_handle)
{
        void *ret;
        u64 dma_mask;
        unsigned long rmask;

        if (hwdev == NULL)
                return pci_alloc_consistent(hwdev, size, dma_handle);
        dma_mask = hwdev->dma_mask;
        rmask = ~((unsigned long)dma_mask);
        hwdev->dma_mask = 0xffffffff; /* do without masking */
        ret = pci_alloc_consistent(hwdev, size, dma_handle);
        hwdev->dma_mask = dma_mask; /* restore */
        if (ret) {
                /* obtained address is out of range? */
                if (((unsigned long)*dma_handle + size - 1) & rmask) {
                        /* reallocate with the proper mask */
                        pci_free_consistent(hwdev, size, ret, *dma_handle);
                        ret = pci_alloc_consistent(hwdev, size, dma_handle);
                }
        } else {
                /* wish to success now with the proper mask... */
                if (dma_mask != 0xffffffff)
                        ret = pci_alloc_consistent(hwdev, size, dma_handle);
        }
        return ret;
}

#endif /* HACK_PCI_ALLOC_CONSISTENT */

--- NEW FILE: sgbuf.c ---
/*
 * Scatter-Gather buffer
 *
 *  Copyright (c) by Takashi Iwai <[EMAIL PROTECTED]>
 *
 *   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
 *
 */

#include <linux/config.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <sound/memalloc.h>


/* table entries are align to 32 */
#define SGBUF_TBL_ALIGN         32
#define sgbuf_align_table(tbl)  ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * 
SGBUF_TBL_ALIGN)


/**
 * snd_malloc_sgbuf_pages - allocate the pages for the PCI SG buffer
 * @pci: the pci device pointer
 * @size: the requested buffer size in bytes
 * @dmab: the buffer record to store
 *
 * Initializes the SG-buffer table and allocates the buffer pages
 * for the given size.
 * The pages are mapped to the virtually continuous memory.
 *
 * This function is usually called from the middle-level functions such as
 * snd_pcm_lib_malloc_pages().
 *
 * Returns the mapped virtual address of the buffer if allocation was
 * successful, or NULL at error.
 */
void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer 
*dmab)
{
        struct snd_sg_buf *sgbuf;
        unsigned int i, pages;

        dmab->area = NULL;
        dmab->addr = 0;
        dmab->private_data = sgbuf = kmalloc(sizeof(*sgbuf), GFP_KERNEL);
        if (! sgbuf)
                return NULL;
        memset(sgbuf, 0, sizeof(*sgbuf));
        sgbuf->pci = pci;
        pages = snd_sgbuf_aligned_pages(size);
        sgbuf->tblsize = sgbuf_align_table(pages);
        sgbuf->table = kmalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL);
        if (! sgbuf->table)
                goto _failed;
        memset(sgbuf->table, 0, sizeof(*sgbuf->table) * sgbuf->tblsize);
        sgbuf->page_table = kmalloc(sizeof(*sgbuf->page_table) * sgbuf->tblsize, 
GFP_KERNEL);
        if (! sgbuf->page_table)
                goto _failed;
        memset(sgbuf->page_table, 0, sizeof(*sgbuf->page_table) * sgbuf->tblsize);

        /* allocate each page */
        for (i = 0; i < pages; i++) {
                void *ptr;
                dma_addr_t addr;
                ptr = snd_malloc_pci_page(sgbuf->pci, &addr);
                if (! ptr)
                        goto _failed;
                sgbuf->table[i].buf = ptr;
                sgbuf->table[i].addr = addr;
                sgbuf->page_table[i] = virt_to_page(ptr);
                sgbuf->pages++;
        }

        sgbuf->size = size;
        dmab->area = vmap(sgbuf->page_table, sgbuf->pages);
        if (! dmab->area)
                goto _failed;
        return dmab->area;

 _failed:
        snd_free_sgbuf_pages(dmab); /* free the table */
        return NULL;
}

/**
 * snd_free_sgbuf_pages - free the sg buffer
 * @dmab: buffer record
 *
 * Releases the pages and the SG-buffer table.
 *
 * This function is called usually from the middle-level function
 * such as snd_pcm_lib_free_pages().
 *
 * Returns zero if successful, or a negative error code on failure.
 */
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
{
        struct snd_sg_buf *sgbuf = dmab->private_data;
        int i;

        if (! sgbuf)
                return -EINVAL;

        for (i = 0; i < sgbuf->pages; i++)
                snd_free_pci_page(sgbuf->pci, sgbuf->table[i].buf, 
sgbuf->table[i].addr);
        if (dmab->area)
                vunmap(dmab->area);
        dmab->area = NULL;

        if (sgbuf->table)
                kfree(sgbuf->table);
        if (sgbuf->page_table)
                kfree(sgbuf->page_table);
        kfree(sgbuf);
        dmab->private_data = NULL;
        
        return 0;
}

Index: Makefile
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/Makefile,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- Makefile    9 Feb 2003 18:41:54 -0000       1.35
+++ Makefile    28 Feb 2003 14:29:15 -0000      1.36
@@ -14,8 +14,10 @@
 
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
                pcm_memory.o
+
+snd-page-alloc-objs := memalloc.o
 ifeq ($(CONFIG_PCI),y)
-snd-pcm-objs += pcm_sgbuf.o
+snd-page-alloc-objs += sgbuf.o memory_wrapper.o
 endif
 
 snd-rawmidi-objs  := rawmidi.o
@@ -31,72 +33,72 @@
 obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
 
 obj-$(CONFIG_SND_MIXER_OSS) += oss/
-obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o oss/
+obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o snd-page-alloc.o oss/
 obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o seq/
 obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd.o
+obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
 obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-rawmidi.o snd.o snd-timer.o
 obj-$(CONFIG_SND_MTPAV) += snd-rawmidi.o snd.o snd-timer.o
 obj-$(CONFIG_SND_MPU401) += snd-rawmidi.o snd.o snd-timer.o
-obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_AD1816A) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_AD1848) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_CS4232) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CS4236) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES1688) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_GUSCLASSIC) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_GUSMAX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_GUSEXTREME) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_INTERWAVE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_INTERWAVE_STB) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o 
snd-hwdep.o
-obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o 
snd-hwdep.o
-obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o
-obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-pcm.o
-obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd.o
+obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_AD1816A) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_CS4232) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_CS4236) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ES1688) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_GUSCLASSIC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_GUSMAX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_GUSEXTREME) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_INTERWAVE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_INTERWAVE_STB) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o 
snd-hwdep.o
+obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o 
snd-hwdep.o
+obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o 
snd-hwdep.o
+obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o 
snd-hwdep.o
+obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-page-alloc.o 
snd-pcm.o
+obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
+obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
 ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-hwdep.o
   obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o
 endif
-obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o 
snd-rawmidi.o
 
 obj-m := $(sort $(obj-m))

Index: init.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/init.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -r1.32 -r1.33
--- init.c      31 Jan 2003 15:19:25 -0000      1.32
+++ init.c      28 Feb 2003 14:29:16 -0000      1.33
@@ -495,6 +495,22 @@
 
 #endif
 
+#ifdef MODULE
+static snd_info_entry_t *snd_card_module_info_entry;
+static void snd_card_module_info_read(snd_info_entry_t *entry, snd_info_buffer_t * 
buffer)
+{
+       int idx;
+       snd_card_t *card;
+
+       for (idx = 0; idx < SNDRV_CARDS; idx++) {
+               read_lock(&snd_card_rwlock);
+               if ((card = snd_cards[idx]) != NULL)
+                       snd_iprintf(buffer, "%i %s\n", idx, card->module->name);
+               read_unlock(&snd_card_rwlock);
+       }
+}
+#endif
+
 int __init snd_card_info_init(void)
 {
        snd_info_entry_t *entry;
@@ -509,6 +525,20 @@
                return -ENOMEM;
        }
        snd_card_info_entry = entry;
+
+#ifdef MODULE
+       entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
+       if (entry) {
+               entry->content = SNDRV_INFO_CONTENT_TEXT;
+               entry->c.text.read_size = PAGE_SIZE;
+               entry->c.text.read = snd_card_module_info_read;
+               if (snd_info_register(entry) < 0)
+                       snd_info_free_entry(entry);
+               else
+                       snd_card_module_info_entry = entry;
+       }
+#endif
+
        return 0;
 }
 
@@ -516,6 +546,10 @@
 {
        if (snd_card_info_entry)
                snd_info_unregister(snd_card_info_entry);
+#ifdef MODULE
+       if (snd_card_module_info_entry)
+               snd_info_unregister(snd_card_module_info_entry);
+#endif
        return 0;
 }
 

Index: memory.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/memory.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- memory.c    25 Feb 2003 15:07:34 -0000      1.25
+++ memory.c    28 Feb 2003 14:29:17 -0000      1.26
@@ -1,6 +1,7 @@
 /*
  *  Copyright (c) by Jaroslav Kysela <[EMAIL PROTECTED]>
- *  Memory allocation routines.
+ * 
+ *  Memory allocation helpers.
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -28,9 +29,6 @@
 #include <linux/pci.h>
 #include <sound/core.h>
 #include <sound/info.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
 
 /*
  *  memory allocation helpers and debug routines
@@ -48,7 +46,6 @@
 
 #define snd_alloc_track_entry(obj) (struct snd_alloc_track *)((char*)obj - (unsigned 
long)((struct snd_alloc_track *)0)->data)
 
-static long snd_alloc_pages;
 static long snd_alloc_kmalloc;
 static long snd_alloc_vmalloc;
 static LIST_HEAD(snd_alloc_kmalloc_list);
@@ -61,7 +58,6 @@
 
 void snd_memory_init(void)
 {
-       snd_alloc_pages = 0;
        snd_alloc_kmalloc = 0;
        snd_alloc_vmalloc = 0;
 }
@@ -70,8 +66,7 @@
 {
        struct list_head *head;
        struct snd_alloc_track *t;
-       if (snd_alloc_pages > 0)
-               snd_printk(KERN_ERR "Not freed snd_alloc_pages = %li\n", 
snd_alloc_pages);
+
        if (snd_alloc_kmalloc > 0)
                snd_printk(KERN_ERR "Not freed snd_alloc_kmalloc = %li\n", 
snd_alloc_kmalloc);
        if (snd_alloc_vmalloc > 0)
@@ -226,8 +221,6 @@
 
 static void snd_memory_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
 {
-       long pages = snd_alloc_pages >> (PAGE_SHIFT-12);
-       snd_iprintf(buffer, "pages  : %li bytes (%li pages per %likB)\n", pages * 
PAGE_SIZE, pages, PAGE_SIZE / 1024);
        snd_iprintf(buffer, "kmalloc: %li bytes\n", snd_alloc_kmalloc);
        snd_iprintf(buffer, "vmalloc: %li bytes\n", snd_alloc_vmalloc);
 }
@@ -263,335 +256,6 @@
 
 #endif /* CONFIG_SND_DEBUG_MEMORY */
 
-
-/**
- * snd_malloc_pages - allocate pages with the given size
- * @size: the size to allocate in bytes
- * @dma_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.
- */
-void *snd_malloc_pages(unsigned long size, unsigned int dma_flags)
-{
-       int pg;
-       void *res;
-
-       snd_assert(size > 0, return NULL);
-       snd_assert(dma_flags != 0, return NULL);
-       for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-       if ((res = (void *) __get_free_pages(dma_flags, pg)) != NULL) {
-               struct page *page = virt_to_page(res);
-               struct page *last_page = page + (1 << pg);
-               while (page < last_page)
-                       SetPageReserved(page++);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-               snd_alloc_pages += 1 << pg;
-#endif
-       }
-       return res;
-}
-
-/**
- * snd_malloc_pages_fallback - allocate pages with the given size with fallback
- * @size: the requested size to allocate in bytes
- * @dma_flags: the allocation conditions, GFP_XXX
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size.  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.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pages_fallback(unsigned long size, unsigned int dma_flags, unsigned 
long *res_size)
-{
-       void *res;
-
-       snd_assert(size > 0, return NULL);
-       snd_assert(res_size != NULL, return NULL);
-       do {
-               if ((res = snd_malloc_pages(size, dma_flags)) != NULL) {
-                       *res_size = size;
-                       return res;
-               }
-               size >>= 1;
-       } while (size >= PAGE_SIZE);
-       return NULL;
-}
-
-/**
- * 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, unsigned long size)
-{
-       int pg;
-       struct page *page, *last_page;
-
-       if (ptr == NULL)
-               return;
-       for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-       page = virt_to_page(ptr);
-       last_page = page + (1 << pg);
-       while (page < last_page)
-               ClearPageReserved(page++);
-       free_pages((unsigned long) ptr, pg);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-       snd_alloc_pages -= 1 << pg;
-#endif
-}
-
-#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
-
-/**
- * snd_malloc_isa_pages - allocate pages for ISA bus with the given size
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * ISA bus.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_isa_pages(unsigned long size, dma_addr_t *dma_addr)
-{
-       void *dma_area;
-       dma_area = snd_malloc_pages(size, GFP_ATOMIC|GFP_DMA);
-       *dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
-       return dma_area;
-}
-
-/**
- * snd_malloc_isa_pages_fallback - allocate pages with the given size with fallback 
for ISA bus
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for PCI bus.  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.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_isa_pages_fallback(unsigned long size,
-                                   dma_addr_t *dma_addr,
-                                   unsigned long *res_size)
-{
-       void *dma_area;
-       dma_area = snd_malloc_pages_fallback(size, GFP_ATOMIC|GFP_DMA, res_size);
-       *dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL;
-       return dma_area;
-}
-
-#endif /* CONFIG_ISA && !CONFIG_PCI */
-
-#ifdef CONFIG_PCI
-
-/**
- * snd_malloc_pci_pages - allocate pages for PCI bus with the given size
- * @pci: the pci device pointer
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * PCI bus.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pci_pages(struct pci_dev *pci,
-                          unsigned long size,
-                          dma_addr_t *dma_addr)
-{
-       int pg;
-       void *res;
-
-       snd_assert(size > 0, return NULL);
-       snd_assert(dma_addr != NULL, return NULL);
-       for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-       res = pci_alloc_consistent(pci, PAGE_SIZE * (1 << pg), dma_addr);
-       if (res != NULL) {
-               struct page *page = virt_to_page(res);
-               struct page *last_page = page + (1 << pg);
-               while (page < last_page)
-                       SetPageReserved(page++);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-               snd_alloc_pages += 1 << pg;
-#endif
-       }
-       return res;
-}
-
-/**
- * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback 
for PCI bus
- * @pci: pci device pointer
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for PCI bus.  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.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_pci_pages_fallback(struct pci_dev *pci,
-                                   unsigned long size,
-                                   dma_addr_t *dma_addr,
-                                   unsigned long *res_size)
-{
-       void *res;
-
-       snd_assert(res_size != NULL, return NULL);
-       do {
-               if ((res = snd_malloc_pci_pages(pci, size, dma_addr)) != NULL) {
-                       *res_size = size;
-                       return res;
-               }
-               size >>= 1;
-       } while (size >= PAGE_SIZE);
-       return NULL;
-}
-
-/**
- * snd_free_pci_pages - release the pages
- * @pci: pci device pointer
- * @size: the allocated buffer size
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_pages().
- */
-void snd_free_pci_pages(struct pci_dev *pci,
-                       unsigned long size,
-                       void *ptr,
-                       dma_addr_t dma_addr)
-{
-       int pg;
-       struct page *page, *last_page;
-
-       if (ptr == NULL)
-               return;
-       for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-       page = virt_to_page(ptr);
-       last_page = page + (1 << pg);
-       while (page < last_page)
-               ClearPageReserved(page++);
-       pci_free_consistent(pci, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-       snd_alloc_pages -= 1 << pg;
-#endif
-}
-
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_SBUS
-
-/**
- * snd_malloc_sbus_pages - allocate pages for SBUS with the given size
- * @sdev: sbus device pointer
- * @size: the size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- *
- * Allocates the physically contiguous pages with the given size for
- * SBUS.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_sbus_pages(struct sbus_dev *sdev,
-                           unsigned long size,
-                           dma_addr_t *dma_addr)
-{
-       int pg;
-       void *res;
-
-       snd_assert(size > 0, return NULL);
-       snd_assert(dma_addr != NULL, return NULL);
-       for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-       res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
-       if (res != NULL) {
-               struct page *page = virt_to_page(res);
-               struct page *last_page = page + (1 << pg);
-               while (page < last_page)
-                       SetPageReserved(page++);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-               snd_alloc_pages += 1 << pg;
-#endif
-       }
-       return res;
-}
-
-/**
- * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback 
for SBUS
- * @sdev: sbus device pointer
- * @size: the requested size to allocate in bytes
- * @dma_addr: the pointer to store the physical address of the buffer
- * @res_size: the pointer to store the size of buffer actually allocated
- *
- * Allocates the physically contiguous pages with the given request
- * size for SBUS.  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.
- *
- * Returns the pointer of the buffer, or NULL if no enoguh memory.
- */
-void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev,
-                                    unsigned long size,
-                                    dma_addr_t *dma_addr,
-                                    unsigned long *res_size)
-{
-       void *res;
-
-       snd_assert(res_size != NULL, return NULL);
-       do {
-               if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) {
-                       *res_size = size;
-                       return res;
-               }
-               size >>= 1;
-       } while (size >= PAGE_SIZE);
-       return NULL;
-}
-
-/**
- * snd_free_sbus_pages - release the pages
- * @sdev: sbus device pointer
- * @size: the allocated buffer size
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_pages().
- */
-void snd_free_sbus_pages(struct sbus_dev *sdev,
-                        unsigned long size,
-                        void *ptr,
-                        dma_addr_t dma_addr)
-{
-       int pg;
-       struct page *page, *last_page;
-
-       if (ptr == NULL)
-               return;
-       for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-       page = virt_to_page(ptr);
-       last_page = page + (1 << pg);
-       while (page < last_page)
-               ClearPageReserved(page++);
-       sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-       snd_alloc_pages -= 1 << pg;
-#endif
-}
-
-#endif /* CONFIG_SBUS */
-
 /**
  * snd_kcalloc - memory allocation and zero-clear
  * @size: the size to allocate in bytes
@@ -695,81 +359,3 @@
        return 0;
 #endif
 }
-
-
-#ifdef CONFIG_PCI
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(__i386__)
-/*
- * on ix86, we allocate a page with GFP_KERNEL to assure the
- * allocation.  the code is almost same with kernel/i386/pci-dma.c but
- * it allocates only a single page and checks the validity of the
- * page address with the given pci dma mask.
- */
-
-/**
- * snd_malloc_pci_page - allocate a page in the valid pci dma mask
- * @pci: pci device pointer
- * @addrp: the pointer to store the physical address of the buffer
- *
- * Allocates a single page for the given PCI device and returns
- * the virtual address and stores the physical address on addrp.
- * 
- * This function cannot be called from interrupt handlers or
- * within spinlocks.
- */
-void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
-{
-       void *ptr;
-       dma_addr_t addr;
-       unsigned long rmask;
-
-       rmask = ~(unsigned long)(pci ? pci->dma_mask : 0x00ffffff);
-       ptr = (void *)__get_free_page(GFP_KERNEL);
-       if (ptr) {
-               addr = virt_to_phys(ptr);
-               if (((unsigned long)addr + PAGE_SIZE - 1) & rmask) {
-                       /* try to reallocate with the GFP_DMA */
-                       free_page((unsigned long)ptr);
-                       ptr = (void *)__get_free_page(GFP_ATOMIC | GFP_DMA);
-                       if (ptr) /* ok, the address must be within lower 16MB... */
-                               addr = virt_to_phys(ptr);
-                       else
-                               addr = 0;
-               }
-       } else
-               addr = 0;
-       if (ptr) {
-               struct page *page = virt_to_page(ptr);
-               memset(ptr, 0, PAGE_SIZE);
-               SetPageReserved(page);
-#ifdef CONFIG_SND_DEBUG_MEMORY
-               snd_alloc_pages++;
-#endif
-       }
-       *addrp = addr;
-       return ptr;
-}
-#else
-/* on other architectures, call snd_malloc_pci_pages() helper function
- * which uses pci_alloc_consistent().
- */
-void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp)
-{
-       return snd_malloc_pci_pages(pci, PAGE_SIZE, addrp);
-}
-#endif /* 2.4 && i386 */
-
-#if 0 /* for kernel-doc */
-/**
- * snd_free_pci_page - release a page
- * @pci: pci device pointer
- * @ptr: the buffer pointer to release
- * @dma_addr: the physical address of the buffer
- *
- * Releases the buffer allocated via snd_malloc_pci_page().
- */
-void snd_free_pci_page(struct pci_dev *pci, void *ptr, dma_addr_t dma_addr);
-#endif /* for kernel-doc */
-
-#endif /* CONFIG_PCI */

Index: pcm.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/pcm.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- pcm.c       31 Jan 2003 15:19:25 -0000      1.24
+++ pcm.c       28 Feb 2003 14:29:18 -0000      1.25
@@ -595,8 +595,6 @@
                        snd_magic_kfree(substream);
                        return err;
                }
-               substream->dma_type = SNDRV_PCM_DMA_TYPE_UNKNOWN;
-               substream->dma_private = NULL;
                spin_lock_init(&substream->timer_lock);
                prev = substream;
        }

Index: pcm_lib.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/pcm_lib.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -r1.31 -r1.32
--- pcm_lib.c   27 Feb 2003 09:17:10 -0000      1.31
+++ pcm_lib.c   28 Feb 2003 14:29:19 -0000      1.32
@@ -2658,6 +2658,9 @@
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages);
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages_for_all);
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages);
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages_for_all);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
 #endif
 #ifdef CONFIG_SBUS
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages);

Index: pcm_memory.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/pcm_memory.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- pcm_memory.c        10 Feb 2003 11:53:49 -0000      1.18
+++ pcm_memory.c        28 Feb 2003 14:29:19 -0000      1.19
@@ -26,9 +26,6 @@
 #include <sound/pcm.h>
 #include <sound/info.h>
 #include <sound/initval.h>
-#ifdef CONFIG_PCI
-#include <sound/pcm_sgbuf.h>
-#endif
 
 static int preallocate_dma = 1;
 MODULE_PARM(preallocate_dma, "i");
@@ -44,59 +41,33 @@
 
 
 /*
- * allocate pages on the specified bus
- */
-static int alloc_pcm_pages(snd_pcm_substream_t *substream, size_t size,
-                          struct snd_pcm_dma_buffer *dmab)
-{
-       switch (substream->dma_type) {
-       case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
-               dmab->area = snd_malloc_pages(size, (unsigned int)((unsigned 
long)substream->dma_private & 0xffffffff));
-               dmab->addr = 0UL;               /* not valid */
-               break;
-#ifdef CONFIG_ISA
-       case SNDRV_PCM_DMA_TYPE_ISA:
-               dmab->area = snd_malloc_isa_pages(size, &dmab->addr);
-               break;
-#endif
-#ifdef CONFIG_PCI
-       case SNDRV_PCM_DMA_TYPE_PCI:
-               dmab->area = snd_malloc_pci_pages((struct pci_dev 
*)substream->dma_private, size, &dmab->addr);
-               break;
-       case SNDRV_PCM_DMA_TYPE_PCI_SG:
-               snd_pcm_sgbuf_alloc_pages((struct pci_dev *)substream->dma_private, 
size, dmab);
-               break;
-#endif
-#ifdef CONFIG_SBUS
-       case SNDRV_PCM_DMA_TYPE_SBUS:
-               dmab->area = snd_malloc_sbus_pages((struct sbus_dev 
*)substream->dma_private, size, &dmab->addr);
-               break;
-#endif
-       default:
-               dmab->area = NULL;
-               dmab->addr = 0;
-               return -ENXIO;
-       }
-       return 0;
-}
-
-/*
  * try to allocate as the large pages as possible.
  * stores the resultant memory size in *res_size.
  *
  * the minimum size is snd_minimum_buffer.  it should be power of 2.
  */
-static int alloc_pcm_pages_fallback(snd_pcm_substream_t *substream,
-                                   size_t size,
-                                   struct snd_pcm_dma_buffer *dmab)
+static int preallocate_pcm_pages(snd_pcm_substream_t *substream, size_t size)
 {
+       struct snd_dma_buffer *dmab = &substream->dma_buffer;
        int err;
+
        snd_assert(size > 0, return -EINVAL);
+
+       /* already reserved? */
+       if (snd_dma_get_reserved(&substream->dma_device, dmab) > 0) {
+               if (dmab->bytes >= size)
+                       return 0; /* yes */
+               /* no, reset the reserved block */
+               snd_dma_free_reserved(&substream->dma_device);
+               dmab->bytes = 0;
+       }
+
        do {
-               if ((err = alloc_pcm_pages(substream, size, dmab)) < 0)
+               if ((err = snd_dma_alloc_pages(&substream->dma_device, size, dmab)) < 
0)
                        return err;
                if (dmab->area) {
-                       dmab->bytes = size;
+                       /* remember this one */
+                       snd_dma_set_reserved(&substream->dma_device, dmab);
                        return 0;
                }
                size >>= 1;
@@ -106,46 +77,13 @@
 }
 
 /*
- * release the pages on the specified bus
- */
-static void free_pcm_pages(snd_pcm_substream_t *substream,
-                          struct snd_pcm_dma_buffer *dmab)
-{
-       switch (substream->dma_type) {
-       case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
-               snd_free_pages(dmab->area, dmab->bytes);
-               break;
-#ifdef CONFIG_ISA
-       case SNDRV_PCM_DMA_TYPE_ISA:
-               snd_free_isa_pages(dmab->bytes, dmab->area, dmab->addr);
-               break;
-#endif
-#ifdef CONFIG_PCI
-       case SNDRV_PCM_DMA_TYPE_PCI:
-               snd_free_pci_pages((struct pci_dev *)substream->dma_private,
-                                  dmab->bytes, dmab->area, dmab->addr);
-               break;
-       case SNDRV_PCM_DMA_TYPE_PCI_SG:
-               snd_pcm_sgbuf_free_pages(dmab);
-               break;
-#endif
-#ifdef CONFIG_SBUS
-       case SNDRV_PCM_DMA_TYPE_SBUS:
-               snd_free_sbus_pages((struct sbus_dev *)substream->dma_private,
-                                   dmab->bytes, dmab->area, dmab->addr);
-               break;
-#endif
-       }
-}
-
-/*
  * release the preallocated buffer if not yet done.
  */
 static void snd_pcm_lib_preallocate_dma_free(snd_pcm_substream_t *substream)
 {
        if (substream->dma_buffer.area == NULL)
                return;
-       free_pcm_pages(substream, &substream->dma_buffer);
+       snd_dma_free_reserved(&substream->dma_device);
        substream->dma_buffer.area = NULL;
 }
 
@@ -164,7 +102,7 @@
                snd_info_unregister(substream->proc_prealloc_entry);
                substream->proc_prealloc_entry = NULL;
        }
-       substream->dma_type = SNDRV_PCM_DMA_TYPE_UNKNOWN;
+       substream->dma_device.type = SNDRV_DMA_TYPE_UNKNOWN;
        return 0;
 }
 
@@ -210,7 +148,7 @@
        snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
        char line[64], str[64];
        size_t size;
-       struct snd_pcm_dma_buffer new_dmab;
+       struct snd_dma_buffer new_dmab;
 
        if (substream->runtime) {
                buffer->error = -EBUSY;
@@ -228,7 +166,7 @@
                memset(&new_dmab, 0, sizeof(new_dmab));
                if (size > 0) {
 
-                       if (alloc_pcm_pages(substream, size, &new_dmab) < 0 ||
+                       if (snd_dma_alloc_pages(&substream->dma_device, size, 
&new_dmab) < 0 ||
                            new_dmab.area == NULL) {
                                buffer->error = -ENOMEM;
                                return;
@@ -237,7 +175,7 @@
                } else {
                        substream->buffer_bytes_max = UINT_MAX;
                }
-               snd_pcm_lib_preallocate_dma_free(substream);
+               snd_dma_set_reserved(&substream->dma_device, &new_dmab);
                substream->dma_buffer = new_dmab;
        } else {
                buffer->error = -EINVAL;
@@ -254,7 +192,7 @@
 
        memset(&substream->dma_buffer, 0, sizeof(substream->dma_buffer));
        if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
-               alloc_pcm_pages_fallback(substream, size, &substream->dma_buffer);
+               preallocate_pcm_pages(substream, size);
 
        if (substream->dma_buffer.bytes > 0)
                substream->buffer_bytes_max = substream->dma_buffer.bytes;
@@ -274,6 +212,16 @@
        return 0;
 }
 
+
+/*
+ * set up the unique pcm id
+ */
+static inline void setup_pcm_id(snd_pcm_substream_t *subs)
+{
+       subs->dma_device.id = subs->pcm->device << 16 |
+               subs->stream << 8 | subs->number;
+}
+
 /**
  * snd_pcm_lib_preallocate_pages - pre-allocation for the continuous memory type
  * @substream: the pcm substream instance
@@ -289,8 +237,9 @@
                                      size_t size, size_t max,
                                      unsigned int flags)
 {
-       substream->dma_type = SNDRV_PCM_DMA_TYPE_CONTINUOUS;
-       substream->dma_private = (void *)(unsigned long)flags;
+       substream->dma_device.type = SNDRV_DMA_TYPE_CONTINUOUS;
+       substream->dma_device.dev.flags = flags;
+       setup_pcm_id(substream);
        return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -334,8 +283,9 @@
 int snd_pcm_lib_preallocate_isa_pages(snd_pcm_substream_t *substream,
                                      size_t size, size_t max)
 {
-       substream->dma_type = SNDRV_PCM_DMA_TYPE_ISA;
-       substream->dma_private = NULL;
+       substream->dma_device.type = SNDRV_DMA_TYPE_ISA;
+       substream->dma_device.dev.flags = 0; /* FIXME: any good identifier? */
+       setup_pcm_id(substream);
        return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -379,9 +329,9 @@
 int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size)
 {
        snd_pcm_runtime_t *runtime;
-       struct snd_pcm_dma_buffer dmab;
+       struct snd_dma_buffer dmab;
 
-       snd_assert(substream->dma_type != SNDRV_PCM_DMA_TYPE_UNKNOWN, return -EINVAL);
+       snd_assert(substream->dma_device.type != SNDRV_DMA_TYPE_UNKNOWN, return 
-EINVAL);
        snd_assert(substream != NULL, return -EINVAL);
        runtime = substream->runtime;
        snd_assert(runtime != NULL, return -EINVAL);    
@@ -398,7 +348,7 @@
                dmab = substream->dma_buffer;
        } else {
                memset(&dmab, 0, sizeof(dmab));
-               alloc_pcm_pages(substream, size, &dmab);
+               snd_dma_alloc_pages(&substream->dma_device, size, NULL);
        }
        if (! dmab.area)
                return -ENOMEM;
@@ -427,13 +377,13 @@
        if (runtime->dma_area == NULL)
                return 0;
        if (runtime->dma_area != substream->dma_buffer.area) {
-               struct snd_pcm_dma_buffer dmab;
+               struct snd_dma_buffer dmab;
                memset(&dmab, 0, sizeof(dmab));
                dmab.area = runtime->dma_area;
                dmab.addr = runtime->dma_addr;
                dmab.bytes = runtime->dma_bytes;
                dmab.private_data = runtime->dma_private;
-               free_pcm_pages(substream, &dmab);
+               snd_dma_free_pages(&substream->dma_device, &dmab);
        }
        runtime->dma_area = NULL;
        runtime->dma_addr = 0UL;
@@ -459,8 +409,9 @@
                                      snd_pcm_substream_t *substream,
                                      size_t size, size_t max)
 {
-       substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI;
-       substream->dma_private = pci;
+       substream->dma_device.type = SNDRV_DMA_TYPE_PCI;
+       substream->dma_device.dev.pci = pci;
+       setup_pcm_id(substream);
        return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -510,8 +461,9 @@
                                       snd_pcm_substream_t *substream,
                                       size_t size, size_t max)
 {
-       substream->dma_type = SNDRV_PCM_DMA_TYPE_SBUS;
-       substream->dma_private = sdev;
+       substream->dma_device.type = SNDRV_DMA_TYPE_SBUS;
+       substream->dma_device.dev.sbus = sdev;
+       setup_pcm_id(substream);
        return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -563,8 +515,9 @@
                                     snd_pcm_substream_t *substream,
                                     size_t size, size_t max)
 {
-       substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI_SG;
-       substream->dma_private = pci;
+       substream->dma_device.type = SNDRV_DMA_TYPE_PCI_SG;
+       substream->dma_device.dev.pci = pci;
+       setup_pcm_id(substream);
        return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
@@ -594,6 +547,24 @@
                        if ((err = snd_pcm_lib_preallocate_sg_pages(pci, substream, 
size, max)) < 0)
                                return err;
        return 0;
+}
+
+/**
+ * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
+ * @substream: the pcm substream instance
+ * @offset: the buffer offset
+ *
+ * Returns the page struct at the given buffer offset.
+ * Used as the page callback of PCM ops.
+ */
+struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long 
offset)
+{
+       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+
+       unsigned int idx = offset >> PAGE_SHIFT;
+       if (idx >= (unsigned int)sgbuf->pages)
+               return NULL;
+       return sgbuf->page_table[idx];
 }
 
 #endif /* CONFIG_PCI */

Index: sound.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/sound.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -r1.36 -r1.37
--- sound.c     25 Feb 2003 13:01:16 -0000      1.36
+++ sound.c     28 Feb 2003 14:29:21 -0000      1.37
@@ -432,24 +432,6 @@
 #endif
 EXPORT_SYMBOL(snd_kcalloc);
 EXPORT_SYMBOL(snd_kmalloc_strdup);
-EXPORT_SYMBOL(snd_malloc_pages);
-EXPORT_SYMBOL(snd_malloc_pages_fallback);
-EXPORT_SYMBOL(snd_free_pages);
-#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI)
-EXPORT_SYMBOL(snd_malloc_isa_pages);
-EXPORT_SYMBOL(snd_malloc_isa_pages_fallback);
-#endif
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(snd_malloc_pci_pages);
-EXPORT_SYMBOL(snd_malloc_pci_pages_fallback);
-EXPORT_SYMBOL(snd_malloc_pci_page);
-EXPORT_SYMBOL(snd_free_pci_pages);
-#endif
-#ifdef CONFIG_SBUS
-EXPORT_SYMBOL(snd_malloc_sbus_pages);
-EXPORT_SYMBOL(snd_malloc_sbus_pages_fallback);
-EXPORT_SYMBOL(snd_free_sbus_pages);
-#endif
 EXPORT_SYMBOL(copy_to_user_fromio);
 EXPORT_SYMBOL(copy_from_user_toio);
   /* init.c */
@@ -529,6 +511,3 @@
 EXPORT_SYMBOL(snd_wrapper_vmalloc);
 EXPORT_SYMBOL(snd_wrapper_vfree);
 #endif
-#ifdef HACK_PCI_ALLOC_CONSISTENT
-EXPORT_SYMBOL(snd_pci_hack_alloc_consistent);
-#endif 

Index: wrappers.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/wrappers.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- wrappers.c  22 Oct 2002 09:29:28 -0000      1.9
+++ wrappers.c  28 Feb 2003 14:29:21 -0000      1.10
@@ -49,59 +49,3 @@
 }
 #endif
 
-
-/* check the condition in <sound/core.h> !! */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
-#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
-
-#include <linux/pci.h>
-
-/* to be sure... */
-#ifdef HACK_PCI_ALLOC_CONSISTENT
-#error pci_alloc_consistent hack is already defined!!
-#endif
-
-/*
- * A dirty hack... when the kernel code is fixed this should be removed.
- *
- * since pci_alloc_consistent always tries GFP_DMA when the requested
- * pci memory region is below 32bit, it happens quite often that even
- * 2 order of pages cannot be allocated.
- *
- * so in the following, we allocate at first without dma_mask, so that
- * allocation will be done without GFP_DMA.  if the area doesn't match
- * with the requested region, then realloate with the original dma_mask
- * again.
- */
-
-void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
-                                   dma_addr_t *dma_handle)
-{
-       void *ret;
-       u64 dma_mask;
-       unsigned long rmask;
-
-       if (hwdev == NULL)
-               return pci_alloc_consistent(hwdev, size, dma_handle);
-       dma_mask = hwdev->dma_mask;
-       rmask = ~((unsigned long)dma_mask);
-       hwdev->dma_mask = 0xffffffff; /* do without masking */
-       ret = pci_alloc_consistent(hwdev, size, dma_handle);
-       hwdev->dma_mask = dma_mask; /* restore */
-       if (ret) {
-               /* obtained address is out of range? */
-               if (((unsigned long)*dma_handle + size - 1) & rmask) {
-                       /* reallocate with the proper mask */
-                       pci_free_consistent(hwdev, size, ret, *dma_handle);
-                       ret = pci_alloc_consistent(hwdev, size, dma_handle);
-               }
-       } else {
-               /* wish to success now with the proper mask... */
-               if (dma_mask != 0xffffffff)
-                       ret = pci_alloc_consistent(hwdev, size, dma_handle);
-       }
-       return ret;
-}
-
-#endif
-#endif

--- pcm_sgbuf.c DELETED ---



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog

Reply via email to