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

📄 pata_bf54x.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 * *	Note: Original code is ata_std_softreset(). */static int bfin_std_softreset(struct ata_link *link, unsigned int *classes,		unsigned long deadline){	struct ata_port *ap = link->ap;	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;	unsigned int devmask = 0, err_mask;	u8 err;	if (ata_link_offline(link)) {		classes[0] = ATA_DEV_NONE;		goto out;	}	/* determine if device 0/1 are present */	if (bfin_devchk(ap, 0))		devmask |= (1 << 0);	if (slave_possible && bfin_devchk(ap, 1))		devmask |= (1 << 1);	/* select device 0 again */	bfin_std_dev_select(ap, 0);	/* issue bus reset */	err_mask = bfin_bus_softreset(ap, devmask);	if (err_mask) {		ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",				err_mask);		return -EIO;	}	/* determine by signature whether we have ATA or ATAPI devices */	classes[0] = ata_dev_try_classify(&ap->link.device[0],				devmask & (1 << 0), &err);	if (slave_possible && err != 0x81)		classes[1] = ata_dev_try_classify(&ap->link.device[1],					devmask & (1 << 1), &err); out:	return 0;}/** *	bfin_bmdma_status - Read IDE DMA status *	@ap: Port associated with this ATA transaction. */static unsigned char bfin_bmdma_status(struct ata_port *ap){	unsigned char host_stat = 0;	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	unsigned short int_status = ATAPI_GET_INT_STATUS(base);	if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {		host_stat |= ATA_DMA_ACTIVE;	}	if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {		host_stat |= ATA_DMA_INTR;	}	if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {		host_stat |= ATA_DMA_ERR;	}	return host_stat;}/** *	bfin_data_xfer - Transfer data by PIO *	@adev: device for this I/O *	@buf: data buffer *	@buflen: buffer length *	@write_data: read/write * *	Note: Original code is ata_data_xfer(). */static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,			   unsigned int buflen, int write_data){	struct ata_port *ap = adev->link->ap;	unsigned int words = buflen >> 1;	unsigned short *buf16 = (u16 *) buf;	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	/* Transfer multiple of 2 bytes */	if (write_data) {		write_atapi_data(base, words, buf16);	} else {		read_atapi_data(base, words, buf16);	}	/* Transfer trailing 1 byte, if any. */	if (unlikely(buflen & 0x01)) {		unsigned short align_buf[1] = { 0 };		unsigned char *trailing_buf = buf + buflen - 1;		if (write_data) {			memcpy(align_buf, trailing_buf, 1);			write_atapi_data(base, 1, align_buf);		} else {			read_atapi_data(base, 1, align_buf);			memcpy(trailing_buf, align_buf, 1);		}	}}/** *	bfin_irq_clear - Clear ATAPI interrupt. *	@ap: Port associated with this ATA transaction. * *	Note: Original code is ata_bmdma_irq_clear(). */static void bfin_irq_clear(struct ata_port *ap){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	pr_debug("in atapi irq clear\n");	ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT		| MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT		| MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);}/** *	bfin_irq_on - Enable interrupts on a port. *	@ap: Port on which interrupts are enabled. * *	Note: Original code is ata_irq_on(). */static unsigned char bfin_irq_on(struct ata_port *ap){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	u8 tmp;	pr_debug("in atapi irq on\n");	ap->ctl &= ~ATA_NIEN;	ap->last_ctl = ap->ctl;	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);	tmp = ata_wait_idle(ap);	bfin_irq_clear(ap);	return tmp;}/** *	bfin_bmdma_freeze - Freeze DMA controller port *	@ap: port to freeze * *	Note: Original code is ata_bmdma_freeze(). */static void bfin_bmdma_freeze(struct ata_port *ap){	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	pr_debug("in atapi dma freeze\n");	ap->ctl |= ATA_NIEN;	ap->last_ctl = ap->ctl;	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);	/* Under certain circumstances, some controllers raise IRQ on	 * ATA_NIEN manipulation.  Also, many controllers fail to mask	 * previously pending IRQ on ATA_NIEN assertion.  Clear it.	 */	ata_chk_status(ap);	bfin_irq_clear(ap);}/** *	bfin_bmdma_thaw - Thaw DMA controller port *	@ap: port to thaw * *	Note: Original code is ata_bmdma_thaw(). */void bfin_bmdma_thaw(struct ata_port *ap){	bfin_check_status(ap);	bfin_irq_clear(ap);	bfin_irq_on(ap);}/** *	bfin_std_postreset - standard postreset callback *	@ap: the target ata_port *	@classes: classes of attached devices * *	Note: Original code is ata_std_postreset(). */static void bfin_std_postreset(struct ata_link *link, unsigned int *classes){	struct ata_port *ap = link->ap;	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;	/* re-enable interrupts */	bfin_irq_on(ap);	/* is double-select really necessary? */	if (classes[0] != ATA_DEV_NONE)		bfin_std_dev_select(ap, 1);	if (classes[1] != ATA_DEV_NONE)		bfin_std_dev_select(ap, 0);	/* bail out if no device is present */	if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {		return;	}	/* set up device control */	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);}/** *	bfin_error_handler - Stock error handler for DMA controller *	@ap: port to handle error for */static void bfin_error_handler(struct ata_port *ap){	ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL,			   bfin_std_postreset);}static void bfin_port_stop(struct ata_port *ap){	pr_debug("in atapi port stop\n");	if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {		free_dma(CH_ATAPI_RX);		free_dma(CH_ATAPI_TX);	}}static int bfin_port_start(struct ata_port *ap){	pr_debug("in atapi port start\n");	if (!(ap->udma_mask || ap->mwdma_mask))		return 0;	if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {		if (request_dma(CH_ATAPI_TX,			"BFIN ATAPI TX DMA") >= 0)			return 0;		free_dma(CH_ATAPI_RX);	}	ap->udma_mask = 0;	ap->mwdma_mask = 0;	dev_err(ap->dev, "Unable to request ATAPI DMA!"		" Continue in PIO mode.\n");	return 0;}static struct scsi_host_template bfin_sht = {	.module			= THIS_MODULE,	.name			= DRV_NAME,	.ioctl			= ata_scsi_ioctl,	.queuecommand		= ata_scsi_queuecmd,	.can_queue		= ATA_DEF_QUEUE,	.this_id		= ATA_SHT_THIS_ID,	.sg_tablesize		= SG_NONE,	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,	.emulated		= ATA_SHT_EMULATED,	.use_clustering		= ATA_SHT_USE_CLUSTERING,	.proc_name		= DRV_NAME,	.dma_boundary		= ATA_DMA_BOUNDARY,	.slave_configure	= ata_scsi_slave_config,	.slave_destroy		= ata_scsi_slave_destroy,	.bios_param		= ata_std_bios_param,#ifdef CONFIG_PM	.resume			= ata_scsi_device_resume,	.suspend		= ata_scsi_device_suspend,#endif};static const struct ata_port_operations bfin_pata_ops = {	.set_piomode		= bfin_set_piomode,	.set_dmamode		= bfin_set_dmamode,	.tf_load		= bfin_tf_load,	.tf_read		= bfin_tf_read,	.exec_command		= bfin_exec_command,	.check_status		= bfin_check_status,	.check_altstatus	= bfin_check_altstatus,	.dev_select		= bfin_std_dev_select,	.bmdma_setup		= bfin_bmdma_setup,	.bmdma_start		= bfin_bmdma_start,	.bmdma_stop		= bfin_bmdma_stop,	.bmdma_status		= bfin_bmdma_status,	.data_xfer		= bfin_data_xfer,	.qc_prep		= ata_noop_qc_prep,	.qc_issue		= ata_qc_issue_prot,	.freeze			= bfin_bmdma_freeze,	.thaw			= bfin_bmdma_thaw,	.error_handler		= bfin_error_handler,	.post_internal_cmd	= bfin_bmdma_stop,	.irq_handler		= ata_interrupt,	.irq_clear		= bfin_irq_clear,	.irq_on			= bfin_irq_on,	.port_start		= bfin_port_start,	.port_stop		= bfin_port_stop,};static struct ata_port_info bfin_port_info[] = {	{		.sht		= &bfin_sht,		.flags		= ATA_FLAG_SLAVE_POSS				| ATA_FLAG_MMIO				| ATA_FLAG_NO_LEGACY,		.pio_mask	= 0x1f,	/* pio0-4 */		.mwdma_mask	= 0,		.udma_mask	= 0,		.port_ops	= &bfin_pata_ops,	},};/** *	bfin_reset_controller - initialize BF54x ATAPI controller. */static int bfin_reset_controller(struct ata_host *host){	void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr;	int count;	unsigned short status;	/* Disable all ATAPI interrupts */	ATAPI_SET_INT_MASK(base, 0);	SSYNC();	/* Assert the RESET signal 25us*/	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST);	udelay(30);	/* Negate the RESET signal for 2ms*/	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST);	msleep(2);	/* Wait on Busy flag to clear */	count = 10000000;	do {		status = read_atapi_register(base, ATA_REG_STATUS);	} while (count-- && (status & ATA_BUSY));	/* Enable only ATAPI Device interrupt */	ATAPI_SET_INT_MASK(base, 1);	SSYNC();	return (!count);}/** *	atapi_io_port - define atapi peripheral port pins. */static unsigned short atapi_io_port[] = {	P_ATAPI_RESET,	P_ATAPI_DIOR,	P_ATAPI_DIOW,	P_ATAPI_CS0,	P_ATAPI_CS1,	P_ATAPI_DMACK,	P_ATAPI_DMARQ,	P_ATAPI_INTRQ,	P_ATAPI_IORDY,	0};/** *	bfin_atapi_probe	-	attach a bfin atapi interface *	@pdev: platform device * *	Register a bfin atapi interface. * * *	Platform devices are expected to contain 2 resources per port: * *		- I/O Base (IORESOURCE_IO) *		- IRQ	   (IORESOURCE_IRQ) * */static int __devinit bfin_atapi_probe(struct platform_device *pdev){	int board_idx = 0;	struct resource *res;	struct ata_host *host;	unsigned int fsclk = get_sclk();	int udma_mode = 5;	const struct ata_port_info *ppi[] =		{ &bfin_port_info[board_idx], NULL };	/*	 * Simple resource validation ..	 */	if (unlikely(pdev->num_resources != 2)) {		dev_err(&pdev->dev, "invalid number of resources\n");		return -EINVAL;	}	/*	 * Get the register base first	 */	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (res == NULL)		return -EINVAL;	while (bfin_port_info[board_idx].udma_mask > 0 &&			udma_fsclk[udma_mode] > fsclk) {		udma_mode--;		bfin_port_info[board_idx].udma_mask >>= 1;	}	/*	 * Now that that's out of the way, wire up the port..	 */	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);	if (!host)		return -ENOMEM;	host->ports[0]->ioaddr.ctl_addr = (void *)res->start;	if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {		dev_err(&pdev->dev, "Requesting Peripherals faild\n");		return -EFAULT;	}	if (bfin_reset_controller(host)) {		peripheral_free_list(atapi_io_port);		dev_err(&pdev->dev, "Fail to reset ATAPI device\n");		return -EFAULT;	}	if (ata_host_activate(host, platform_get_irq(pdev, 0),		ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {		peripheral_free_list(atapi_io_port);		dev_err(&pdev->dev, "Fail to attach ATAPI device\n");		return -ENODEV;	}	return 0;}/** *	bfin_atapi_remove	-	unplug a bfin atapi interface *	@pdev: platform device * *	A bfin atapi device has been unplugged. Perform the needed *	cleanup. Also called on module unload for any active devices. */static int __devexit bfin_atapi_remove(struct platform_device *pdev){	struct device *dev = &pdev->dev;	struct ata_host *host = dev_get_drvdata(dev);	ata_host_detach(host);	peripheral_free_list(atapi_io_port);	return 0;}#ifdef CONFIG_PMint bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state){	return 0;}int bfin_atapi_resume(struct platform_device *pdev){	return 0;}#endifstatic struct platform_driver bfin_atapi_driver = {	.probe			= bfin_atapi_probe,	.remove			= __devexit_p(bfin_atapi_remove),	.driver = {		.name		= DRV_NAME,		.owner		= THIS_MODULE,#ifdef CONFIG_PM		.suspend	= bfin_atapi_suspend,		.resume		= bfin_atapi_resume,#endif	},};#define ATAPI_MODE_SIZE		10static char bfin_atapi_mode[ATAPI_MODE_SIZE];static int __init bfin_atapi_init(void){	pr_info("register bfin atapi driver\n");	switch(bfin_atapi_mode[0]) {	case 'p':	case 'P':		break;	case 'm':	case 'M':		bfin_port_info[0].mwdma_mask = ATA_MWDMA2;		break;	default:		bfin_port_info[0].udma_mask = ATA_UDMA5;	};	return platform_driver_register(&bfin_atapi_driver);}static void __exit bfin_atapi_exit(void){	platform_driver_unregister(&bfin_atapi_driver);}module_init(bfin_atapi_init);module_exit(bfin_atapi_exit);/* * ATAPI mode: * pio/PIO * udma/UDMA (default) * mwdma/MWDMA */module_param_string(bfin_atapi_mode, bfin_atapi_mode, ATAPI_MODE_SIZE, 0);MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);

⌨️ 快捷键说明

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