예제 #1
0
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;
}
예제 #4
0
파일: nuc900-pcm.c 프로젝트: 020gzh/linux
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);
}
예제 #5
0
파일: nuc900-pcm.c 프로젝트: 020gzh/linux
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);
}
예제 #6
0
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;
}
예제 #7
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;
	}
}
예제 #9
0
파일: nuc900-pcm.c 프로젝트: 020gzh/linux
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;
}