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

📄 parport_ip32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Negotiate to forward mode if necessary. */	if (physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {		/* Event 47: Set nInit high. */		parport_ip32_frob_control(p, DCR_nINIT | DCR_AUTOFD,					     DCR_nINIT | DCR_AUTOFD);		/* Event 49: PError goes high. */		if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR)) {			printk(KERN_DEBUG PPIP32 "%s: PError timeout in %s",			       p->name, __func__);			physport->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;			return 0;		}	}	/* Reset FIFO, go in forward mode, and disable ackIntEn */	parport_ip32_set_mode(p, ECR_MODE_PS2);	parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);	parport_ip32_data_forward(p);	parport_ip32_disable_irq(p);	parport_ip32_set_mode(p, ECR_MODE_ECP);	physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;	/* Wait for peripheral to become ready */	if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT,				       DSR_nBUSY | DSR_nFAULT)) {		/* Avoid to flood the logs */		if (ready_before)			printk(KERN_INFO PPIP32 "%s: not ready in %s\n",			       p->name, __func__);		ready_before = 0;		goto stop;	}	ready_before = 1;	written = parport_ip32_fifo_write_block(p, buf, len);	/* Wait FIFO to empty.  Timeout is proportional to FIFO_depth.  */	parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth);	/* Check for a potential residue */	written -= parport_ip32_get_fifo_residue(p, ECR_MODE_ECP);	/* Then, wait for BUSY to get low. */	if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY))		printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n",		       p->name, __func__);stop:	/* Reset FIFO */	parport_ip32_set_mode(p, ECR_MODE_PS2);	physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;	return written;}/* * FIXME - Insert here parport_ip32_ecp_write_addr(). *//*--- Default parport operations ---------------------------------------*/static __initdata struct parport_operations parport_ip32_ops = {	.write_data		= parport_ip32_write_data,	.read_data		= parport_ip32_read_data,	.write_control		= parport_ip32_write_control,	.read_control		= parport_ip32_read_control,	.frob_control		= parport_ip32_frob_control,	.read_status		= parport_ip32_read_status,	.enable_irq		= parport_ip32_enable_irq,	.disable_irq		= parport_ip32_disable_irq,	.data_forward		= parport_ip32_data_forward,	.data_reverse		= parport_ip32_data_reverse,	.init_state		= parport_ip32_init_state,	.save_state		= parport_ip32_save_state,	.restore_state		= parport_ip32_restore_state,	.epp_write_data		= parport_ieee1284_epp_write_data,	.epp_read_data		= parport_ieee1284_epp_read_data,	.epp_write_addr		= parport_ieee1284_epp_write_addr,	.epp_read_addr		= parport_ieee1284_epp_read_addr,	.ecp_write_data		= parport_ieee1284_ecp_write_data,	.ecp_read_data		= parport_ieee1284_ecp_read_data,	.ecp_write_addr		= parport_ieee1284_ecp_write_addr,	.compat_write_data	= parport_ieee1284_write_compat,	.nibble_read_data	= parport_ieee1284_read_nibble,	.byte_read_data		= parport_ieee1284_read_byte,	.owner			= THIS_MODULE,};/*--- Device detection -------------------------------------------------*//** * parport_ip32_ecp_supported - check for an ECP port * @p:		pointer to the &parport structure * * Returns 1 if an ECP port is found, and 0 otherwise.  This function actually * checks if an Extended Control Register seems to be present.  On successful * return, the port is placed in SPP mode. */static __init unsigned int parport_ip32_ecp_supported(struct parport *p){	struct parport_ip32_private * const priv = p->physport->private_data;	unsigned int ecr;	ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;	writeb(ecr, priv->regs.ecr);	if (readb(priv->regs.ecr) != (ecr | ECR_F_EMPTY))		goto fail;	pr_probe(p, "Found working ECR register\n");	parport_ip32_set_mode(p, ECR_MODE_SPP);	parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);	return 1;fail:	pr_probe(p, "ECR register not found\n");	return 0;}/** * parport_ip32_fifo_supported - check for FIFO parameters * @p:		pointer to the &parport structure * * Check for FIFO parameters of an Extended Capabilities Port.  Returns 1 on * success, and 0 otherwise.  Adjust FIFO parameters in the parport structure. * On return, the port is placed in SPP mode. */static __init unsigned int parport_ip32_fifo_supported(struct parport *p){	struct parport_ip32_private * const priv = p->physport->private_data;	unsigned int configa, configb;	unsigned int pword;	unsigned int i;	/* Configuration mode */	parport_ip32_set_mode(p, ECR_MODE_CFG);	configa = readb(priv->regs.cnfgA);	configb = readb(priv->regs.cnfgB);	/* Find out PWord size */	switch (configa & CNFGA_ID_MASK) {	case CNFGA_ID_8:		pword = 1;		break;	case CNFGA_ID_16:		pword = 2;		break;	case CNFGA_ID_32:		pword = 4;		break;	default:		pr_probe(p, "Unknown implementation ID: 0x%0x\n",			 (configa & CNFGA_ID_MASK) >> CNFGA_ID_SHIFT);		goto fail;		break;	}	if (pword != 1) {		pr_probe(p, "Unsupported PWord size: %u\n", pword);		goto fail;	}	priv->pword = pword;	pr_probe(p, "PWord is %u bits\n", 8 * priv->pword);	/* Check for compression support */	writeb(configb | CNFGB_COMPRESS, priv->regs.cnfgB);	if (readb(priv->regs.cnfgB) & CNFGB_COMPRESS)		pr_probe(p, "Hardware compression detected (unsupported)\n");	writeb(configb & ~CNFGB_COMPRESS, priv->regs.cnfgB);	/* Reset FIFO and go in test mode (no interrupt, no DMA) */	parport_ip32_set_mode(p, ECR_MODE_TST);	/* FIFO must be empty now */	if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) {		pr_probe(p, "FIFO not reset\n");		goto fail;	}	/* Find out FIFO depth. */	priv->fifo_depth = 0;	for (i = 0; i < 1024; i++) {		if (readb(priv->regs.ecr) & ECR_F_FULL) {			/* FIFO full */			priv->fifo_depth = i;			break;		}		writeb((u8)i, priv->regs.fifo);	}	if (i >= 1024) {		pr_probe(p, "Can't fill FIFO\n");		goto fail;	}	if (!priv->fifo_depth) {		pr_probe(p, "Can't get FIFO depth\n");		goto fail;	}	pr_probe(p, "FIFO is %u PWords deep\n", priv->fifo_depth);	/* Enable interrupts */	parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);	/* Find out writeIntrThreshold: number of PWords we know we can write	 * if we get an interrupt. */	priv->writeIntrThreshold = 0;	for (i = 0; i < priv->fifo_depth; i++) {		if (readb(priv->regs.fifo) != (u8)i) {			pr_probe(p, "Invalid data in FIFO\n");			goto fail;		}		if (!priv->writeIntrThreshold		    && readb(priv->regs.ecr) & ECR_SERVINTR)			/* writeIntrThreshold reached */			priv->writeIntrThreshold = i + 1;		if (i + 1 < priv->fifo_depth		    && readb(priv->regs.ecr) & ECR_F_EMPTY) {			/* FIFO empty before the last byte? */			pr_probe(p, "Data lost in FIFO\n");			goto fail;		}	}	if (!priv->writeIntrThreshold) {		pr_probe(p, "Can't get writeIntrThreshold\n");		goto fail;	}	pr_probe(p, "writeIntrThreshold is %u\n", priv->writeIntrThreshold);	/* FIFO must be empty now */	if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) {		pr_probe(p, "Can't empty FIFO\n");		goto fail;	}	/* Reset FIFO */	parport_ip32_set_mode(p, ECR_MODE_PS2);	/* Set reverse direction (must be in PS2 mode) */	parport_ip32_data_reverse(p);	/* Test FIFO, no interrupt, no DMA */	parport_ip32_set_mode(p, ECR_MODE_TST);	/* Enable interrupts */	parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);	/* Find out readIntrThreshold: number of PWords we can read if we get	 * an interrupt. */	priv->readIntrThreshold = 0;	for (i = 0; i < priv->fifo_depth; i++) {		writeb(0xaa, priv->regs.fifo);		if (readb(priv->regs.ecr) & ECR_SERVINTR) {			/* readIntrThreshold reached */			priv->readIntrThreshold = i + 1;			break;		}	}	if (!priv->readIntrThreshold) {		pr_probe(p, "Can't get readIntrThreshold\n");		goto fail;	}	pr_probe(p, "readIntrThreshold is %u\n", priv->readIntrThreshold);	/* Reset ECR */	parport_ip32_set_mode(p, ECR_MODE_PS2);	parport_ip32_data_forward(p);	parport_ip32_set_mode(p, ECR_MODE_SPP);	return 1;fail:	priv->fifo_depth = 0;	parport_ip32_set_mode(p, ECR_MODE_SPP);	return 0;}/*--- Initialization code ----------------------------------------------*//** * parport_ip32_make_isa_registers - compute (ISA) register addresses * @regs:	pointer to &struct parport_ip32_regs to fill * @base:	base address of standard and EPP registers * @base_hi:	base address of ECP registers * @regshift:	how much to shift register offset by * * Compute register addresses, according to the ISA standard.  The addresses * of the standard and EPP registers are computed from address @base.  The * addresses of the ECP registers are computed from address @base_hi. */static void __initparport_ip32_make_isa_registers(struct parport_ip32_regs *regs,				void __iomem *base, void __iomem *base_hi,				unsigned int regshift){#define r_base(offset)    ((u8 __iomem *)base    + ((offset) << regshift))#define r_base_hi(offset) ((u8 __iomem *)base_hi + ((offset) << regshift))	*regs = (struct parport_ip32_regs){		.data		= r_base(0),		.dsr		= r_base(1),		.dcr		= r_base(2),		.eppAddr	= r_base(3),		.eppData0	= r_base(4),		.eppData1	= r_base(5),		.eppData2	= r_base(6),		.eppData3	= r_base(7),		.ecpAFifo	= r_base(0),		.fifo		= r_base_hi(0),		.cnfgA		= r_base_hi(0),		.cnfgB		= r_base_hi(1),		.ecr		= r_base_hi(2)	};#undef r_base_hi#undef r_base}/** * parport_ip32_probe_port - probe and register IP32 built-in parallel port * * Returns the new allocated &parport structure.  On error, an error code is * encoded in return value with the ERR_PTR function. */static __init struct parport *parport_ip32_probe_port(void){	struct parport_ip32_regs regs;	struct parport_ip32_private *priv = NULL;	struct parport_operations *ops = NULL;	struct parport *p = NULL;	int err;	parport_ip32_make_isa_registers(&regs, &mace->isa.parallel,					&mace->isa.ecp1284, 8 /* regshift */);	ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);	priv = kmalloc(sizeof(struct parport_ip32_private), GFP_KERNEL);	p = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, ops);	if (ops == NULL || priv == NULL || p == NULL) {		err = -ENOMEM;		goto fail;	}	p->base = MACE_BASE + offsetof(struct sgi_mace, isa.parallel);	p->base_hi = MACE_BASE + offsetof(struct sgi_mace, isa.ecp1284);	p->private_data = priv;	*ops = parport_ip32_ops;	*priv = (struct parport_ip32_private){		.regs			= regs,		.dcr_writable		= DCR_DIR | DCR_SELECT | DCR_nINIT |					  DCR_AUTOFD | DCR_STROBE,		.irq_mode		= PARPORT_IP32_IRQ_FWD,	};	init_completion(&priv->irq_complete);	/* Probe port. */	if (!parport_ip32_ecp_supported(p)) {		err = -ENODEV;		goto fail;	}	parport_ip32_dump_state(p, "begin init", 0);	/* We found what looks like a working ECR register.  Simply assume	 * that all modes are correctly supported.  Enable basic modes. */	p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;	p->modes |= PARPORT_MODE_TRISTATE;	if (!parport_ip32_fifo_supported(p)) {		printk(KERN_WARNING PPIP32		       "%s: error: FIFO disabled\n", p->name);		/* Disable hardware modes depending on a working FIFO. */		features &= ~PARPORT_IP32_ENABLE_SPP;		features &= ~PARPORT_IP32_ENABLE_ECP;		/* DMA is not needed if FIFO is not supported.  */		features &= ~PARPORT_IP32_ENABLE_DMA;	}	/* Request IRQ */	if (features & PARPORT_IP32_ENABLE_IRQ) {		int irq = MACEISA_PARALLEL_IRQ;		if (request_irq(irq, parport_ip32_interrupt, 0, p->name, p)) {			printk(KERN_WARNING PPIP32			       "%s: error: IRQ disabled\n", p->name);			/* DMA cannot work without interrupts. */			features &= ~PARPORT_IP32_ENABLE_DMA;		} else {			pr_probe(p, "Interrupt support enabled\n");			p->irq = irq;			priv->dcr_writable |= DCR_IRQ;		}	}	/* Allocate DMA resources */	if (features & PARPORT_IP32_ENABLE_DMA) {		if (parport_ip32_dma_register())			printk(KERN_WARNING PPIP32			       "%s: error: DMA disabled\n", p->name);		else {			pr_probe(p, "DMA support enabled\n");			p->dma = 0; /* arbitrary value != PARPORT_DMA_NONE */			p->modes |= PARPORT_MODE_DMA;		}	}	if (features & PARPORT_IP32_ENABLE_SPP) {		/* Enable compatibility FIFO mode */		p->ops->compat_write_data = parport_ip32_compat_write_data;		p->modes |= PARPORT_MODE_COMPAT;		pr_probe(p, "Hardware support for SPP mode enabled\n");	}	if (features & PARPORT_IP32_ENABLE_EPP) {		/* Set up access functions to use EPP hardware. */		p->ops->epp_read_data = parport_ip32_epp_read_data;		p->ops->epp_write_data = parport_ip32_epp_write_data;		p->ops->epp_read_addr = parport_ip32_epp_read_addr;		p->ops->epp_write_addr = parport_ip32_epp_write_addr;		p->modes |= PARPORT_MODE_EPP;		pr_probe(p, "Hardware support for EPP mode enabled\n");	}	if (features & PARPORT_IP32_ENABLE_ECP) {		/* Enable ECP FIFO mode */		p->ops->ecp_write_data = parport_ip32_ecp_write_data;		/* 

⌨️ 快捷键说明

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