linux 3.15.2 UDA1341 声卡移植

来源:互联网 发布:glide源码详解 编辑:程序博客网 时间:2024/06/07 02:58

linux3.15 相对于linux2.6.32的sound有些改动,移植方法基本和原来的相似

static struct map_desc mini2440_iodesc[] __initdata = {/* nothing to declare, move along */    {.virtual= (u32)S3C24XX_VA_ISA_WORD,.pfn= __phys_to_pfn(S3C2410_CS2),.length= 0x10000,.type= MT_DEVICE,}, {.virtual= (u32)S3C24XX_VA_ISA_WORD + 0x10000,.pfn= __phys_to_pfn(S3C2410_CS2 + (1<<24)),.length= SZ_4M,.type= MT_DEVICE,}, {.virtual= (u32)S3C24XX_VA_ISA_BYTE,.pfn= __phys_to_pfn(S3C2410_CS2),.length= 0x10000,.type= MT_DEVICE,}, {.virtual= (u32)S3C24XX_VA_ISA_BYTE + 0x10000,.pfn= __phys_to_pfn(S3C2410_CS2 + (1<<24)),.length= SZ_4M,.type= MT_DEVICE,}, {.virtual= 0xE0000000,.pfn= __phys_to_pfn(0x19000000),.length= SZ_1M,.type= MT_DEVICE,}};static struct s3c24xx_uda134x_platform_data mini2440_audio_pins = {.l3_clk = S3C2410_GPB(4),.l3_mode = S3C2410_GPB(2),.l3_data = S3C2410_GPB(3),.model = UDA134X_UDA1341};static struct platform_device mini2440_audio = {.name= "s3c24xx_uda134x",.id= 0,.dev= {.platform_data= &mini2440_audio_pins,},};static struct platform_device uda1340_codec = {.name = "uda134x-codec",.id = -1,};static struct platform_device *mini2440_devices[] __initdata = {&s3c_device_ohci,&s3c_device_wdt,&s3c_device_i2c0,&s3c_device_rtc,&s3c_device_usbgadget,&s3c_device_led,&mini2440_button_device,&s3c_device_nand,&s3c_device_sdi,&s3c_device_adc,&s3c_device_hwmon,&s3c_device_ts,&s3c_device_iis,&uda1340_codec,&mini2440_audio,&samsung_asoc_dma,};

添加上述文件后,基本就可以了,make menuconfig 启动声卡的支持

但是声卡驱动虽然移植注册成功在放音的时候噪声很大,基本都是噪音,而linux2.6.32内核的却没此问题,在网上找解决方案无果,于是尝试找到内核升级sound部分的更改,发现原来的s3c24xx_pcm.c 变为dma.c,对比两个文件确实有改动,把dma.c的内容更改后放音正常,喜悦之情不敢独享,与网友分享,希望网友少走弯路。我想给内核提交个补丁,可是流程太麻烦了。

修改后dma.c的内容

