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

📄 harmony.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	.hw_free = 		snd_card_harmony_hw_free,	.prepare =		snd_card_harmony_playback_prepare,	.trigger =		snd_card_harmony_playback_trigger, 	.pointer =		snd_card_harmony_playback_pointer,};static snd_pcm_ops_t snd_card_harmony_capture_ops = {	.open =			snd_card_harmony_capture_open,	.close =		snd_card_harmony_capture_close,	.ioctl =		snd_card_harmony_capture_ioctl,	.hw_params = 	snd_card_harmony_hw_params,	.hw_free = 		snd_card_harmony_hw_free,	.prepare =		snd_card_harmony_capture_prepare,	.trigger =		snd_card_harmony_capture_trigger,	.pointer =		snd_card_harmony_capture_pointer,};static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony){	snd_pcm_t *pcm;	int err;	/* Request that IRQ */	if (request_irq(harmony->irq, snd_card_harmony_interrupt, 0 ,"harmony", harmony)) {		printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony->irq);		return -EFAULT;	}		snd_harmony_disable_interrupts(harmony);	   	if ((err = snd_pcm_new(harmony->card, "Harmony", 0, 1, 1, &pcm)) < 0)		return err;		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_harmony_playback_ops); 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_harmony_capture_ops); 		pcm->private_data = harmony;	pcm->info_flags = 0;	strcpy(pcm->name, "Harmony");	harmony->pcm = pcm;		/* initialize graveyard buffer */	harmony->dma_dev.type = SNDRV_DMA_TYPE_DEV;	harmony->dma_dev.dev = &harmony->pa_dev->dev;	err = snd_dma_alloc_pages(harmony->dma_dev.type,				  harmony->dma_dev.dev,				  HARMONY_BUF_SIZE*GRAVEYARD_BUFS,				  &harmony->graveyard_dma);	if (err == -ENOMEM) {		/* use continuous buffers */		harmony->dma_dev.type = SNDRV_DMA_TYPE_CONTINUOUS;		harmony->dma_dev.dev = snd_dma_continuous_data(GFP_KERNEL);		err = snd_dma_alloc_pages(harmony->dma_dev.type,					  harmony->dma_dev.dev,					  HARMONY_BUF_SIZE*GRAVEYARD_BUFS,					  &harmony->graveyard_dma);	}	if (err < 0) {		printk(KERN_ERR PFX "can't allocate graveyard buffer\n");		return err;	}	harmony->graveyard_count = 0;		/* initialize silence buffers */	err = snd_dma_alloc_pages(harmony->dma_dev.type,				  harmony->dma_dev.dev,				  HARMONY_BUF_SIZE*SILENCE_BUFS,				  &harmony->silence_dma);	if (err < 0) {		printk(KERN_ERR PFX "can't allocate silence buffer\n");		return err;	}	harmony->silence_count = 0;	if (harmony->dma_dev.type == SNDRV_DMA_TYPE_CONTINUOUS) {		harmony->graveyard_dma.addr = __pa(harmony->graveyard_dma.area);		harmony->silence_dma.addr = __pa(harmony->silence_dma.area);	}	harmony->ply_stopped = harmony->cap_stopped = 1;		harmony->playback_substream = NULL;	harmony->capture_substream = NULL;	harmony->graveyard_count = 0;	err = snd_pcm_lib_preallocate_pages_for_all(pcm, harmony->dma_dev.type,						    harmony->dma_dev.dev,						    MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);	if (err < 0) {		printk(KERN_ERR PFX "buffer allocation error %d\n", err);		// return err;	}	return 0;}/* * mixer routines */static void snd_harmony_set_new_gain(snd_card_harmony_t *harmony){	DPRINTK(KERN_INFO PFX "Setting new gain %x at %lx\n", harmony->current_gain, harmony->hpa+REG_GAINCTL);	/* Wait until we're out of control mode */ 	snd_harmony_wait_cntl(harmony);		gsc_writel(harmony->current_gain, harmony->hpa+REG_GAINCTL);}#define HARMONY_VOLUME(xname, left_shift, right_shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \  .info = snd_harmony_mixercontrol_info, \  .get = snd_harmony_volume_get, .put = snd_harmony_volume_put, \  .private_value = ((left_shift) | ((right_shift) << 8) | ((mask) << 16) | ((invert) << 24)) }static int snd_harmony_mixercontrol_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo){	int mask = (kcontrol->private_value >> 16) & 0xff;	int left_shift = (kcontrol->private_value) & 0xff;	int right_shift = (kcontrol->private_value >> 8) & 0xff;		uinfo->type = (mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER);	uinfo->count = (left_shift == right_shift) ? 1 : 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = mask;	return 0;} static int snd_harmony_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	snd_card_harmony_t *harmony = snd_kcontrol_chip(kcontrol);	int shift_left = (kcontrol->private_value) & 0xff;	int shift_right = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	unsigned long flags;	int left, right;		spin_lock_irqsave(&harmony->mixer_lock, flags);	left = (harmony->current_gain >> shift_left) & mask;	right = (harmony->current_gain >> shift_right) & mask;	if (invert) {		left = mask - left;		right = mask - right;	}	ucontrol->value.integer.value[0] = left;	ucontrol->value.integer.value[1] = right;	spin_unlock_irqrestore(&harmony->mixer_lock, flags);	return 0;}  static int snd_harmony_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	snd_card_harmony_t *harmony = snd_kcontrol_chip(kcontrol);	int shift_left = (kcontrol->private_value) & 0xff;	int shift_right = (kcontrol->private_value >> 8) & 0xff;	int mask = (kcontrol->private_value >> 16) & 0xff;	int invert = (kcontrol->private_value >> 24) & 0xff;	unsigned long flags;	int left, right;	int old_gain = harmony->current_gain;		left = ucontrol->value.integer.value[0] & mask;	right = ucontrol->value.integer.value[1] & mask;	if (invert) {		left = mask - left;		right = mask - right;	}		spin_lock_irqsave(&harmony->mixer_lock, flags);	harmony->current_gain = harmony->current_gain & ~( (mask << shift_right) | (mask << shift_left)); 	harmony->current_gain = harmony->current_gain | ((left << shift_left) | (right << shift_right) );	snd_harmony_set_new_gain(harmony);	spin_unlock_irqrestore(&harmony->mixer_lock, flags);		return (old_gain - harmony->current_gain);}#define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/sizeof(snd_kcontrol_new_t))static snd_kcontrol_new_t snd_harmony_controls[] = {HARMONY_VOLUME("PCM Capture Volume", 12, 16, 0x0f, 0),HARMONY_VOLUME("Master Volume", 20, 20, 0x0f, 1),HARMONY_VOLUME("PCM Playback Volume", 6, 0, 0x3f, 1),};static void __init snd_harmony_reset_codec(snd_card_harmony_t *harmony){ 	snd_harmony_wait_cntl(harmony);	gsc_writel(1, harmony->hpa+REG_RESET);	mdelay(50);		/* wait 50 ms */	gsc_writel(0, harmony->hpa+REG_RESET);}/* * Mute all the output and reset Harmony. */static void __init snd_harmony_mixer_reset(snd_card_harmony_t *harmony){	harmony->current_gain = HARMONY_GAIN_TOTAL_SILENCE;	snd_harmony_set_new_gain(harmony);	snd_harmony_reset_codec(harmony);	harmony->current_gain = HARMONY_GAIN_DEFAULT;	snd_harmony_set_new_gain(harmony);}static int __init snd_card_harmony_mixer_init(snd_card_harmony_t *harmony){	snd_card_t *card = harmony->card;	int idx, err;	snd_assert(harmony != NULL, return -EINVAL);	strcpy(card->mixername, "Harmony Gain control interface");	for (idx = 0; idx < HARMONY_CONTROLS; idx++) {		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_harmony_controls[idx], harmony))) < 0)			return err;	}		snd_harmony_mixer_reset(harmony);	return 0;}static int snd_card_harmony_create(snd_card_t *card, struct parisc_device *pa_dev, snd_card_harmony_t *harmony){	u32	cntl;		harmony->card = card;		harmony->pa_dev = pa_dev;	/* Set the HPA of harmony */	harmony->hpa = pa_dev->hpa;		harmony->irq = pa_dev->irq;	if (!harmony->irq) {		printk(KERN_ERR PFX "no irq found\n");		return -ENODEV;	}	/* Grab the ID and revision from the device */	harmony->id = (gsc_readl(harmony->hpa+REG_ID)&0x00ff0000) >> 16;	if ((harmony->id | 1) != 0x15) {		printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", harmony->id);		return -EBUSY;	}	cntl = gsc_readl(harmony->hpa+REG_CNTL);	harmony->rev = (cntl>>20) & 0xff;	printk(KERN_INFO "Lasi Harmony Audio driver h/w id %i, rev. %i at 0x%lx, IRQ %i\n",	harmony->id, harmony->rev, pa_dev->hpa, harmony->irq);		/* Make sure the control bit isn't set, although I don't think it 	   ever is. */	if (cntl & HARMONY_CNTL_C) {		printk(KERN_WARNING PFX "CNTL busy\n");		harmony->hpa = 0;		return -EBUSY;	}		return 0;}	static int __init snd_card_harmony_probe(struct parisc_device *pa_dev){	static int dev;	snd_card_harmony_t *chip;	snd_card_t *card;	int err;		if (dev >= SNDRV_CARDS)		return -ENODEV;	if (!enable[dev]) {		dev++;		return -ENOENT;	}		snd_harmony_cards[dev] = snd_card_new(index[dev], id[dev], THIS_MODULE,			    sizeof(snd_card_harmony_t));	card = snd_harmony_cards[dev];					if (card == NULL)		return -ENOMEM;	chip = (struct snd_card_harmony *)card->private_data;	spin_lock_init(&chip->control_lock);	spin_lock_init(&chip->mixer_lock);		if ((err = snd_card_harmony_create(card, pa_dev, chip)) < 0) {		printk(KERN_ERR PFX "Creation failed\n");		snd_card_free(card);		return err;	}	if ((err = snd_card_harmony_pcm_init(chip)) < 0) {		printk(KERN_ERR PFX "PCM Init failed\n");		snd_card_free(card);		return err;	}	if ((err = snd_card_harmony_mixer_init(chip)) < 0) {		printk(KERN_ERR PFX "Mixer init failed\n");		snd_card_free(card);		return err;	}		snd_harmony_proc_init(chip);		strcpy(card->driver, "Harmony");	strcpy(card->shortname, "ALSA driver for LASI Harmony");	sprintf(card->longname, "%s at h/w, id %i, rev. %i hpa 0x%lx, IRQ %i\n",card->shortname, chip->id, chip->rev, pa_dev->hpa, chip->irq);	if ((err = snd_card_register(card)) < 0) {		snd_card_free(card);		return err;	}	printk(KERN_DEBUG PFX "Successfully registered harmony pcm backend & mixer %d\n", dev);	dev++;	return 0;}static struct parisc_device_id snd_card_harmony_devicetbl[] = { { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, /* Bushmaster/Flounder */ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */ { 0, }};MODULE_DEVICE_TABLE(parisc, snd_card_harmony_devicetbl);/* * bloc device parisc. c'est une structure qui definit un device * que l'on trouve sur parisc.  * On y trouve les differents numeros HVERSION correspondant au device * en question (ce qui permet a l'inventory de l'identifier) et la fonction * d'initialisation du chose  */static struct parisc_driver snd_card_harmony_driver = {	.name		= "Lasi ALSA Harmony",	.id_table	= snd_card_harmony_devicetbl,	.probe		= snd_card_harmony_probe,};static int __init alsa_card_harmony_init(void){	int err;		if ((err = register_parisc_driver(&snd_card_harmony_driver)) < 0) {		printk(KERN_ERR "Harmony soundcard not found or device busy\n");		return err;	}	return 0;}static void __exit alsa_card_harmony_exit(void){	int idx;	snd_card_harmony_t *harmony;		for (idx = 0; idx < SNDRV_CARDS; idx++)	{		if (snd_harmony_cards[idx] != NULL)		{				DPRINTK(KERN_INFO PFX "Freeing card %d\n", idx);			harmony = snd_harmony_cards[idx]->private_data;			free_irq(harmony->irq, snd_card_harmony_interrupt);			printk(KERN_INFO PFX "Card unloaded %d, irq=%d\n", idx, harmony->irq);			snd_card_free(snd_harmony_cards[idx]);		}	}	}module_init(alsa_card_harmony_init)module_exit(alsa_card_harmony_exit)

⌨️ 快捷键说明

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