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

📄 sscape.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	int err;	if (sscape->type == SSCAPE_VIVO)		port += 4;	if (dma1 == dma2)		dma2 = -1;	err = snd_cs4231_create(card,				port, -1, irq, dma1, dma2,				CS4231_HW_DETECT, CS4231_HWSHARE_DMA1, &chip);	if (!err) {		unsigned long flags;		struct snd_pcm *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); */		if (sscape->type != SSCAPE_VIVO) {			int val;			/*			 * 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 8mA			 * b) enable frequency selection (for capture/playback)			 */			spin_lock_irqsave(&chip->reg_lock, flags);			snd_cs4231_out(chip, CS4231_MISC_INFO,					CS4231_MODE2 | 0x10);			val = snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL);			snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL,					val | AD1845_FREQ_SEL_ENABLE);			spin_unlock_irqrestore(&chip->reg_lock, flags);		}		err = snd_cs4231_pcm(chip, 0, &pcm);		if (err < 0) {			snd_printk(KERN_ERR "sscape: No PCM device "					    "for AD1845 chip\n");			goto _error;		}		err = snd_cs4231_mixer(chip);		if (err < 0) {			snd_printk(KERN_ERR "sscape: No mixer device "					    "for AD1845 chip\n");			goto _error;		}		err = snd_cs4231_timer(chip, 0, NULL);		if (err < 0) {			snd_printk(KERN_ERR "sscape: No timer device "					    "for AD1845 chip\n");			goto _error;		}		if (sscape->type != SSCAPE_VIVO) {			err = snd_ctl_add(card,					  snd_ctl_new1(&midi_mixer_ctl, chip));			if (err < 0) {				snd_printk(KERN_ERR "sscape: Could not create "						    "MIDI mixer control\n");				goto _error;			}			chip->set_playback_format = ad1845_playback_format;			chip->set_capture_format = ad1845_capture_format;		}		strcpy(card->driver, "SoundScape");		strcpy(card->shortname, pcm->name);		snprintf(card->longname, sizeof(card->longname),			 "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",			 pcm->name, chip->port, chip->irq,			 chip->dma1, chip->dma2);		sscape->chip = chip;	}	_error:	return err;}/* * Create an ALSA soundcard entry for the SoundScape, using * the given list of port, IRQ and DMA resources. */static int __devinit create_sscape(int dev, struct snd_card *card){	struct soundscape *sscape = get_card_soundscape(card);	unsigned dma_cfg;	unsigned irq_cfg;	unsigned mpu_irq_cfg;	unsigned xport;	struct resource *io_res;	struct resource *wss_res;	unsigned long flags;	int err;	/*	 * Check that the user didn't pass us garbage data ...	 */	irq_cfg = get_irq_config(irq[dev]);	if (irq_cfg == INVALID_IRQ) {		snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);		return -ENXIO;	}	mpu_irq_cfg = get_irq_config(mpu_irq[dev]);	if (mpu_irq_cfg == INVALID_IRQ) {		printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);		return -ENXIO;	}	xport = port[dev];	/*	 * Grab IO ports that we will need to probe so that we	 * can detect and control this hardware ...	 */	io_res = request_region(xport, 8, "SoundScape");	if (!io_res) {		snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport);		return -EBUSY;	}	wss_res = NULL;	if (sscape->type == SSCAPE_VIVO) {		wss_res = request_region(wss_port[dev], 4, "SoundScape");		if (!wss_res) {			snd_printk(KERN_ERR "sscape: can't grab port 0x%lx\n",					    wss_port[dev]);			err = -EBUSY;			goto _release_region;		}	}	/*	 * Grab one DMA channel ...	 */	err = request_dma(dma[dev], "SoundScape");	if (err < 0) {		snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", dma[dev]);		goto _release_region;	}	spin_lock_init(&sscape->lock);	spin_lock_init(&sscape->fwlock);	sscape->io_res = io_res;	sscape->wss_res = wss_res;	sscape->io_base = xport;	sscape->wss_base = wss_port[dev];	if (!detect_sscape(sscape)) {		printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);		err = -ENODEV;		goto _release_dma;	}	printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n",			 sscape->io_base, irq[dev], dma[dev]);	if (sscape->type != SSCAPE_VIVO) {		/*		 * 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.		 */		err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw));		if (err < 0) {			printk(KERN_ERR "sscape: Failed to create "					"firmware device\n");			goto _release_dma;		}		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			    | (dma[dev] << 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 ...	 */	err = create_ad1845(card, wss_port[dev], irq[dev],			    dma[dev], dma2[dev]);	if (err < 0) {		printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d\n",		       wss_port[dev], irq[dev]);		goto _release_dma;	}#define MIDI_DEVNUM  0	if (sscape->type != SSCAPE_VIVO) {		err = create_mpu401(card, MIDI_DEVNUM,				    MPU401_IO(xport), mpu_irq[dev]);		if (err < 0) {			printk(KERN_ERR "sscape: Failed to create "					"MPU-401 device at 0x%x\n",					MPU401_IO(xport));			goto _release_dma;		}		/*		 * Enable the master IRQ ...		 */		sscape_write(sscape, GA_INTENA_REG, 0x80);		/*		 * 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;	return 0;_release_dma:	free_dma(dma[dev]);_release_region:	release_and_free_resource(wss_res);	release_and_free_resource(io_res);	return err;}static int __devinit snd_sscape_match(struct device *pdev, unsigned int i){	/*	 * Make sure we were given ALL of the other parameters.	 */	if (port[i] == SNDRV_AUTO_PORT)		return 0;	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 0;	}	return 1;}static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev){	struct snd_card *card;	struct soundscape *sscape;	int ret;	card = snd_card_new(index[dev], id[dev], THIS_MODULE,			    sizeof(struct soundscape));	if (!card)		return -ENOMEM;	sscape = get_card_soundscape(card);	sscape->type = SSCAPE;	dma[dev] &= 0x03;	ret = create_sscape(dev, card);	if (ret < 0)		goto _release_card;	snd_card_set_dev(card, pdev);	if ((ret = snd_card_register(card)) < 0) {		printk(KERN_ERR "sscape: Failed to register sound card\n");		goto _release_card;	}	dev_set_drvdata(pdev, card);	return 0;_release_card:	snd_card_free(card);	return ret;}static int __devexit snd_sscape_remove(struct device *devptr, unsigned int dev){	snd_card_free(dev_get_drvdata(devptr));	dev_set_drvdata(devptr, NULL);	return 0;}#define DEV_NAME "sscape"static struct isa_driver snd_sscape_driver = {	.match		= snd_sscape_match,	.probe		= snd_sscape_probe,	.remove		= __devexit_p(snd_sscape_remove),	/* FIXME: suspend/resume */	.driver		= {		.name	= DEV_NAME	},};#ifdef CONFIG_PNPstatic inline int __devinit get_next_autoindex(int i){	while (i < SNDRV_CARDS && port[i] != SNDRV_AUTO_PORT)		++i;	return i;}static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,				       const struct pnp_card_device_id *pid){	static int idx = 0;	struct pnp_dev *dev;	struct snd_card *card;	struct soundscape *sscape;	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 ...	 */	dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);	if (! dev)		return -ENODEV;	if (!pnp_is_active(dev)) {		if (pnp_activate_dev(dev) < 0) {			printk(KERN_INFO "sscape: device is inactive\n");			return -EBUSY;		}	}	/*	 * Create a new ALSA sound card entry, in anticipation	 * of detecting our hardware ...	 */	card = snd_card_new(index[idx], id[idx], THIS_MODULE,			    sizeof(struct soundscape));	if (!card)		return -ENOMEM;	sscape = get_card_soundscape(card);	/*	 * Identify card model ...	 */	if (!strncmp("ENS4081", pid->id, 7))		sscape->type = SSCAPE_VIVO;	else		sscape->type = SSCAPE_PNP;	/*	 * Read the correct parameters off the ISA PnP bus ...	 */	port[idx] = pnp_port_start(dev, 0);	irq[idx] = pnp_irq(dev, 0);	mpu_irq[idx] = pnp_irq(dev, 1);	dma[idx] = pnp_dma(dev, 0) & 0x03;	if (sscape->type == SSCAPE_PNP) {		dma2[idx] = dma[idx];		wss_port[idx] = CODEC_IO(port[idx]);	} else {		wss_port[idx] = pnp_port_start(dev, 1);		dma2[idx] = pnp_dma(dev, 1);	}	ret = create_sscape(idx, card);	if (ret < 0)		goto _release_card;	snd_card_set_dev(card, &pcard->card->dev);	if ((ret = snd_card_register(card)) < 0) {		printk(KERN_ERR "sscape: Failed to register sound card\n");		goto _release_card;	}	pnp_set_card_drvdata(pcard, card);	++idx;	return 0;_release_card:	snd_card_free(card);	return ret;}static void __devexit sscape_pnp_remove(struct pnp_card_link * pcard){	snd_card_free(pnp_get_card_drvdata(pcard));	pnp_set_card_drvdata(pcard, NULL);}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_init(void){	int err;	err = isa_register_driver(&snd_sscape_driver, SNDRV_CARDS);#ifdef CONFIG_PNP	if (!err)		isa_registered = 1;	err = pnp_register_card_driver(&sscape_pnpc_driver);	if (!err)		pnp_registered = 1;	if (isa_registered)		err = 0;#endif	return err;}static void __exit sscape_exit(void){#ifdef CONFIG_PNP	if (pnp_registered)		pnp_unregister_card_driver(&sscape_pnpc_driver);	if (isa_registered)#endif		isa_unregister_driver(&snd_sscape_driver);}module_init(sscape_init);module_exit(sscape_exit);

⌨️ 快捷键说明

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