static ssize_t goldfish_audio_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) { struct goldfish_audio *data = fp->private_data; unsigned long irq_flags; ssize_t result = 0; char *kbuf; while (count > 0) { ssize_t copy = count; if (copy > WRITE_BUFFER_SIZE) copy = WRITE_BUFFER_SIZE; wait_event_interruptible(data->wait, data->buffer_status & (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY)); if ((data->buffer_status & AUDIO_INT_WRITE_BUFFER_1_EMPTY) != 0) kbuf = data->write_buffer1; else kbuf = data->write_buffer2; /* copy from user space to the appropriate buffer */ if (copy_from_user(kbuf, buf, copy)) { result = -EFAULT; break; } spin_lock_irqsave(&data->lock, irq_flags); /* * clear the buffer empty flag, and signal the emulator * to start writing the buffer */ if (kbuf == data->write_buffer1) { data->buffer_status &= ~AUDIO_INT_WRITE_BUFFER_1_EMPTY; AUDIO_WRITE(data, AUDIO_WRITE_BUFFER_1, copy); } else { data->buffer_status &= ~AUDIO_INT_WRITE_BUFFER_2_EMPTY; AUDIO_WRITE(data, AUDIO_WRITE_BUFFER_2, copy); } spin_unlock_irqrestore(&data->lock, irq_flags); buf += copy; result += copy; count -= copy; } return result; }
static int goldfish_audio_release(struct inode *ip, struct file *fp) { atomic_dec(&open_count); /* FIXME: surely this is wrong for the multi-opened case */ AUDIO_WRITE(audio_data, AUDIO_INT_ENABLE, 0); return 0; }
static ssize_t goldfish_audio_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { struct goldfish_audio *data = fp->private_data; int length; int result = 0; if (!data->read_supported) return -ENODEV; while (count > 0) { length = (count > READ_BUFFER_SIZE ? READ_BUFFER_SIZE : count); AUDIO_WRITE(data, AUDIO_START_READ, length); wait_event_interruptible(data->wait, (data->buffer_status & AUDIO_INT_READ_BUFFER_FULL)); length = AUDIO_READ(data, AUDIO_READ_BUFFER_AVAILABLE); /* copy data to user space */ if (copy_to_user(buf, data->read_buffer, length)) return -EFAULT; result += length; buf += length; count -= length; } return result; }
static void nuc900_update_dma_register(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct nuc900_audio *nuc900_audio = runtime->private_data; void __iomem *mmio_addr, *mmio_len; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { mmio_addr = nuc900_audio->mmio + ACTL_PDSTB; mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH; } else { mmio_addr = nuc900_audio->mmio + ACTL_RDSTB; mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH; } AUDIO_WRITE(mmio_addr, runtime->dma_addr); AUDIO_WRITE(mmio_len, runtime->dma_bytes); }
static void nuc900_dma_stop(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct nuc900_audio *nuc900_audio = runtime->private_data; unsigned long val; val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); val &= ~(T_DMA_IRQ | R_DMA_IRQ); AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); }
int main(int argc, char **argv) { LIBAUDIO_OBJ *p = NULL; int num; int len; unsigned char *inbuf; int j; p = AUDIO_INIT(AUDIO_MODE_WRITE); printf("after audio-init.\r\n"); inbuf =(unsigned char *)malloc(160); if(inbuf == NULL) { SYS_ERROR("malloc failed.\r\n"); return -1; } memset(inbuf, 0x00, 160); printf("after malloc.\r\n"); FILE *fp = NULL; fp = fopen("b.g711", "rb+"); fseek(fp, 0, SEEK_END); len = ftell(fp); fseek(fp, 0, SEEK_SET); num = (int)(len/160); printf("before for().\r\n"); for(j = 0; j<num; j++) { if(fread(inbuf, 160, 1, fp) != 1) { SYS_ERROR("fread failed.\r\n"); return -1; } if(AUDIO_WRITE(p, inbuf, AUDIO_A711,160) !=succeed_type_succeed) { SYS_ERROR("AUDIO_WRITE failed.\r\n"); return -1; } } fclose(fp); AUDIO_DESTROY(p, AUDIO_MODE_WRITE); return 0; }
static int nuc900_dma_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct nuc900_audio *nuc900_audio = runtime->private_data; unsigned long flags, val; int ret = 0; spin_lock_irqsave(&nuc900_audio->lock, flags); nuc900_update_dma_register(substream, nuc900_audio->dma_addr[substream->stream], nuc900_audio->buffersize[substream->stream]); val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); switch (runtime->channels) { case 1: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); val |= PLAY_RIGHT_CHNNEL; } else { val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); val |= RECORD_RIGHT_CHNNEL; } AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); break; case 2: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); else val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); break; default: ret = -EINVAL; } spin_unlock_irqrestore(&nuc900_audio->lock, flags); return ret; }
static int goldfish_audio_open(struct inode *ip, struct file *fp) { if (!audio_data) return -ENODEV; if (atomic_inc_return(&open_count) == 1) { fp->private_data = audio_data; audio_data->buffer_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY); AUDIO_WRITE(audio_data, AUDIO_INT_ENABLE, AUDIO_INT_MASK); return 0; } else { atomic_dec(&open_count); return -EBUSY; } }
static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id) { struct snd_pcm_substream *substream = dev_id; struct nuc900_audio *nuc900_audio = substream->runtime->private_data; unsigned long val; spin_lock(&nuc900_audio->lock); val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); if (val & R_DMA_IRQ) { AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ); val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); if (val & R_DMA_MIDDLE_IRQ) { val |= R_DMA_MIDDLE_IRQ; AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); } if (val & R_DMA_END_IRQ) { val |= R_DMA_END_IRQ; AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); } } else if (val & T_DMA_IRQ) { AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ); val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); if (val & P_DMA_MIDDLE_IRQ) { val |= P_DMA_MIDDLE_IRQ; AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); } if (val & P_DMA_END_IRQ) { val |= P_DMA_END_IRQ; AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); } } else { dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n"); spin_unlock(&nuc900_audio->lock); return IRQ_HANDLED; } spin_unlock(&nuc900_audio->lock); snd_pcm_period_elapsed(substream); return IRQ_HANDLED; }
static int goldfish_audio_probe(struct platform_device *pdev) { int ret; struct resource *r; struct goldfish_audio *data; dma_addr_t buf_addr; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT u32 buf_addr_high, buf_addr_low; #endif data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) { ret = -ENOMEM; goto err_data_alloc_failed; } spin_lock_init(&data->lock); init_waitqueue_head(&data->wait); platform_set_drvdata(pdev, data); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&pdev->dev, "platform_get_resource failed\n"); ret = -ENODEV; goto err_no_io_base; } data->reg_base = ioremap(r->start, PAGE_SIZE); if (data->reg_base == NULL) { ret = -ENOMEM; goto err_no_io_base; } data->irq = platform_get_irq(pdev, 0); if (data->irq < 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); ret = -ENODEV; goto err_no_irq; } data->buffer_virt = dma_alloc_coherent(&pdev->dev, COMBINED_BUFFER_SIZE, &buf_addr, GFP_KERNEL); if (data->buffer_virt == 0) { ret = -ENOMEM; dev_err(&pdev->dev, "allocate buffer failed\n"); goto err_alloc_write_buffer_failed; } data->buffer_phys = buf_addr; data->write_buffer1 = data->buffer_virt; data->write_buffer2 = data->buffer_virt + WRITE_BUFFER_SIZE; data->read_buffer = data->buffer_virt + 2 * WRITE_BUFFER_SIZE; ret = request_irq(data->irq, goldfish_audio_interrupt, IRQF_SHARED, pdev->name, data); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); goto err_request_irq_failed; } ret = misc_register(&goldfish_audio_device); if (ret) { dev_err(&pdev->dev, "misc_register returned %d in goldfish_audio_init\n", ret); goto err_misc_register_failed; } #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT buf_addr_low = (u32)(buf_addr); buf_addr_high = (u32)((buf_addr) >> 32); AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_1, buf_addr_low); AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_1_HIGH, buf_addr_high); buf_addr_low = (u32)(buf_addr + WRITE_BUFFER_SIZE); buf_addr_high = (u32)((buf_addr + WRITE_BUFFER_SIZE) >> 32); AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_2, buf_addr_low); AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_2_HIGH, buf_addr_high); buf_addr_low = (u32)(buf_addr + 2 * WRITE_BUFFER_SIZE); buf_addr_high = (u32)((buf_addr + 2 * WRITE_BUFFER_SIZE) >> 32); data->read_supported = AUDIO_READ(data, AUDIO_READ_SUPPORTED); if (data->read_supported){ AUDIO_WRITE(data, AUDIO_SET_READ_BUFFER, buf_addr_low); AUDIO_WRITE(data, AUDIO_SET_READ_BUFFER_HIGH, buf_addr_high); } #else AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_1, buf_addr); AUDIO_WRITE(data, AUDIO_SET_WRITE_BUFFER_2, buf_addr + WRITE_BUFFER_SIZE); data->read_supported = AUDIO_READ(data, AUDIO_READ_SUPPORTED); if (data->read_supported) AUDIO_WRITE(data, AUDIO_SET_READ_BUFFER, buf_addr + 2 * WRITE_BUFFER_SIZE); #endif audio_data = data; return 0; err_misc_register_failed: err_request_irq_failed: dma_free_coherent(&pdev->dev, COMBINED_BUFFER_SIZE, data->buffer_virt, data->buffer_phys); err_alloc_write_buffer_failed: err_no_irq: iounmap(data->reg_base); err_no_io_base: kfree(data); err_data_alloc_failed: return ret; }