Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15360948
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2009-12-11 13:02:39

浅析ac97声卡intel8x0的DMA内存substream->dma_buffer什么时候被赋值的

 对于snd-intel8x0.ko驱动,为设备直接申请可以供DMA使用的DDR内存空间到substream->dma_buffer
insmod snd-intel8x0.ko
==> sys_init_module
==> alsa_card_intel8x0_init
==> __pci_register_driver
==> driver_register
==> bus_add_driver
==> driver_attach
==> driver_probe_device
==> really_probe
==> pci_device_probe
==> local_pci_probe
==> snd_intel8x0_probe
==> snd_intel8x0_pcm
==> snd_intel8x0_pcm1
==> snd_pcm_lib_preallocate_pages_for_all
==> snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                          snd_dma_pci_data(chip->pci),
                          rec->prealloc_size, rec->prealloc_max_size);
这里rec就是snd_intel8x0_pcm中[luther.gliethttp]
intel_pcms[]对应的数据参数,如下:
static struct ich_pcm_table intel_pcms[] __devinitdata = {
    {
        .playback_ops = &snd_intel8x0_playback_ops,
        .capture_ops = &snd_intel8x0_capture_ops,
        .prealloc_size = 64 * 1024, // 预先申请DMA空间为64k[luther.gliethttp]
        .prealloc_max_size = 128 * 1024,
    },
    ......
};
/**
 * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams)
 * @pcm: the pcm instance
 * @type: DMA type (SNDRV_DMA_TYPE_*)
 * @data: DMA type dependant data
 * @size: the requested pre-allocation size in bytes
 * @max: the max. allowed pre-allocation size
 *
 * Do pre-allocation to all substreams of the given pcm for the
 * specified DMA type.
 *
 * Returns zero if successful, or a negative error code on failure.
 */
int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
                      int type, void *data,
                      size_t size, size_t max)
{
    struct snd_pcm_substream *substream;
    int stream, err;

    for (stream = 0; stream < 2; stream++)
        for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
            if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0)
                return err;
    return 0;
}
==> snd_pcm_lib_preallocate_pages
/**
 * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type
 * @substream: the pcm substream instance
 * @type: DMA type (SNDRV_DMA_TYPE_*)
 * @data: DMA type dependant data
 * @size: the requested pre-allocation size in bytes
 * @max: the max. allowed pre-allocation size
 *
 * Do pre-allocation for the given DMA buffer type.
 *
 * When substream->dma_buf_id is set, the function tries to look for
 * the reserved buffer, and the buffer is not freed but reserved at
 * destruction time.  The dma_buf_id must be unique for all systems
 * (in the same DMA buffer type) e.g. using snd_dma_pci_buf_id().
 *
 * Returns zero if successful, or a negative error code on failure.
 */
int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
                  int type, struct device *data,
                  size_t size, size_t max)
{
    substream->dma_buffer.dev.type = type;
    substream->dma_buffer.dev.dev = data;
    return snd_pcm_lib_preallocate_pages1(substream, size, max);
}
==> snd_pcm_lib_preallocate_pages1
/*
 * pre-allocate the buffer and create a proc file for the substream
 */
static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream,
                      size_t size, size_t max)
{

    if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
        preallocate_pcm_pages(substream, size);

    if (substream->dma_buffer.bytes > 0)
        substream->buffer_bytes_max = substream->dma_buffer.bytes;
    substream->dma_max = max;
    preallocate_info_init(substream);
    return 0;
}
==> preallocate_pcm_pages完成实际的内存申请动作[luther.gliethttp]
/*
 * 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 preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size)
{
    struct snd_dma_buffer *dmab = &substream->dma_buffer; // dmab指向substream->dma_buffer
    int err;
// 对于snd-intel8x0.ko驱动,该size值在intel_pcms[]中定义,比如这里playback放音流
// 预留DMA内存大小为64k[luther.gliethttp]
    /* already reserved? */
    if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) {
        if (dmab->bytes >= size)
            return 0; /* yes */
        /* no, free the reserved block */
        snd_dma_free_pages(dmab);
        dmab->bytes = 0;
    }
    do {
        if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev,
                           size, dmab)) < 0) { // 根据dmab->dev.type类型,在不同的地方申请DMA缓冲
            if (err != -ENOMEM)
                return err; /* fatal error */
        } else
            return 0;
        size >>= 1;
    } while (size >= snd_minimum_buffer);
    dmab->bytes = 0; /* tell error */
    return 0;
}
==> snd_dma_alloc_pages
/**
 * 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.
 *
 * Returns zero if the buffer with the given size is allocated successfuly,
 * other a negative value at error.
 */
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
            struct snd_dma_buffer *dmab)
{
    if (WARN_ON(!size))
        return -ENXIO;
    if (WARN_ON(!dmab))
        return -ENXIO;

    dmab->dev.type = type;
    dmab->dev.dev = device;
    dmab->bytes = 0;
    switch (type) {
    case SNDRV_DMA_TYPE_CONTINUOUS:
        dmab->area = snd_malloc_pages(size, (unsigned long)device);
        dmab->addr = 0;
        break;
#ifdef CONFIG_HAS_DMA
    case SNDRV_DMA_TYPE_DEV: // 对于snd-intel8x0.ko驱动,为设备直接申请可以供DMA使用的DDR内存空间
    // 因为dmab指向substream->dma_buffer,所以substream->dma_buffer的area获得了数据
        dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
        break;
#endif
#ifdef CONFIG_SND_DMA_SGBUF
    case SNDRV_DMA_TYPE_DEV_SG:
        snd_malloc_sgbuf_pages(device, size, dmab, NULL);
        break;
#endif
    default:
        printk(KERN_ERR "snd-malloc: invalid device type %d\n", type);
        dmab->area = NULL;
        dmab->addr = 0;
        return -ENXIO;
    }
    if (! dmab->area)
        return -ENOMEM;
    dmab->bytes = size;
    return 0;
}
阅读(2286) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~