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

📄 harmony.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
        return bytes_to_frames(rt, caught);}static int snd_harmony_playback_open(struct snd_pcm_substream *ss){	struct snd_harmony *h = snd_pcm_substream_chip(ss);	struct snd_pcm_runtime *rt = ss->runtime;	int err;		h->psubs = ss;	rt->hw = snd_harmony_playback;	snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE, 				   &hw_constraint_rates);		err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);	if (err < 0)		return err;		return 0;}static intsnd_harmony_capture_open(struct snd_pcm_substream *ss){        struct snd_harmony *h = snd_pcm_substream_chip(ss);        struct snd_pcm_runtime *rt = ss->runtime;        int err;        h->csubs = ss;        rt->hw = snd_harmony_capture;        snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,                                   &hw_constraint_rates);        err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);        if (err < 0)                return err;        return 0;}static int snd_harmony_playback_close(struct snd_pcm_substream *ss){	struct snd_harmony *h = snd_pcm_substream_chip(ss);	h->psubs = NULL;	return 0;}static intsnd_harmony_capture_close(struct snd_pcm_substream *ss){        struct snd_harmony *h = snd_pcm_substream_chip(ss);        h->csubs = NULL;        return 0;}static int snd_harmony_hw_params(struct snd_pcm_substream *ss,		      struct snd_pcm_hw_params *hw){	int err;	struct snd_harmony *h = snd_pcm_substream_chip(ss);		err = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw));	if (err > 0 && h->dma.type == SNDRV_DMA_TYPE_CONTINUOUS)		ss->runtime->dma_addr = __pa(ss->runtime->dma_area);		return err;}static int snd_harmony_hw_free(struct snd_pcm_substream *ss) {	return snd_pcm_lib_free_pages(ss);}static struct snd_pcm_ops snd_harmony_playback_ops = {	.open =	snd_harmony_playback_open,	.close = snd_harmony_playback_close,	.ioctl = snd_pcm_lib_ioctl,	.hw_params = snd_harmony_hw_params,	.hw_free = snd_harmony_hw_free,	.prepare = snd_harmony_playback_prepare,	.trigger = snd_harmony_playback_trigger, 	.pointer = snd_harmony_playback_pointer,};static struct snd_pcm_ops snd_harmony_capture_ops = {        .open = snd_harmony_capture_open,        .close = snd_harmony_capture_close,        .ioctl = snd_pcm_lib_ioctl,        .hw_params = snd_harmony_hw_params,        .hw_free = snd_harmony_hw_free,        .prepare = snd_harmony_capture_prepare,        .trigger = snd_harmony_capture_trigger,        .pointer = snd_harmony_capture_pointer,};static int snd_harmony_pcm_init(struct snd_harmony *h){	struct snd_pcm *pcm;	int err;	harmony_disable_interrupts(h);	   	err = snd_pcm_new(h->card, "harmony", 0, 1, 1, &pcm);	if (err < 0)		return err;		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 			&snd_harmony_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,			&snd_harmony_capture_ops);	pcm->private_data = h;	pcm->info_flags = 0;	strcpy(pcm->name, "harmony");	h->pcm = pcm;	h->psubs = NULL;	h->csubs = NULL;		/* initialize graveyard buffer */	h->dma.type = SNDRV_DMA_TYPE_DEV;	h->dma.dev = &h->dev->dev;	err = snd_dma_alloc_pages(h->dma.type,				  h->dma.dev,				  BUF_SIZE*GRAVEYARD_BUFS,				  &h->gdma);	if (err < 0) {		printk(KERN_ERR PFX "cannot allocate graveyard buffer!\n");		return err;	}		/* initialize silence buffers */	err = snd_dma_alloc_pages(h->dma.type,				  h->dma.dev,				  BUF_SIZE*SILENCE_BUFS,				  &h->sdma);	if (err < 0) {		printk(KERN_ERR PFX "cannot allocate silence buffer!\n");		return err;	}	/* pre-allocate space for DMA */	err = snd_pcm_lib_preallocate_pages_for_all(pcm, h->dma.type,						    h->dma.dev,						    MAX_BUF_SIZE, 						    MAX_BUF_SIZE);	if (err < 0) {		printk(KERN_ERR PFX "buffer allocation error: %d\n", err);		return err;	}	h->st.format = snd_harmony_set_data_format(h,		SNDRV_PCM_FORMAT_S16_BE, 1);	return 0;}static void snd_harmony_set_new_gain(struct snd_harmony *h){ 	harmony_wait_for_control(h);	harmony_write(h, HARMONY_GAINCTL, h->st.gain);}static int snd_harmony_mixercontrol_info(struct snd_kcontrol *kc, 			      struct snd_ctl_elem_info *uinfo){	int mask = (kc->private_value >> 16) & 0xff;	int left_shift = (kc->private_value) & 0xff;	int right_shift = (kc->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(struct snd_kcontrol *kc, 		       struct snd_ctl_elem_value *ucontrol){	struct snd_harmony *h = snd_kcontrol_chip(kc);	int shift_left = (kc->private_value) & 0xff;	int shift_right = (kc->private_value >> 8) & 0xff;	int mask = (kc->private_value >> 16) & 0xff;	int invert = (kc->private_value >> 24) & 0xff;	int left, right;		spin_lock_irq(&h->mixer_lock);	left = (h->st.gain >> shift_left) & mask;	right = (h->st.gain >> shift_right) & mask;	if (invert) {		left = mask - left;		right = mask - right;	}		ucontrol->value.integer.value[0] = left;	if (shift_left != shift_right)		ucontrol->value.integer.value[1] = right;	spin_unlock_irq(&h->mixer_lock);	return 0;}  static int snd_harmony_volume_put(struct snd_kcontrol *kc, 		       struct snd_ctl_elem_value *ucontrol){	struct snd_harmony *h = snd_kcontrol_chip(kc);	int shift_left = (kc->private_value) & 0xff;	int shift_right = (kc->private_value >> 8) & 0xff;	int mask = (kc->private_value >> 16) & 0xff;	int invert = (kc->private_value >> 24) & 0xff;	int left, right;	int old_gain = h->st.gain;		spin_lock_irq(&h->mixer_lock);	left = ucontrol->value.integer.value[0] & mask;	if (invert)		left = mask - left;	h->st.gain &= ~( (mask << shift_left ) ); 	h->st.gain |= (left << shift_left);	if (shift_left != shift_right) {		right = ucontrol->value.integer.value[1] & mask;		if (invert)			right = mask - right;		h->st.gain &= ~( (mask << shift_right) );		h->st.gain |= (right << shift_right);	}	snd_harmony_set_new_gain(h);	spin_unlock_irq(&h->mixer_lock);		return h->st.gain != old_gain;}static int snd_harmony_captureroute_info(struct snd_kcontrol *kc, 			      struct snd_ctl_elem_info *uinfo){	static char *texts[2] = { "Line", "Mic" };	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 2;	if (uinfo->value.enumerated.item > 1)		uinfo->value.enumerated.item = 1;	strcpy(uinfo->value.enumerated.name,	       texts[uinfo->value.enumerated.item]);	return 0;}static int snd_harmony_captureroute_get(struct snd_kcontrol *kc, 			     struct snd_ctl_elem_value *ucontrol){	struct snd_harmony *h = snd_kcontrol_chip(kc);	int value;		spin_lock_irq(&h->mixer_lock);	value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1;	ucontrol->value.enumerated.item[0] = value;	spin_unlock_irq(&h->mixer_lock);	return 0;}  static int snd_harmony_captureroute_put(struct snd_kcontrol *kc, 			     struct snd_ctl_elem_value *ucontrol){	struct snd_harmony *h = snd_kcontrol_chip(kc);	int value;	int old_gain = h->st.gain;		spin_lock_irq(&h->mixer_lock);	value = ucontrol->value.enumerated.item[0] & 1;	h->st.gain &= ~HARMONY_GAIN_IS_MASK; 	h->st.gain |= value << HARMONY_GAIN_IS_SHIFT;	snd_harmony_set_new_gain(h);	spin_unlock_irq(&h->mixer_lock);		return h->st.gain != old_gain;}#define HARMONY_CONTROLS	ARRAY_SIZE(snd_harmony_controls)#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 struct snd_kcontrol_new snd_harmony_controls[] = {	HARMONY_VOLUME("Master Playback Volume", HARMONY_GAIN_LO_SHIFT, 		       HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1),	HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT,		       HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0),	HARMONY_VOLUME("Monitor Volume", HARMONY_GAIN_MA_SHIFT,		       HARMONY_GAIN_MA_SHIFT, HARMONY_GAIN_MA, 1),	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = "Input Route",		.info = snd_harmony_captureroute_info,		.get = snd_harmony_captureroute_get,		.put = snd_harmony_captureroute_put	},	HARMONY_VOLUME("Internal Speaker Switch", HARMONY_GAIN_SE_SHIFT,		       HARMONY_GAIN_SE_SHIFT, 1, 0),	HARMONY_VOLUME("Line-Out Switch", HARMONY_GAIN_LE_SHIFT,		       HARMONY_GAIN_LE_SHIFT, 1, 0),	HARMONY_VOLUME("Headphones Switch", HARMONY_GAIN_HE_SHIFT,		       HARMONY_GAIN_HE_SHIFT, 1, 0),};static void __devinitsnd_harmony_mixer_reset(struct snd_harmony *h){	harmony_mute(h);	harmony_reset(h);	h->st.gain = HARMONY_GAIN_DEFAULT;	harmony_unmute(h);}static int __devinitsnd_harmony_mixer_init(struct snd_harmony *h){	struct snd_card *card = h->card;	int idx, err;	snd_assert(h != NULL, return -EINVAL);	strcpy(card->mixername, "Harmony Gain control interface");	for (idx = 0; idx < HARMONY_CONTROLS; idx++) {		err = snd_ctl_add(card, 				  snd_ctl_new1(&snd_harmony_controls[idx], h));		if (err < 0)			return err;	}		snd_harmony_mixer_reset(h);	return 0;}static intsnd_harmony_free(struct snd_harmony *h){        if (h->gdma.addr)                snd_dma_free_pages(&h->gdma);        if (h->sdma.addr)                snd_dma_free_pages(&h->sdma);	if (h->irq >= 0)		free_irq(h->irq, h);	if (h->iobase)		iounmap(h->iobase);	parisc_set_drvdata(h->dev, NULL);	kfree(h);	return 0;}static intsnd_harmony_dev_free(struct snd_device *dev){	struct snd_harmony *h = dev->device_data;	return snd_harmony_free(h);}static int __devinitsnd_harmony_create(struct snd_card *card, 		   struct parisc_device *padev, 		   struct snd_harmony **rchip){	int err;	struct snd_harmony *h;	static struct snd_device_ops ops = {		.dev_free = snd_harmony_dev_free,	};	*rchip = NULL;	h = kzalloc(sizeof(*h), GFP_KERNEL);	if (h == NULL)		return -ENOMEM;	h->hpa = padev->hpa.start;	h->card = card;	h->dev = padev;	h->irq = -1;	h->iobase = ioremap_nocache(padev->hpa.start, HARMONY_SIZE);	if (h->iobase == NULL) {		printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n",		       padev->hpa.start);		err = -EBUSY;		goto free_and_ret;	}			err = request_irq(padev->irq, snd_harmony_interrupt, 0,			  "harmony", h);	if (err) {		printk(KERN_ERR PFX "could not obtain interrupt %d",		       padev->irq);		goto free_and_ret;	}	h->irq = padev->irq;	spin_lock_init(&h->mixer_lock);	spin_lock_init(&h->lock);        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,                                  h, &ops)) < 0) {                goto free_and_ret;        }	snd_card_set_dev(card, &padev->dev);	*rchip = h;	return 0;free_and_ret:	snd_harmony_free(h);	return err;}static int __devinitsnd_harmony_probe(struct parisc_device *padev){	int err;	struct snd_card *card;	struct snd_harmony *h;	card = snd_card_new(index, id, THIS_MODULE, 0);	if (card == NULL)		return -ENOMEM;	err = snd_harmony_create(card, padev, &h);	if (err < 0)		goto free_and_ret;	err = snd_harmony_pcm_init(h);	if (err < 0)		goto free_and_ret;	err = snd_harmony_mixer_init(h);	if (err < 0)		goto free_and_ret;	strcpy(card->driver, "harmony");	strcpy(card->shortname, "Harmony");	sprintf(card->longname, "%s at 0x%lx, irq %i",		card->shortname, h->hpa, h->irq);	err = snd_card_register(card);	if (err < 0)		goto free_and_ret;	parisc_set_drvdata(padev, card);	return 0;free_and_ret:	snd_card_free(card);	return err;}static int __devexitsnd_harmony_remove(struct parisc_device *padev){	snd_card_free(parisc_get_drvdata(padev));	parisc_set_drvdata(padev, NULL);	return 0;}static struct parisc_driver snd_harmony_driver = {	.name = "harmony",	.id_table = snd_harmony_devtable,	.probe = snd_harmony_probe,	.remove = snd_harmony_remove,};static int __init alsa_harmony_init(void){	return register_parisc_driver(&snd_harmony_driver);}static void __exitalsa_harmony_fini(void){	unregister_parisc_driver(&snd_harmony_driver);}MODULE_LICENSE("GPL");MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");MODULE_DESCRIPTION("Harmony sound driver");module_init(alsa_harmony_init);module_exit(alsa_harmony_fini);

⌨️ 快捷键说明

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