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

📄 sscape.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	int err;#define CS4231_SHARE_HARDWARE  (CS4231_HWSHARE_DMA1 | CS4231_HWSHARE_DMA2)	/*	 * The AD1845 PCM device is only half-duplex, and so	 * we only give it one DMA channel ...	 */	if ((err = snd_cs4231_create(card,				     port, -1, irq, dma1, dma1,				     CS4231_HW_DETECT,				     CS4231_HWSHARE_DMA1, &chip)) == 0) {		unsigned long flags;		snd_pcm_t *pcm;#define AD1845_FREQ_SEL_ENABLE  0x08#define AD1845_PWR_DOWN_CTRL   0x1b#define AD1845_CRYS_CLOCK_SEL  0x1d/* * It turns out that the PLAYBACK_ENABLE bit is set * by the lowlevel driver ... *#define AD1845_IFACE_CONFIG  \           (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)    snd_cs4231_mce_up(chip);    spin_lock_irqsave(&chip->reg_lock, flags);    snd_cs4231_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);    spin_unlock_irqrestore(&chip->reg_lock, flags);    snd_cs4231_mce_down(chip); */		/*		 * The input clock frequency on the SoundScape must		 * be 14.31818 MHz, because we must set this register		 * to get the playback to sound correct ...		 */		snd_cs4231_mce_up(chip);		spin_lock_irqsave(&chip->reg_lock, flags);		snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);		spin_unlock_irqrestore(&chip->reg_lock, flags);		snd_cs4231_mce_down(chip);		/*		 * More custom configuration:		 * a) select "mode 2", and provide a current drive of 8 mA		 * b) enable frequency selection (for capture/playback)		 */		spin_lock_irqsave(&chip->reg_lock, flags);		snd_cs4231_out(chip, CS4231_MISC_INFO, (CS4231_MODE2 | 0x10));		snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL, snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL) | AD1845_FREQ_SEL_ENABLE);		spin_unlock_irqrestore(&chip->reg_lock, flags);		if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) {			snd_printk(KERN_ERR "sscape: No PCM device for AD1845 chip\n");			goto _error;		}		if ((err = snd_cs4231_mixer(chip)) < 0) {			snd_printk(KERN_ERR "sscape: No mixer device for AD1845 chip\n");			goto _error;		}		if ((err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip))) < 0) {			snd_printk(KERN_ERR "sscape: Could not create MIDI mixer control\n");			goto _error;		}		strcpy(card->driver, "SoundScape");		strcpy(card->shortname, pcm->name);		snprintf(card->longname, sizeof(card->longname),		         "%s at 0x%lx, IRQ %d, DMA %d\n",		         pcm->name, chip->port, chip->irq, chip->dma1);		chip->set_playback_format = ad1845_playback_format;		chip->set_capture_format = ad1845_capture_format;		sscape->chip = chip;	}	_error:	return err;}struct params{	int index;	const char *id;	unsigned port;	int irq;	int mpu_irq;	int dma1;};static inline struct params*init_params(struct params *params,            int index,            const char *id,            unsigned port,            int irq,            int mpu_irq,            int dma1){	params->index = index;	params->id = id;	params->port = port;	params->irq = irq;	params->mpu_irq = mpu_irq;  	params->dma1 = (dma1 & 0x03);	return params;}/* * Create an ALSA soundcard entry for the SoundScape, using * the given list of port, IRQ and DMA resources. */static int __devinit create_sscape(const struct params *params, snd_card_t **rcardp){	snd_card_t *card;	register struct soundscape *sscape;	register unsigned dma_cfg;	unsigned irq_cfg;	unsigned mpu_irq_cfg;	struct resource *io_res;	unsigned long flags;	int err;	/*	 * Check that the user didn't pass us garbage data ...	 */	irq_cfg = get_irq_config(params->irq);	if (irq_cfg == INVALID_IRQ) {		snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", params->irq);		return -ENXIO;	}	mpu_irq_cfg = get_irq_config(params->mpu_irq);	if (mpu_irq_cfg == INVALID_IRQ) {		printk(KERN_ERR "sscape: Invalid IRQ %d\n", params->mpu_irq);		return -ENXIO;	}	/*	 * Grab IO ports that we will need to probe so that we	 * can detect and control this hardware ...	 */	if ((io_res = request_region(params->port, 8, "SoundScape")) == NULL) {		snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", params->port);		return -EBUSY;	}	/*	 * Grab both DMA channels (OK, only one for now) ...	 */	if ((err = request_dma(params->dma1, "SoundScape")) < 0) {		snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", params->dma1);		goto _release_region;	}	/*	 * Create a new ALSA sound card entry, in anticipation	 * of detecting our hardware ...	 */	if ((card = snd_card_new(params->index, params->id, THIS_MODULE, sizeof(struct soundscape))) == NULL) {		err = -ENOMEM;		goto _release_dma;	}	sscape = get_card_soundscape(card);	spin_lock_init(&sscape->lock);	spin_lock_init(&sscape->fwlock);	sscape->io_res = io_res;	sscape->io_base = params->port;	if (!detect_sscape(sscape)) {		printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);		err = -ENODEV;		goto _release_card;	}	printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n",	                 sscape->io_base, params->irq, params->dma1);	/*	 * Now create the hardware-specific device so that we can	 * load the microcode into the on-board processor.	 * We cannot use the MPU-401 MIDI system until this firmware	 * has been loaded into the card.	 */	if ((err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw))) < 0) {		printk(KERN_ERR "sscape: Failed to create firmware device\n");		goto _release_card;	}	strlcpy(sscape->hw->name, "SoundScape M68K", sizeof(sscape->hw->name));	sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0';	sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE;	sscape->hw->ops.open = sscape_hw_open;	sscape->hw->ops.release = sscape_hw_release;	sscape->hw->ops.ioctl = sscape_hw_ioctl;	sscape->hw->private_data = sscape;	/*	 * Tell the on-board devices where their resources are (I think -	 * I can't be sure without a datasheet ... So many magic values!)	 */	spin_lock_irqsave(&sscape->lock, flags);	activate_ad1845_unsafe(sscape->io_base);	sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */	sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);	sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);	/*	 * Enable and configure the DMA channels ...	 */	sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);	dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40);	sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);	sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);	sscape_write_unsafe(sscape->io_base,	                    GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg);	sscape_write_unsafe(sscape->io_base,	                    GA_CDCFG_REG, 0x09 | DMA_8BIT | (params->dma1 << 4) | (irq_cfg << 1));	spin_unlock_irqrestore(&sscape->lock, flags);	/*	 * We have now enabled the codec chip, and so we should	 * detect the AD1845 device ...	 */	if ((err = create_ad1845(card, CODEC_IO(params->port), params->irq, params->dma1)) < 0) {		printk(KERN_ERR "sscape: No AD1845 device at 0x%x, IRQ %d\n",		                CODEC_IO(params->port), params->irq);		goto _release_card;	}#define MIDI_DEVNUM  0	if ((err = create_mpu401(card, MIDI_DEVNUM, MPU401_IO(params->port), params->mpu_irq)) < 0) {		printk(KERN_ERR "sscape: Failed to create MPU-401 device at 0x%x\n",		                MPU401_IO(params->port));		goto _release_card;	}	/*	 * Enable the master IRQ ...	 */	sscape_write(sscape, GA_INTENA_REG, 0x80);	if ((err = snd_card_register(card)) < 0) {		printk(KERN_ERR "sscape: Failed to register sound card\n");		goto _release_card;	}	/*	 * Initialize mixer	 */	sscape->midi_vol = 0;	host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100);	host_write_ctrl_unsafe(sscape->io_base, 0, 100);	host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100);	/*	 * Now that we have successfully created this sound card,	 * it is safe to store the pointer.	 * NOTE: we only register the sound card's "destructor"	 *       function now that our "constructor" has completed.	 */	card->private_free = soundscape_free;	*rcardp = card;	return 0;	_release_card:	snd_card_free(card);	_release_dma:	free_dma(params->dma1);	_release_region:	release_resource(io_res);	kfree_nocheck(io_res);	return err;}static int sscape_cards __devinitdata;static struct params sscape_params[SNDRV_CARDS] __devinitdata;#ifdef CONFIG_PNPstatic inline int __devinit get_next_autoindex(int i){	while ((i < SNDRV_CARDS) && (port[i] != SNDRV_AUTO_PORT)) {		++i;	} /* while */	return i;}static inline int __devinit is_port_known(unsigned io, struct params *params, int cards){	while (--cards >= 0) {		if (params[cards].port == io)			return 1;	} /* while */	return 0;}static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,				       const struct pnp_card_device_id *pid){	struct pnp_dev *dev;	static int idx = 0;	int ret;	/*	 * Allow this function to fail *quietly* if all the ISA PnP	 * devices were configured using module parameters instead.	 */	if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS) {		return -ENOSPC;	}	/*	 * We have found a candidate ISA PnP card. Now we	 * have to check that it has the devices that we	 * expect it to have.	 *	 * We will NOT try and autoconfigure all of the resources	 * needed and then activate the card as we are assuming that	 * has already been done at boot-time using /proc/isapnp.	 * We shall simply try to give each active card the resources	 * that it wants. This is a sensible strategy for a modular	 * system where unused modules are unloaded regularly.	 *	 * This strategy is utterly useless if we compile the driver	 * into the kernel, of course.	 */	// printk(KERN_INFO "sscape: %s\n", card->name);	/*	 * Check that we still have room for another sound card ...	 */	if (sscape_cards >= SNDRV_CARDS) {		printk(KERN_ERR "sscape: No room for another ALSA device\n");		return -ENOSPC;	}	ret = -ENODEV;	dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);	if (dev) {		struct params *this;		if (!pnp_is_active(dev)) {			if (pnp_activate_dev(dev) < 0) {				printk(KERN_INFO "sscape: device is inactive\n");				return -EBUSY;			}		}		/*		 * Read the correct parameters off the ISA PnP bus ...		 */		this = init_params(&sscape_params[sscape_cards],				   index[idx],				   id[idx],				   pnp_port_start(dev, 0),				   pnp_irq(dev, 0),				   pnp_irq(dev, 1),				   pnp_dma(dev, 0));		/*		 * Do we know about this sound card already?		 */		if ( !is_port_known(this->port, sscape_params, sscape_cards) ) {			snd_card_t *card;			ret = create_sscape(this, &card);			if (ret < 0)				return ret;			snd_card_set_dev(card, &pcard->card->dev);			pnp_set_card_drvdata(pcard, card);			++sscape_cards;			++idx;		}	}	return ret;}static void __devexit sscape_pnp_remove(struct pnp_card_link * pcard){	snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);        	pnp_set_card_drvdata(pcard, NULL);	snd_card_disconnect(card);	snd_card_free_in_thread(card);}static struct pnp_card_driver sscape_pnpc_driver = {	.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,	.name = "sscape",	.id_table = sscape_pnpids,	.probe = sscape_pnp_detect,	.remove = __devexit_p(sscape_pnp_remove),};#endif /* CONFIG_PNP */static int __init sscape_manual_probe(struct params *params){	int ret;	unsigned i;	snd_card_t *card;	for (i = 0; i < SNDRV_CARDS; ++i) {		/*		 * We do NOT probe for ports.		 * If we're not given a port number for this		 * card then we completely ignore this line		 * of parameters.		 */		if (port[i] == SNDRV_AUTO_PORT)			continue;		/*		 * Make sure we were given ALL of the other parameters.		 */		if ( (irq[i] == SNDRV_AUTO_IRQ) ||		     (mpu_irq[i] == SNDRV_AUTO_IRQ) ||		     (dma[i] == SNDRV_AUTO_DMA) ) {			printk(KERN_INFO			       "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n");			return -ENXIO;		}		/*		 * This cards looks OK ...		 */		init_params(params, index[i], id[i], port[i], irq[i], mpu_irq[i], dma[i]);		ret = create_sscape(params, &card);		if (ret < 0)			return ret;		sscape_card[sscape_cards] = card;		params++;		sscape_cards++;	} /* for */	return 0;}static void sscape_exit(void){	unsigned i;#ifdef CONFIG_PNP	pnp_unregister_card_driver(&sscape_pnpc_driver);#endif	for (i = 0; i < ARRAY_SIZE(sscape_card); ++i) {		snd_card_free(sscape_card[i]);	} /* for */}static int __init sscape_init(void){	int ret;	/*	 * First check whether we were passed any parameters.	 * These MUST take precedence over ANY automatic way	 * of allocating cards, because the operator is	 * S-P-E-L-L-I-N-G it out for us...	 */	ret = sscape_manual_probe(sscape_params);	if (ret < 0) {		int i;		for (i = 0; i < sscape_cards; ++i)			snd_card_free(sscape_card[i]);		return ret;	}#ifdef CONFIG_PNP	if (sscape_cards < SNDRV_CARDS) {		ret = pnp_register_card_driver(&sscape_pnpc_driver);		if (ret < 0) {			sscape_exit();			return ret;		}	}#endif	return 0;}module_init(sscape_init);module_exit(sscape_exit);

⌨️ 快捷键说明

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