⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 es1968.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			kfree(chunk);		}	}	mutex_unlock(&chip->memory_mutex);}static void snd_es1968_free_dmabuf(struct es1968 *chip){	struct list_head *p;	if (! chip->dma.area)		return;	snd_dma_reserve_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci));	while ((p = chip->buf_list.next) != &chip->buf_list) {		struct esm_memory *chunk = list_entry(p, struct esm_memory, list);		list_del(p);		kfree(chunk);	}}static int __devinitsnd_es1968_init_dmabuf(struct es1968 *chip){	int err;	struct esm_memory *chunk;	chip->dma.dev.type = SNDRV_DMA_TYPE_DEV;	chip->dma.dev.dev = snd_dma_pci_data(chip->pci);	if (! snd_dma_get_reserved_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci))) {		err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV,						   snd_dma_pci_data(chip->pci),						   chip->total_bufsize, &chip->dma);		if (err < 0 || ! chip->dma.area) {			snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n",				   chip->total_bufsize);			return -ENOMEM;		}		if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) {			snd_dma_free_pages(&chip->dma);			snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n");			return -ENOMEM;		}	}	INIT_LIST_HEAD(&chip->buf_list);	/* allocate an empty chunk */	chunk = kmalloc(sizeof(*chunk), GFP_KERNEL);	if (chunk == NULL) {		snd_es1968_free_dmabuf(chip);		return -ENOMEM;	}	memset(chip->dma.area, 0, ESM_MEM_ALIGN);	chunk->buf = chip->dma;	chunk->buf.area += ESM_MEM_ALIGN;	chunk->buf.addr += ESM_MEM_ALIGN;	chunk->buf.bytes -= ESM_MEM_ALIGN;	chunk->empty = 1;	list_add(&chunk->list, &chip->buf_list);	return 0;}/* setup the dma_areas *//* buffer is extracted from the pre-allocated memory chunk */static int snd_es1968_hw_params(struct snd_pcm_substream *substream,				struct snd_pcm_hw_params *hw_params){	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct esschan *chan = runtime->private_data;	int size = params_buffer_bytes(hw_params);	if (chan->memory) {		if (chan->memory->buf.bytes >= size) {			runtime->dma_bytes = size;			return 0;		}		snd_es1968_free_memory(chip, chan->memory);	}	chan->memory = snd_es1968_new_memory(chip, size);	if (chan->memory == NULL) {		// snd_printd("cannot allocate dma buffer: size = %d\n", size);		return -ENOMEM;	}	snd_pcm_set_runtime_buffer(substream, &chan->memory->buf);	return 1; /* area was changed */}/* remove dma areas if allocated */static int snd_es1968_hw_free(struct snd_pcm_substream *substream){	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct esschan *chan;		if (runtime->private_data == NULL)		return 0;	chan = runtime->private_data;	if (chan->memory) {		snd_es1968_free_memory(chip, chan->memory);		chan->memory = NULL;	}	return 0;}/* * allocate APU pair */static int snd_es1968_alloc_apu_pair(struct es1968 *chip, int type){	int apu;	for (apu = 0; apu < NR_APUS; apu += 2) {		if (chip->apu[apu] == ESM_APU_FREE &&		    chip->apu[apu + 1] == ESM_APU_FREE) {			chip->apu[apu] = chip->apu[apu + 1] = type;			return apu;		}	}	return -EBUSY;}/* * release APU pair */static void snd_es1968_free_apu_pair(struct es1968 *chip, int apu){	chip->apu[apu] = chip->apu[apu + 1] = ESM_APU_FREE;}/****************** * PCM open/close * ******************/static int snd_es1968_playback_open(struct snd_pcm_substream *substream){	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct esschan *es;	int apu1;	/* search 2 APUs */	apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY);	if (apu1 < 0)		return apu1;	es = kzalloc(sizeof(*es), GFP_KERNEL);	if (!es) {		snd_es1968_free_apu_pair(chip, apu1);		return -ENOMEM;	}	es->apu[0] = apu1;	es->apu[1] = apu1 + 1;	es->apu_mode[0] = 0;	es->apu_mode[1] = 0;	es->running = 0;	es->substream = substream;	es->mode = ESM_MODE_PLAY;	runtime->private_data = es;	runtime->hw = snd_es1968_playback;	runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max =		calc_available_memory_size(chip);	spin_lock_irq(&chip->substream_lock);	list_add(&es->list, &chip->substream_list);	spin_unlock_irq(&chip->substream_lock);	return 0;}static int snd_es1968_capture_open(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct esschan *es;	int apu1, apu2;	apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE);	if (apu1 < 0)		return apu1;	apu2 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_RATECONV);	if (apu2 < 0) {		snd_es1968_free_apu_pair(chip, apu1);		return apu2;	}		es = kzalloc(sizeof(*es), GFP_KERNEL);	if (!es) {		snd_es1968_free_apu_pair(chip, apu1);		snd_es1968_free_apu_pair(chip, apu2);		return -ENOMEM;	}	es->apu[0] = apu1;	es->apu[1] = apu1 + 1;	es->apu[2] = apu2;	es->apu[3] = apu2 + 1;	es->apu_mode[0] = 0;	es->apu_mode[1] = 0;	es->apu_mode[2] = 0;	es->apu_mode[3] = 0;	es->running = 0;	es->substream = substream;	es->mode = ESM_MODE_CAPTURE;	/* get mixbuffer */	if ((es->mixbuf = snd_es1968_new_memory(chip, ESM_MIXBUF_SIZE)) == NULL) {		snd_es1968_free_apu_pair(chip, apu1);		snd_es1968_free_apu_pair(chip, apu2);		kfree(es);                return -ENOMEM;        }	memset(es->mixbuf->buf.area, 0, ESM_MIXBUF_SIZE);	runtime->private_data = es;	runtime->hw = snd_es1968_capture;	runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max =		calc_available_memory_size(chip) - 1024; /* keep MIXBUF size */	snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);	spin_lock_irq(&chip->substream_lock);	list_add(&es->list, &chip->substream_list);	spin_unlock_irq(&chip->substream_lock);	return 0;}static int snd_es1968_playback_close(struct snd_pcm_substream *substream){	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct esschan *es;	if (substream->runtime->private_data == NULL)		return 0;	es = substream->runtime->private_data;	spin_lock_irq(&chip->substream_lock);	list_del(&es->list);	spin_unlock_irq(&chip->substream_lock);	snd_es1968_free_apu_pair(chip, es->apu[0]);	kfree(es);	return 0;}static int snd_es1968_capture_close(struct snd_pcm_substream *substream){	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct esschan *es;	if (substream->runtime->private_data == NULL)		return 0;	es = substream->runtime->private_data;	spin_lock_irq(&chip->substream_lock);	list_del(&es->list);	spin_unlock_irq(&chip->substream_lock);	snd_es1968_free_memory(chip, es->mixbuf);	snd_es1968_free_apu_pair(chip, es->apu[0]);	snd_es1968_free_apu_pair(chip, es->apu[2]);	kfree(es);	return 0;}static struct snd_pcm_ops snd_es1968_playback_ops = {	.open =		snd_es1968_playback_open,	.close =	snd_es1968_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_es1968_hw_params,	.hw_free =	snd_es1968_hw_free,	.prepare =	snd_es1968_pcm_prepare,	.trigger =	snd_es1968_pcm_trigger,	.pointer =	snd_es1968_pcm_pointer,};static struct snd_pcm_ops snd_es1968_capture_ops = {	.open =		snd_es1968_capture_open,	.close =	snd_es1968_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_es1968_hw_params,	.hw_free =	snd_es1968_hw_free,	.prepare =	snd_es1968_pcm_prepare,	.trigger =	snd_es1968_pcm_trigger,	.pointer =	snd_es1968_pcm_pointer,};/* * measure clock */#define CLOCK_MEASURE_BUFSIZE	16768	/* enough large for a single shot */static void __devinit es1968_measure_clock(struct es1968 *chip){	int i, apu;	unsigned int pa, offset, t;	struct esm_memory *memory;	struct timeval start_time, stop_time;	if (chip->clock == 0)		chip->clock = 48000; /* default clock value */	/* search 2 APUs (although one apu is enough) */	if ((apu = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY)) < 0) {		snd_printk(KERN_ERR "Hmm, cannot find empty APU pair!?\n");		return;	}	if ((memory = snd_es1968_new_memory(chip, CLOCK_MEASURE_BUFSIZE)) == NULL) {		snd_printk(KERN_ERR "cannot allocate dma buffer - using default clock %d\n", chip->clock);		snd_es1968_free_apu_pair(chip, apu);		return;	}	memset(memory->buf.area, 0, CLOCK_MEASURE_BUFSIZE);	wave_set_register(chip, apu << 3, (memory->buf.addr - 0x10) & 0xfff8);	pa = (unsigned int)((memory->buf.addr - chip->dma.addr) >> 1);	pa |= 0x00400000;	/* System RAM (Bit 22) */	/* initialize apu */	for (i = 0; i < 16; i++)		apu_set_register(chip, apu, i, 0x0000);	apu_set_register(chip, apu, 0, 0x400f);	apu_set_register(chip, apu, 4, ((pa >> 16) & 0xff) << 8);	apu_set_register(chip, apu, 5, pa & 0xffff);	apu_set_register(chip, apu, 6, (pa + CLOCK_MEASURE_BUFSIZE/2) & 0xffff);	apu_set_register(chip, apu, 7, CLOCK_MEASURE_BUFSIZE/2);	apu_set_register(chip, apu, 8, 0x0000);	apu_set_register(chip, apu, 9, 0xD000);	apu_set_register(chip, apu, 10, 0x8F08);	apu_set_register(chip, apu, 11, 0x0000);	spin_lock_irq(&chip->reg_lock);	outw(1, chip->io_port + 0x04); /* clear WP interrupts */	outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); /* enable WP ints */	spin_unlock_irq(&chip->reg_lock);	snd_es1968_apu_set_freq(chip, apu, ((unsigned int)48000 << 16) / chip->clock); /* 48000 Hz */	chip->in_measurement = 1;	chip->measure_apu = apu;	spin_lock_irq(&chip->reg_lock);	snd_es1968_bob_inc(chip, ESM_BOB_FREQ);	__apu_set_register(chip, apu, 5, pa & 0xffff);	snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR);	do_gettimeofday(&start_time);	spin_unlock_irq(&chip->reg_lock);	msleep(50);	spin_lock_irq(&chip->reg_lock);	offset = __apu_get_register(chip, apu, 5);	do_gettimeofday(&stop_time);	snd_es1968_trigger_apu(chip, apu, 0); /* stop */	snd_es1968_bob_dec(chip);	chip->in_measurement = 0;	spin_unlock_irq(&chip->reg_lock);	/* check the current position */	offset -= (pa & 0xffff);	offset &= 0xfffe;	offset += chip->measure_count * (CLOCK_MEASURE_BUFSIZE/2);	t = stop_time.tv_sec - start_time.tv_sec;	t *= 1000000;	if (stop_time.tv_usec < start_time.tv_usec)		t -= start_time.tv_usec - stop_time.tv_usec;	else		t += stop_time.tv_usec - start_time.tv_usec;	if (t == 0) {		snd_printk(KERN_ERR "?? calculation error..\n");	} else {		offset *= 1000;		offset = (offset / t) * 1000 + ((offset % t) * 1000) / t;		if (offset < 47500 || offset > 48500) {			if (offset >= 40000 && offset <= 50000)				chip->clock = (chip->clock * offset) / 48000;		}		printk(KERN_INFO "es1968: clocking to %d\n", chip->clock);	}	snd_es1968_free_memory(chip, memory);	snd_es1968_free_apu_pair(chip, apu);}/* */static void snd_es1968_pcm_free(struct snd_pcm *pcm){	struct es1968 *esm = pcm->private_data;	snd_es1968_free_dmabuf(esm);	esm->pcm = NULL;}static int __devinitsnd_es1968_pcm(struct es1968 *chip, int device){	struct snd_pcm *pcm;	int err;	/* get DMA buffer */	if ((err = snd_es1968_init_dmabuf(chip)) < 0)		return err;	/* set PCMBAR */	wave_set_register(chip, 0x01FC, chip->dma.addr >> 12);	wave_set_register(chip, 0x01FD, chip->dma.addr >> 12);	wave_set_register(chip, 0x01FE, chip->dma.addr >> 12);	wave_set_register(chip, 0x01FF, chip->dma.addr >> 12);	if ((err = snd_pcm_new(chip->card, "ESS Maestro", device,			       chip->playback_streams,			       chip->capture_streams, &pcm)) < 0)		return err;	pcm->private_data = chip;	pcm->private_free = snd_es1968_pcm_free;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1968_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1968_capture_ops);	pcm->info_flags = 0;	strcpy(pcm->name, "ESS Maestro");	chip->pcm = pcm;	return 0;}/* * update pointer */static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es){	unsigned int hwptr;	unsigned int diff;	struct snd_pcm_substream *subs = es->substream;        	if (subs == NULL || !es->running)		return;	hwptr = snd_es1968_get_dma_ptr(chip, es) << es->wav_shift;	hwptr %= es->dma_size;	diff = (es->dma_size + hwptr - es->hwptr) % es->dma_size;	es->hwptr = hwptr;	es->count += diff;	if (es->count > es->frag_size) {		spin_unlock(&chip->substream_lock);		snd_pcm_period_elapsed(subs);		spin_lock(&chip->substream_lock);		es->count %= es->frag_size;	}}/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -