📄 parport_ip32.c
字号:
/* 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(®s, &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 + -