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

📄 wbsd.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	return -ENODEV;}/* * Allocate/free io port ranges */static int __devinit wbsd_request_region(struct wbsd_host *host, int base){	if (base & 0x7)		return -EINVAL;	if (!request_region(base, 8, DRIVER_NAME))		return -EIO;	host->base = base;	return 0;}static void __devexit wbsd_release_regions(struct wbsd_host *host){	if (host->base)		release_region(host->base, 8);	host->base = 0;	if (host->config)		release_region(host->config, 2);	host->config = 0;}/* * Allocate/free DMA port and buffer */static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma){	if (dma < 0)		return;	if (request_dma(dma, DRIVER_NAME))		goto err;	/*	 * We need to allocate a special buffer in	 * order for ISA to be able to DMA to it.	 */	host->dma_buffer = kmalloc(WBSD_DMA_SIZE,		GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);	if (!host->dma_buffer)		goto free;	/*	 * Translate the address to a physical address.	 */	host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer,		WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);	/*	 * ISA DMA must be aligned on a 64k basis.	 */	if ((host->dma_addr & 0xffff) != 0)		goto kfree;	/*	 * ISA cannot access memory above 16 MB.	 */	else if (host->dma_addr >= 0x1000000)		goto kfree;	host->dma = dma;	return;kfree:	/*	 * If we've gotten here then there is some kind of alignment bug	 */	BUG_ON(1);	dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,		WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);	host->dma_addr = (dma_addr_t)NULL;	kfree(host->dma_buffer);	host->dma_buffer = NULL;free:	free_dma(dma);err:	printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. "		"Falling back on FIFO.\n", dma);}static void __devexit wbsd_release_dma(struct wbsd_host *host){	if (host->dma_addr) {		dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,			WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);	}	kfree(host->dma_buffer);	if (host->dma >= 0)		free_dma(host->dma);	host->dma = -1;	host->dma_buffer = NULL;	host->dma_addr = (dma_addr_t)NULL;}/* * Allocate/free IRQ. */static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq){	int ret;	/*	 * Allocate interrupt.	 */	ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);	if (ret)		return ret;	host->irq = irq;	/*	 * Set up tasklets.	 */	tasklet_init(&host->card_tasklet, wbsd_tasklet_card,			(unsigned long)host);	tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo,			(unsigned long)host);	tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc,			(unsigned long)host);	tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout,			(unsigned long)host);	tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,			(unsigned long)host);	tasklet_init(&host->block_tasklet, wbsd_tasklet_block,			(unsigned long)host);	return 0;}static void __devexit wbsd_release_irq(struct wbsd_host *host){	if (!host->irq)		return;	free_irq(host->irq, host);	host->irq = 0;	tasklet_kill(&host->card_tasklet);	tasklet_kill(&host->fifo_tasklet);	tasklet_kill(&host->crc_tasklet);	tasklet_kill(&host->timeout_tasklet);	tasklet_kill(&host->finish_tasklet);	tasklet_kill(&host->block_tasklet);}/* * Allocate all resources for the host. */static int __devinit wbsd_request_resources(struct wbsd_host *host,	int base, int irq, int dma){	int ret;	/*	 * Allocate I/O ports.	 */	ret = wbsd_request_region(host, base);	if (ret)		return ret;	/*	 * Allocate interrupt.	 */	ret = wbsd_request_irq(host, irq);	if (ret)		return ret;	/*	 * Allocate DMA.	 */	wbsd_request_dma(host, dma);	return 0;}/* * Release all resources for the host. */static void __devexit wbsd_release_resources(struct wbsd_host *host){	wbsd_release_dma(host);	wbsd_release_irq(host);	wbsd_release_regions(host);}/* * Configure the resources the chip should use. */static void wbsd_chip_config(struct wbsd_host *host){	wbsd_unlock_config(host);	/*	 * Reset the chip.	 */	wbsd_write_config(host, WBSD_CONF_SWRST, 1);	wbsd_write_config(host, WBSD_CONF_SWRST, 0);	/*	 * Select SD/MMC function.	 */	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);	/*	 * Set up card detection.	 */	wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);	/*	 * Configure chip	 */	wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);	wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);	wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);	if (host->dma >= 0)		wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);	/*	 * Enable and power up chip.	 */	wbsd_write_config(host, WBSD_CONF_ENABLE, 1);	wbsd_write_config(host, WBSD_CONF_POWER, 0x20);	wbsd_lock_config(host);}/* * Check that configured resources are correct. */static int wbsd_chip_validate(struct wbsd_host *host){	int base, irq, dma;	wbsd_unlock_config(host);	/*	 * Select SD/MMC function.	 */	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);	/*	 * Read configuration.	 */	base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;	base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);	irq = wbsd_read_config(host, WBSD_CONF_IRQ);	dma = wbsd_read_config(host, WBSD_CONF_DRQ);	wbsd_lock_config(host);	/*	 * Validate against given configuration.	 */	if (base != host->base)		return 0;	if (irq != host->irq)		return 0;	if ((dma != host->dma) && (host->dma != -1))		return 0;	return 1;}/* * Powers down the SD function */static void wbsd_chip_poweroff(struct wbsd_host *host){	wbsd_unlock_config(host);	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);	wbsd_write_config(host, WBSD_CONF_ENABLE, 0);	wbsd_lock_config(host);}/*****************************************************************************\ *                                                                           * * Devices setup and shutdown                                                * *                                                                           *\*****************************************************************************/static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma,	int pnp){	struct wbsd_host *host = NULL;	struct mmc_host *mmc = NULL;	int ret;	ret = wbsd_alloc_mmc(dev);	if (ret)		return ret;	mmc = dev_get_drvdata(dev);	host = mmc_priv(mmc);	/*	 * Scan for hardware.	 */	ret = wbsd_scan(host);	if (ret) {		if (pnp && (ret == -ENODEV)) {			printk(KERN_WARNING DRIVER_NAME				": Unable to confirm device presence. You may "				"experience lock-ups.\n");		} else {			wbsd_free_mmc(dev);			return ret;		}	}	/*	 * Request resources.	 */	ret = wbsd_request_resources(host, base, irq, dma);	if (ret) {		wbsd_release_resources(host);		wbsd_free_mmc(dev);		return ret;	}	/*	 * See if chip needs to be configured.	 */	if (pnp) {		if ((host->config != 0) && !wbsd_chip_validate(host)) {			printk(KERN_WARNING DRIVER_NAME				": PnP active but chip not configured! "				"You probably have a buggy BIOS. "				"Configuring chip manually.\n");			wbsd_chip_config(host);		}	} else		wbsd_chip_config(host);	/*	 * Power Management stuff. No idea how this works.	 * Not tested.	 */#ifdef CONFIG_PM	if (host->config) {		wbsd_unlock_config(host);		wbsd_write_config(host, WBSD_CONF_PME, 0xA0);		wbsd_lock_config(host);	}#endif	/*	 * Allow device to initialise itself properly.	 */	mdelay(5);	/*	 * Reset the chip into a known state.	 */	wbsd_init_device(host);	mmc_add_host(mmc);	printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));	if (host->chip_id != 0)		printk(" id %x", (int)host->chip_id);	printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);	if (host->dma >= 0)		printk(" dma %d", (int)host->dma);	else		printk(" FIFO");	if (pnp)		printk(" PnP");	printk("\n");	return 0;}static void __devexit wbsd_shutdown(struct device *dev, int pnp){	struct mmc_host *mmc = dev_get_drvdata(dev);	struct wbsd_host *host;	if (!mmc)		return;	host = mmc_priv(mmc);	mmc_remove_host(mmc);	/*	 * Power down the SD/MMC function.	 */	if (!pnp)		wbsd_chip_poweroff(host);	wbsd_release_resources(host);	wbsd_free_mmc(dev);}/* * Non-PnP */static int __devinit wbsd_probe(struct platform_device *dev){	/* Use the module parameters for resources */	return wbsd_init(&dev->dev, io, irq, dma, 0);}static int __devexit wbsd_remove(struct platform_device *dev){	wbsd_shutdown(&dev->dev, 0);	return 0;}/* * PnP */#ifdef CONFIG_PNPstatic int __devinitwbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id){	int io, irq, dma;	/*	 * Get resources from PnP layer.	 */	io = pnp_port_start(pnpdev, 0);	irq = pnp_irq(pnpdev, 0);	if (pnp_dma_valid(pnpdev, 0))		dma = pnp_dma(pnpdev, 0);	else		dma = -1;	DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);	return wbsd_init(&pnpdev->dev, io, irq, dma, 1);}static void __devexit wbsd_pnp_remove(struct pnp_dev *dev){	wbsd_shutdown(&dev->dev, 1);}#endif /* CONFIG_PNP *//* * Power management */#ifdef CONFIG_PMstatic int wbsd_suspend(struct wbsd_host *host, pm_message_t state){	BUG_ON(host == NULL);	return mmc_suspend_host(host->mmc, state);}static int wbsd_resume(struct wbsd_host *host){	BUG_ON(host == NULL);	wbsd_init_device(host);	return mmc_resume_host(host->mmc);}static int wbsd_platform_suspend(struct platform_device *dev,				 pm_message_t state){	struct mmc_host *mmc = platform_get_drvdata(dev);	struct wbsd_host *host;	int ret;	if (mmc == NULL)		return 0;	DBGF("Suspending...\n");	host = mmc_priv(mmc);	ret = wbsd_suspend(host, state);	if (ret)		return ret;	wbsd_chip_poweroff(host);	return 0;}static int wbsd_platform_resume(struct platform_device *dev){	struct mmc_host *mmc = platform_get_drvdata(dev);	struct wbsd_host *host;	if (mmc == NULL)		return 0;	DBGF("Resuming...\n");	host = mmc_priv(mmc);	wbsd_chip_config(host);	/*	 * Allow device to initialise itself properly.	 */	mdelay(5);	return wbsd_resume(host);}#ifdef CONFIG_PNPstatic int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state){	struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);	struct wbsd_host *host;	if (mmc == NULL)		return 0;	DBGF("Suspending...\n");	host = mmc_priv(mmc);	return wbsd_suspend(host, state);}static int wbsd_pnp_resume(struct pnp_dev *pnp_dev){	struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);	struct wbsd_host *host;	if (mmc == NULL)		return 0;	DBGF("Resuming...\n");	host = mmc_priv(mmc);	/*	 * See if chip needs to be configured.	 */	if (host->config != 0) {		if (!wbsd_chip_validate(host)) {			printk(KERN_WARNING DRIVER_NAME				": PnP active but chip not configured! "				"You probably have a buggy BIOS. "				"Configuring chip manually.\n");			wbsd_chip_config(host);		}	}	/*	 * Allow device to initialise itself properly.	 */	mdelay(5);	return wbsd_resume(host);}#endif /* CONFIG_PNP */#else /* CONFIG_PM */#define wbsd_platform_suspend NULL#define wbsd_platform_resume NULL#define wbsd_pnp_suspend NULL#define wbsd_pnp_resume NULL#endif /* CONFIG_PM */static struct platform_device *wbsd_device;static struct platform_driver wbsd_driver = {	.probe		= wbsd_probe,	.remove		= __devexit_p(wbsd_remove),	.suspend	= wbsd_platform_suspend,	.resume		= wbsd_platform_resume,	.driver		= {		.name	= DRIVER_NAME,	},};#ifdef CONFIG_PNPstatic struct pnp_driver wbsd_pnp_driver = {	.name		= DRIVER_NAME,	.id_table	= pnp_dev_table,	.probe		= wbsd_pnp_probe,	.remove		= __devexit_p(wbsd_pnp_remove),	.suspend	= wbsd_pnp_suspend,	.resume		= wbsd_pnp_resume,};#endif /* CONFIG_PNP *//* * Module loading/unloading */static int __init wbsd_drv_init(void){	int result;	printk(KERN_INFO DRIVER_NAME		": Winbond W83L51xD SD/MMC card interface driver, "		DRIVER_VERSION "\n");	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");#ifdef CONFIG_PNP	if (!nopnp) {		result = pnp_register_driver(&wbsd_pnp_driver);		if (result < 0)			return result;	}#endif /* CONFIG_PNP */	if (nopnp) {		result = platform_driver_register(&wbsd_driver);		if (result < 0)			return result;		wbsd_device = platform_device_alloc(DRIVER_NAME, -1);		if (!wbsd_device) {			platform_driver_unregister(&wbsd_driver);			return -ENOMEM;		}		result = platform_device_add(wbsd_device);		if (result) {			platform_device_put(wbsd_device);			platform_driver_unregister(&wbsd_driver);			return result;		}	}	return 0;}static void __exit wbsd_drv_exit(void){#ifdef CONFIG_PNP	if (!nopnp)		pnp_unregister_driver(&wbsd_pnp_driver);#endif /* CONFIG_PNP */	if (nopnp) {		platform_device_unregister(wbsd_device);		platform_driver_unregister(&wbsd_driver);	}	DBG("unloaded\n");}module_init(wbsd_drv_init);module_exit(wbsd_drv_exit);#ifdef CONFIG_PNPmodule_param(nopnp, uint, 0444);#endifmodule_param(io, uint, 0444);module_param(irq, uint, 0444);module_param(dma, int, 0444);MODULE_LICENSE("GPL");MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");MODULE_VERSION(DRIVER_VERSION);#ifdef CONFIG_PNPMODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");#endifMODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");

⌨️ 快捷键说明

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