欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

aica.c

linux 内核源代码
C
第 1 页 / 共 2 页
字号:
	init_timer(&(dreamcastcard->timer));	dreamcastcard->timer.data = (unsigned long) substream;	dreamcastcard->timer.function = aica_period_elapsed;	dreamcastcard->timer.expires = jiffies + 4;	add_timer(&(dreamcastcard->timer));}static int snd_aicapcm_pcm_open(struct snd_pcm_substream				*substream){	struct snd_pcm_runtime *runtime;	struct aica_channel *channel;	struct snd_card_aica *dreamcastcard;	if (!enable)		return -ENOENT;	dreamcastcard = substream->pcm->private_data;	channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);	if (!channel)		return -ENOMEM;	/* set defaults for channel */	channel->sfmt = SM_8BIT;	channel->cmd = AICA_CMD_START;	channel->vol = dreamcastcard->master_volume;	channel->pan = 0x80;	channel->pos = 0;	channel->flags = 0;	/* default to mono */	dreamcastcard->channel = channel;	runtime = substream->runtime;	runtime->hw = snd_pcm_aica_playback_hw;	spu_enable();	dreamcastcard->clicks = 0;	dreamcastcard->current_period = 0;	dreamcastcard->dma_check = 0;	return 0;}static int snd_aicapcm_pcm_close(struct snd_pcm_substream				 *substream){	struct snd_card_aica *dreamcastcard = substream->pcm->private_data;	flush_workqueue(aica_queue);	if (dreamcastcard->timer.data)		del_timer(&dreamcastcard->timer);	kfree(dreamcastcard->channel);	spu_disable();	return 0;}static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream				   *substream){	/* Free the DMA buffer */	return snd_pcm_lib_free_pages(substream);}static int snd_aicapcm_pcm_hw_params(struct snd_pcm_substream				     *substream, struct snd_pcm_hw_params				     *hw_params){	/* Allocate a DMA buffer using ALSA built-ins */	return	    snd_pcm_lib_malloc_pages(substream,				     params_buffer_bytes(hw_params));}static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream				   *substream){	struct snd_card_aica *dreamcastcard = substream->pcm->private_data;	if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)		dreamcastcard->channel->sfmt = SM_16BIT;	dreamcastcard->channel->freq = substream->runtime->rate;	dreamcastcard->substream = substream;	return 0;}static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream				   *substream, int cmd){	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		spu_begin_dma(substream);		break;	case SNDRV_PCM_TRIGGER_STOP:		aica_chn_halt();		break;	default:		return -EINVAL;	}	return 0;}static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream					     *substream){	return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);}static struct snd_pcm_ops snd_aicapcm_playback_ops = {	.open = snd_aicapcm_pcm_open,	.close = snd_aicapcm_pcm_close,	.ioctl = snd_pcm_lib_ioctl,	.hw_params = snd_aicapcm_pcm_hw_params,	.hw_free = snd_aicapcm_pcm_hw_free,	.prepare = snd_aicapcm_pcm_prepare,	.trigger = snd_aicapcm_pcm_trigger,	.pointer = snd_aicapcm_pcm_pointer,};/* TO DO: set up to handle more than one pcm instance */static int __init snd_aicapcmchip(struct snd_card_aica				  *dreamcastcard, int pcm_index){	struct snd_pcm *pcm;	int err;	/* AICA has no capture ability */	err =	    snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,			&pcm);	if (unlikely(err < 0))		return err;	pcm->private_data = dreamcastcard;	strcpy(pcm->name, "AICA PCM");	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,			&snd_aicapcm_playback_ops);	/* Allocate the DMA buffers */	err =	    snd_pcm_lib_preallocate_pages_for_all(pcm,						  SNDRV_DMA_TYPE_CONTINUOUS,						  snd_dma_continuous_data						  (GFP_KERNEL),						  AICA_BUFFER_SIZE,						  AICA_BUFFER_SIZE);	return err;}/* Mixer controls */#define aica_pcmswitch_info		snd_ctl_boolean_mono_infostatic int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,			      struct snd_ctl_elem_value *ucontrol){	ucontrol->value.integer.value[0] = 1;	/* TO DO: Fix me */	return 0;}static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,			      struct snd_ctl_elem_value *ucontrol){	if (ucontrol->value.integer.value[0] == 1)		return 0;	/* TO DO: Fix me */	else		aica_chn_halt();	return 0;}static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,			       struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 0xFF;	return 0;}static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,			      struct snd_ctl_elem_value *ucontrol){	struct snd_card_aica *dreamcastcard;	dreamcastcard = kcontrol->private_data;	if (unlikely(!dreamcastcard->channel))		return -ETXTBSY;	/* we've not yet been set up */	ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;	return 0;}static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,			      struct snd_ctl_elem_value *ucontrol){	struct snd_card_aica *dreamcastcard;	dreamcastcard = kcontrol->private_data;	if (unlikely(!dreamcastcard->channel))		return -ETXTBSY;	if (unlikely(dreamcastcard->channel->vol ==		     ucontrol->value.integer.value[0]))		return 0;	dreamcastcard->channel->vol = ucontrol->value.integer.value[0];	dreamcastcard->master_volume = ucontrol->value.integer.value[0];	spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,		    dreamcastcard->channel, sizeof(struct aica_channel));	return 1;}static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "PCM Playback Switch",	.index = 0,	.info = aica_pcmswitch_info,	.get = aica_pcmswitch_get,	.put = aica_pcmswitch_put};static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,	.name = "PCM Playback Volume",	.index = 0,	.info = aica_pcmvolume_info,	.get = aica_pcmvolume_get,	.put = aica_pcmvolume_put};static int load_aica_firmware(void){	int err;	const struct firmware *fw_entry;	spu_reset();	err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);	if (unlikely(err))		return err;	/* write firware into memory */	spu_disable();	spu_memload(0, fw_entry->data, fw_entry->size);	spu_enable();	release_firmware(fw_entry);	return err;}static int __devinit add_aicamixer_controls(struct snd_card_aica					    *dreamcastcard){	int err;	err = snd_ctl_add	    (dreamcastcard->card,	     snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));	if (unlikely(err < 0))		return err;	err = snd_ctl_add	    (dreamcastcard->card,	     snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));	if (unlikely(err < 0))		return err;	return 0;}static int snd_aica_remove(struct platform_device *devptr){	struct snd_card_aica *dreamcastcard;	dreamcastcard = platform_get_drvdata(devptr);	if (unlikely(!dreamcastcard))		return -ENODEV;	snd_card_free(dreamcastcard->card);	kfree(dreamcastcard);	platform_set_drvdata(devptr, NULL);	return 0;}static int __init snd_aica_probe(struct platform_device *devptr){	int err;	struct snd_card_aica *dreamcastcard;	dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);	if (unlikely(!dreamcastcard))		return -ENOMEM;	dreamcastcard->card =	    snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0);	if (unlikely(!dreamcastcard->card)) {		kfree(dreamcastcard);		return -ENODEV;	}	strcpy(dreamcastcard->card->driver, "snd_aica");	strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);	strcpy(dreamcastcard->card->longname,	       "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");	/* Prepare to use the queue */	INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);	/* Load the PCM 'chip' */	err = snd_aicapcmchip(dreamcastcard, 0);	if (unlikely(err < 0))		goto freedreamcast;	snd_card_set_dev(dreamcastcard->card, &devptr->dev);	dreamcastcard->timer.data = 0;	dreamcastcard->channel = NULL;	/* Add basic controls */	err = add_aicamixer_controls(dreamcastcard);	if (unlikely(err < 0))		goto freedreamcast;	/* Register the card with ALSA subsystem */	err = snd_card_register(dreamcastcard->card);	if (unlikely(err < 0))		goto freedreamcast;	platform_set_drvdata(devptr, dreamcastcard);	aica_queue = create_workqueue(CARD_NAME);	if (unlikely(!aica_queue))		goto freedreamcast;	snd_printk	    ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");	return 0;      freedreamcast:	snd_card_free(dreamcastcard->card);	kfree(dreamcastcard);	return err;}static struct platform_driver snd_aica_driver = {	.probe = snd_aica_probe,	.remove = snd_aica_remove,	.driver = {		   .name = SND_AICA_DRIVER},};static int __init aica_init(void){	int err;	err = platform_driver_register(&snd_aica_driver);	if (unlikely(err < 0))		return err;	pd = platform_device_register_simple(SND_AICA_DRIVER, -1,					     aica_memory_space, 2);	if (unlikely(IS_ERR(pd))) {		platform_driver_unregister(&snd_aica_driver);		return PTR_ERR(pd);	}	/* Load the firmware */	return load_aica_firmware();}static void __exit aica_exit(void){	/* Destroy the aica kernel thread            *	 * being extra cautious to check if it exists*/	if (likely(aica_queue))		destroy_workqueue(aica_queue);	platform_device_unregister(pd);	platform_driver_unregister(&snd_aica_driver);	/* Kill any sound still playing and reset ARM7 to safe state */	spu_reset();}module_init(aica_init);module_exit(aica_exit);

⌨️ 快捷键说明

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