/* * dma.c  --  ALSA Soc Audio Layer * * (c) 2006 Wolfson Microelectronics PLC. * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com * * Copyright 2004-2005 Simtec Electronics *http://armlinux.simtec.co.uk/ *Ben Dooks <ben@simtec.co.uk> * *  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. */#include <linux/slab.h>#include <linux/dma-mapping.h>#include <linux/module.h>#include <sound/soc.h>#include <sound/pcm_params.h>#include <asm/dma.h>#include <mach/hardware.h>#include <mach/dma.h>#include "dma.h"#define ST_RUNNING(1<<0)#define ST_OPENED(1<<1)static const struct snd_pcm_hardware dma_hardware = {.info= SNDRV_PCM_INFO_INTERLEAVED |    SNDRV_PCM_INFO_BLOCK_TRANSFER |    SNDRV_PCM_INFO_MMAP |    SNDRV_PCM_INFO_MMAP_VALID|        SNDRV_PCM_INFO_PAUSE |    SNDRV_PCM_INFO_RESUME,.formats= SNDRV_PCM_FMTBIT_S16_LE |    SNDRV_PCM_FMTBIT_U16_LE |    SNDRV_PCM_FMTBIT_U8 |    SNDRV_PCM_FMTBIT_S8,.channels_min= 2,.channels_max= 2,.buffer_bytes_max= 128*1024,.period_bytes_min= PAGE_SIZE,.period_bytes_max= PAGE_SIZE*2,.periods_min= 2,.periods_max= 128,.fifo_size= 32,};struct runtime_data {spinlock_t lock;int state;unsigned int dma_loaded;unsigned int dma_period;dma_addr_t dma_start;dma_addr_t dma_pos;dma_addr_t dma_end;    unsigned int dma_limit;struct s3c_dma_params *params;};//static void audio_buffdone(void *data);/* dma_enqueue * * place a dma buffer onto the queue for the dma system * to handle. */static void dma_enqueue(struct snd_pcm_substream *substream){       struct runtime_data *prtd = substream->runtime->private_data;       dma_addr_t pos = prtd->dma_pos;       unsigned int limit;       int ret;        pr_debug("Entered%s\n", __func__);        if (samsung_dma_has_circular()) {   limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;   } else   limit = prtd->dma_limit;        pr_debug("%s:loaded %d, limit %d\n",                            __func__,prtd->dma_loaded, limit);        while(prtd->dma_loaded < limit) {              unsigned long len = prtd->dma_period;              pr_debug("dma_loaded:%d\n", prtd->dma_loaded);              if ((pos + len) > prtd->dma_end) {     len  = prtd->dma_end - pos;     pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",           __func__, len);      }                            ret = s3c2410_dma_enqueue(prtd->params->channel,                     substream,pos,len);               if(ret == 0){                     prtd->dma_loaded++;                     pos+= prtd->dma_period;                     if(pos>=prtd->dma_end)                            pos= prtd->dma_start;              }else                     break;       }        prtd->dma_pos= pos;}static void audio_buffdone(struct s3c2410_dma_chan *channel,                                   void* dev_id, int size,                                   enum s3c2410_dma_buffresult result){       struct snd_pcm_substream *substream = dev_id;       struct runtime_data *prtd;        pr_debug("Entered%s\n", __func__);        if(result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)              return;        prtd = substream->runtime->private_data;        if(substream)              snd_pcm_period_elapsed(substream);        spin_lock(&prtd->lock);       if(prtd->state & ST_RUNNING && !samsung_dma_has_circular()){              prtd->dma_loaded--;              dma_enqueue(substream);       }        spin_unlock(&prtd->lock);}static int dma_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_hw_params *params){struct snd_pcm_runtime *runtime = substream->runtime;struct runtime_data *prtd = runtime->private_data;struct snd_soc_pcm_runtime *rtd = substream->private_data;unsigned long totbytes = params_buffer_bytes(params);struct s3c_dma_params *dma =snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);struct samsung_dma_req req;struct samsung_dma_config config;pr_debug("Entered %s\n", __func__);/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */if (!dma)return 0;/* this may get called several times by oss emulation * with different params -HW */if (prtd->params == NULL) {/* prepare DMA */prtd->params = dma;pr_debug("params %p, client %p, channel %d\n", prtd->params,prtd->params->client, prtd->params->channel);prtd->params->ops = samsung_dma_get_ops();req.cap = (samsung_dma_has_circular() ?DMA_CYCLIC : DMA_SLAVE);req.client = prtd->params->client;config.direction =(substream->stream == SNDRV_PCM_STREAM_PLAYBACK? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);config.width = prtd->params->dma_size;config.fifo = prtd->params->dma_addr;prtd->params->ch = prtd->params->ops->request(prtd->params->channel, &req, rtd->cpu_dai->dev,prtd->params->ch_name);if (!prtd->params->ch) {pr_err("Failed to allocate DMA channel\n");return -ENXIO;}prtd->params->ops->config(prtd->params->ch, &config);}s3c2410_dma_set_buffdone_fn(prtd->params->channel,audio_buffdone);snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);runtime->dma_bytes = totbytes;spin_lock_irq(&prtd->lock);prtd->dma_loaded = 0;prtd->dma_period = params_period_bytes(params);prtd->dma_start = runtime->dma_addr;prtd->dma_pos = prtd->dma_start;prtd->dma_end = prtd->dma_start + totbytes;    prtd->dma_limit = runtime->hw.periods_min;spin_unlock_irq(&prtd->lock);return 0;}static int dma_hw_free(struct snd_pcm_substream *substream){struct runtime_data *prtd = substream->runtime->private_data;pr_debug("Entered %s\n", __func__);snd_pcm_set_runtime_buffer(substream, NULL);if (prtd->params) {prtd->params->ops->flush(prtd->params->ch);prtd->params->ops->release(prtd->params->ch,prtd->params->client);prtd->params = NULL;}return 0;}static int dma_prepare(struct snd_pcm_substream *substream){struct runtime_data *prtd = substream->runtime->private_data;int ret = 0;    struct samsung_dma_config config;pr_debug("Entered %s\n", __func__);/* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */if (!prtd->params)return 0;    config.direction =(substream->stream == SNDRV_PCM_STREAM_PLAYBACK? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);config.width = prtd->params->dma_size;config.fifo = prtd->params->dma_addr;    prtd->params->ops->config(prtd->params->ch, &config);/* flush the DMA channel */prtd->params->ops->flush(prtd->params->ch);prtd->dma_loaded = 0;prtd->dma_pos = prtd->dma_start;/* enqueue dma buffers */dma_enqueue(substream);return ret;}static int dma_trigger(struct snd_pcm_substream *substream, int cmd){struct runtime_data *prtd = substream->runtime->private_data;int ret = 0;pr_debug("Entered %s\n", __func__);spin_lock(&prtd->lock);switch (cmd) {case SNDRV_PCM_TRIGGER_START:    case SNDRV_PCM_TRIGGER_RESUME:case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:prtd->state |= ST_RUNNING;prtd->params->ops->trigger(prtd->params->ch);break;case SNDRV_PCM_TRIGGER_STOP:    case SNDRV_PCM_TRIGGER_SUSPEND:case SNDRV_PCM_TRIGGER_PAUSE_PUSH:prtd->state &= ~ST_RUNNING;prtd->params->ops->stop(prtd->params->ch);break;default:ret = -EINVAL;break;}spin_unlock(&prtd->lock);return ret;}static snd_pcm_uframes_tdma_pointer(struct snd_pcm_substream *substream){struct snd_pcm_runtime *runtime = substream->runtime;struct runtime_data *prtd = runtime->private_data;unsigned long res;//pr_debug("Entered %s\n", __func__);//res = prtd->dma_pos - prtd->dma_start;    dma_addr_t src, dst;pr_debug("Entered %s\n", __func__);spin_lock(&prtd->lock);s3c2410_dma_getposition(prtd->params->channel, &src, &dst);if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)res = dst - prtd->dma_start;elseres = src - prtd->dma_start;spin_unlock(&prtd->lock);pr_debug("Pointer offset: %lu\n", res);/* we seem to be getting the odd error from the pcm library due * to out-of-bounds pointers. this is maybe due to the dma engine * not having loaded the new values for the channel before being * called... (todo - fix ) */if (res >= snd_pcm_lib_buffer_bytes(substream)) {if (res == snd_pcm_lib_buffer_bytes(substream))res = 0;}return bytes_to_frames(substream->runtime, res);}static int dma_open(struct snd_pcm_substream *substream){struct snd_pcm_runtime *runtime = substream->runtime;struct runtime_data *prtd;pr_debug("Entered %s\n", __func__);snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);snd_soc_set_runtime_hwparams(substream, &dma_hardware);prtd = kzalloc(sizeof(struct runtime_data), GFP_KERNEL);if (prtd == NULL)return -ENOMEM;spin_lock_init(&prtd->lock);runtime->private_data = prtd;return 0;}static int dma_close(struct snd_pcm_substream *substream){struct snd_pcm_runtime *runtime = substream->runtime;struct runtime_data *prtd = runtime->private_data;pr_debug("Entered %s\n", __func__);if (!prtd)pr_debug("dma_close called with prtd == NULL\n");kfree(prtd);return 0;}static int dma_mmap(struct snd_pcm_substream *substream,struct vm_area_struct *vma){struct snd_pcm_runtime *runtime = substream->runtime;pr_debug("Entered %s\n", __func__);return dma_mmap_writecombine(substream->pcm->card->dev, vma,     runtime->dma_area,     runtime->dma_addr,     runtime->dma_bytes);}static struct snd_pcm_ops dma_ops = {.open= dma_open,.close= dma_close,.ioctl= snd_pcm_lib_ioctl,.hw_params= dma_hw_params,.hw_free= dma_hw_free,.prepare= dma_prepare,.trigger= dma_trigger,.pointer= dma_pointer,.mmap= dma_mmap,};static int preallocate_dma_buffer(struct snd_pcm *pcm, int stream){struct snd_pcm_substream *substream = pcm->streams[stream].substream;struct snd_dma_buffer *buf = &substream->dma_buffer;size_t size = dma_hardware.buffer_bytes_max;pr_debug("Entered %s\n", __func__);buf->dev.type = SNDRV_DMA_TYPE_DEV;buf->dev.dev = pcm->card->dev;buf->private_data = NULL;buf->area = dma_alloc_writecombine(pcm->card->dev, size,   &buf->addr, GFP_KERNEL);if (!buf->area)return -ENOMEM;buf->bytes = size;return 0;}static void dma_free_dma_buffers(struct snd_pcm *pcm){struct snd_pcm_substream *substream;struct snd_dma_buffer *buf;int stream;pr_debug("Entered %s\n", __func__);for (stream = 0; stream < 2; stream++) {substream = pcm->streams[stream].substream;if (!substream)continue;buf = &substream->dma_buffer;if (!buf->area)continue;dma_free_writecombine(pcm->card->dev, buf->bytes,      buf->area, buf->addr);buf->area = NULL;}}static int dma_new(struct snd_soc_pcm_runtime *rtd){struct snd_card *card = rtd->card->snd_card;struct snd_pcm *pcm = rtd->pcm;int ret;pr_debug("Entered %s\n", __func__);ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));if (ret)return ret;if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {ret = preallocate_dma_buffer(pcm,SNDRV_PCM_STREAM_PLAYBACK);if (ret)goto out;}if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {ret = preallocate_dma_buffer(pcm,SNDRV_PCM_STREAM_CAPTURE);if (ret)goto out;}out:return ret;}static struct snd_soc_platform_driver samsung_asoc_platform = {.ops= &dma_ops,.pcm_new= dma_new,.pcm_free= dma_free_dma_buffers,};void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,struct s3c_dma_params *playback,struct s3c_dma_params *capture){snd_soc_dai_init_dma_data(dai, playback, capture);}EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);int samsung_asoc_dma_platform_register(struct device *dev){return snd_soc_register_platform(dev, &samsung_asoc_platform);}EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);void samsung_asoc_dma_platform_unregister(struct device *dev){snd_soc_unregister_platform(dev);}EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");MODULE_DESCRIPTION("Samsung ASoC DMA Driver");MODULE_LICENSE("GPL");


0 0
原创粉丝点击