📄 parport_pc.c
字号:
frob_econtrol (p, 0xe0, ECR_CNF << 5); dma = inb (CONFIGB(p)) & 0x07; /* 000: Indicates jumpered 8-bit DMA if read-only. 100: Indicates jumpered 16-bit DMA if read-only. */ if ((dma & 0x03) == 0) dma = PARPORT_DMA_NONE; outb (oecr, ECONTROL (p)); return dma;}static int __devinit parport_dma_probe (struct parport *p){ const struct parport_pc_private *priv = p->private_data; if (priv->ecr) p->dma = programmable_dma_support(p); /* ask ECP chipset first */ if (p->dma == PARPORT_DMA_NONE) /* ask known Super-IO chips proper, although these claim ECP compatible, some don't report their DMA conforming to ECP standards */ p->dma = get_superio_dma(p); return p->dma;}/* --- Initialisation code -------------------------------- */struct parport *__devinit parport_pc_probe_port (unsigned long int base, unsigned long int base_hi, int irq, int dma, struct pci_dev *dev){ struct parport_pc_private *priv; struct parport_operations *ops; struct parport tmp; struct parport *p = &tmp; int probedirq = PARPORT_IRQ_NONE; if (check_region(base, 3)) return NULL; priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL); if (!priv) { printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base); return NULL; } ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); if (!ops) { printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n", base); kfree (priv); return NULL; } memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations)); priv->ctr = 0xc; priv->ctr_writable = 0xff; priv->ecr = 0; priv->fifo_depth = 0; priv->dma_buf = 0; priv->dma_handle = 0; priv->dev = dev; p->base = base; p->base_hi = base_hi; p->irq = irq; p->dma = dma; p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; p->ops = ops; p->private_data = priv; p->physport = p; if (base_hi && !check_region(base_hi,3)) { parport_ECR_present(p); parport_ECP_supported(p); } if (base != 0x3bc) { if (!check_region(base+0x3, 5)) { if (!parport_EPP_supported(p)) parport_ECPEPP_supported(p); } } if (!parport_SPP_supported (p)) { /* No port. */ kfree (priv); return NULL; } if (priv->ecr) parport_ECPPS2_supported(p); else parport_PS2_supported (p); if (!(p = parport_register_port(base, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, ops))) { kfree (priv); kfree (ops); return NULL; } p->base_hi = base_hi; p->modes = tmp.modes; p->size = (p->modes & PARPORT_MODE_EPP)?8:3; p->private_data = priv; printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); if (p->base_hi && (p->modes & PARPORT_MODE_ECP)) printk(" (0x%lx)", p->base_hi); p->irq = irq; p->dma = dma; if (p->irq == PARPORT_IRQ_AUTO) { p->irq = PARPORT_IRQ_NONE; parport_irq_probe(p); } else if (p->irq == PARPORT_IRQ_PROBEONLY) { p->irq = PARPORT_IRQ_NONE; parport_irq_probe(p); probedirq = p->irq; p->irq = PARPORT_IRQ_NONE; } if (p->irq != PARPORT_IRQ_NONE) { printk(", irq %d", p->irq); if (p->dma == PARPORT_DMA_AUTO) { p->dma = PARPORT_DMA_NONE; parport_dma_probe(p); } } if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq is mandatory (see above) */ p->dma = PARPORT_DMA_NONE;#ifdef CONFIG_PARPORT_PC_FIFO if (p->dma != PARPORT_DMA_NOFIFO && priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) { p->ops->compat_write_data = parport_pc_compat_write_block_pio;#ifdef CONFIG_PARPORT_1284 p->ops->ecp_write_data = parport_pc_ecp_write_block_pio;#endif /* IEEE 1284 support */ if (p->dma != PARPORT_DMA_NONE) { printk(", dma %d", p->dma); p->modes |= PARPORT_MODE_DMA; } else printk(", using FIFO"); } else /* We can't use the DMA channel after all. */ p->dma = PARPORT_DMA_NONE;#endif /* Allowed to use FIFO/DMA */ printk(" [");#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}} { int f = 0; printmode(PCSPP); printmode(TRISTATE); printmode(COMPAT) printmode(EPP); printmode(ECP); printmode(DMA); }#undef printmode#ifndef CONFIG_PARPORT_1284 printk ("(,...)");#endif /* CONFIG_PARPORT_1284 */ printk("]\n"); if (probedirq != PARPORT_IRQ_NONE) printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq); parport_proc_register(p); request_region (p->base, 3, p->name); if (p->size > 3) request_region (p->base + 3, p->size - 3, p->name); if (p->modes & PARPORT_MODE_ECP) request_region (p->base_hi, 3, p->name); if (p->irq != PARPORT_IRQ_NONE) { if (request_irq (p->irq, parport_pc_interrupt, 0, p->name, p)) { printk (KERN_WARNING "%s: irq %d in use, " "resorting to polled operation\n", p->name, p->irq); p->irq = PARPORT_IRQ_NONE; p->dma = PARPORT_DMA_NONE; }#ifdef CONFIG_PARPORT_PC_FIFO if (p->dma != PARPORT_DMA_NONE) { if (request_dma (p->dma, p->name)) { printk (KERN_WARNING "%s: dma %d in use, " "resorting to PIO operation\n", p->name, p->dma); p->dma = PARPORT_DMA_NONE; } else { priv->dma_buf = pci_alloc_consistent(priv->dev, PAGE_SIZE, &priv->dma_handle); if (! priv->dma_buf) { printk (KERN_WARNING "%s: " "cannot get buffer for DMA, " "resorting to PIO operation\n", p->name); free_dma(p->dma); p->dma = PARPORT_DMA_NONE; } } }#endif /* CONFIG_PARPORT_PC_FIFO */ } /* Done probing. Now put the port into a sensible start-up state. */ if (priv->ecr) /* * Put the ECP detected port in PS2 mode. * Do this also for ports that have ECR but don't do ECP. */ outb (0x34, ECONTROL (p)); parport_pc_write_data(p, 0); parport_pc_data_forward (p); /* Now that we've told the sharing engine about the port, and found out its characteristics, let the high-level drivers know about it. */ parport_announce_port (p); return p;}/* Via support maintained by Jeff Garzik <jgarzik@mandrakesoft.com> */static int __devinit sio_via_686a_probe (struct pci_dev *pdev){ u8 tmp; int dma, irq; unsigned port1, port2, have_eppecp; /* * unlock super i/o configuration, set 0x85_1 */ pci_read_config_byte (pdev, 0x85, &tmp); tmp |= (1 << 1); pci_write_config_byte (pdev, 0x85, tmp); /* * Super I/O configuration, index port == 3f0h, data port == 3f1h */ /* 0xE2_1-0: Parallel Port Mode / Enable */ outb (0xE2, 0x3F0); tmp = inb (0x3F1); if ((tmp & 0x03) == 0x03) { printk (KERN_INFO "parport_pc: Via 686A parallel port disabled in BIOS\n"); return 0; } /* 0xE6: Parallel Port I/O Base Address, bits 9-2 */ outb (0xE6, 0x3F0); port1 = inb (0x3F1) << 2; switch (port1) { case 0x3bc: port2 = 0x7bc; break; case 0x378: port2 = 0x778; break; case 0x278: port2 = 0x678; break; default: printk (KERN_INFO "parport_pc: Via 686A weird parport base 0x%X, ignoring\n", port1); return 0; } /* 0xF0_5: EPP+ECP enable */ outb (0xF0, 0x3F0); have_eppecp = (inb (0x3F1) & (1 << 5)); /* * lock super i/o configuration, clear 0x85_1 */ pci_read_config_byte (pdev, 0x85, &tmp); tmp &= ~(1 << 1); pci_write_config_byte (pdev, 0x85, tmp); /* * Get DMA and IRQ from PCI->ISA bridge PCI config registers */ /* 0x50_3-2: PnP Routing for Parallel Port DRQ */ pci_read_config_byte (pdev, 0x50, &tmp); dma = ((tmp >> 2) & 0x03); /* 0x51_7-4: PnP Routing for Parallel Port IRQ */ pci_read_config_byte (pdev, 0x51, &tmp); irq = ((tmp >> 4) & 0x0F); /* filter bogus IRQs */ switch (irq) { case 0: case 2: case 8: case 13: irq = PARPORT_IRQ_NONE; break; default: /* do nothing */ break; } /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */ if (!have_eppecp) dma = PARPORT_DMA_NONE; /* finally, do the probe with values obtained */ if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) { printk (KERN_INFO "parport_pc: Via 686A parallel port: io=0x%X", port1); if (irq != PARPORT_IRQ_NONE) printk (", irq=%d", irq); if (dma != PARPORT_DMA_NONE) printk (", dma=%d", dma); printk ("\n"); return 1; } printk (KERN_WARNING "parport_pc: Strange, can't probe Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n", port1, irq, dma); return 0;}enum parport_pc_sio_types { sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */ last_sio};/* each element directly indexed from enum list, above */static struct parport_pc_superio { int (*probe) (struct pci_dev *pdev);} parport_pc_superio_info[] __devinitdata = { { sio_via_686a_probe, },};enum parport_pc_pci_cards { siig_1s1p_10x_550 = last_sio, siig_1s1p_10x_650, siig_1s1p_10x_850, siig_1p_10x, siig_2p_10x, siig_2s1p_10x_550, siig_2s1p_10x_650, siig_2s1p_10x_850, siig_1p_20x, siig_2p_20x, siig_2p1s_20x_550, siig_2p1s_20x_650, siig_2p1s_20x_850, siig_1s1p_20x_550, siig_1s1p_20x_650, siig_1s1p_20x_850, siig_2s1p_20x_550, siig_2s1p_20x_650, siig_2s1p_20x_850, lava_parallel, lava_parallel_dual_a, lava_parallel_dual_b, boca_ioppar, plx_9050, afavlab_tk9902, timedia_4078a, timedia_4079h, timedia_4085h, timedia_4088a, timedia_4089a, timedia_4095a, timedia_4096a, timedia_4078u, timedia_4079a, timedia_4085u, timedia_4079r, timedia_4079s, timedia_4079d, timedia_4079e, timedia_4079f, timedia_9079a, timedia_9079b, timedia_9079c, timedia_4006a, timedia_4014, timedia_4008a, timedia_4018, timedia_9018a, syba_2p_epp, syba_1p_ecp,};/* each element directly indexed from enum list, above * (but offset by last_sio) */static struct parport_pc_pci { int numports; struct { /* BAR (base address registers) numbers in the config space header */ int lo; int hi; /* -1 if not there, >6 for offset-method (max BAR is 6) */ } addr[4];} cards[] __devinitdata = { /* siig_1s1p_10x_550 */ { 1, { { 3, 4 }, } }, /* siig_1s1p_10x_650 */ { 1, { { 3, 4 }, } }, /* siig_1s1p_10x_850 */ { 1, { { 3, 4 }, } }, /* siig_1p_10x */ { 1, { { 2, 3 }, } }, /* siig_2p_10x */ { 2, { { 2, 3 }, { 4, 5 }, } }, /* siig_2s1p_10x_550 */ { 1, { { 4, 5 }, } }, /* siig_2s1p_10x_650 */ { 1, { { 4, 5 }, } }, /* siig_2s1p_10x_850 */ { 1, { { 4, 5 }, } }, /* siig_1p_20x */ { 1, { { 0, 1 }, } }, /* siig_2p_20x */ { 2, { { 0, 1 }, { 2, 3 }, } }, /* siig_2p1s_20x_550 */ { 2, { { 1, 2 }, { 3, 4 }, } }, /* siig_2p1s_20x_650 */ { 2, { { 1, 2 }, { 3, 4 }, } }, /* siig_2p1s_20x_850 */ { 2, { { 1, 2 }, { 3, 4 }, } }, /* siig_1s1p_20x_550 */ { 1, { { 1, 2 }, } }, /* siig_1s1p_20x_650 */ { 1, { { 1, 2 }, } }, /* siig_1s1p_20x_850 */ { 1, { { 1, 2 }, } }, /* siig_2s1p_20x_550 */ { 1, { { 2, 3 }, } }, /* siig_2s1p_20x_650 */ { 1, { { 2, 3 }, } }, /* siig_2s1p_20x_850 */ { 1, { { 2, 3 }, } }, /* lava_parallel */ { 1, { { 0, -1 }, } }, /* lava_parallel_dual_a */ { 1, { { 0, -1 }, } }, /* lava_parallel_dual_b */ { 1, { { 0, -1 }, } }, /* boca_ioppar */ { 1, { { 0, -1 }, } }, /* plx_9050 */ { 2, { { 4, -1 }, { 5, -1 }, } }, /* afavlab_tk9902 */ { 1, { { 0, 1 }, } }, /* timedia_4078a */ { 1, { { 2, -1 }, } }, /* timedia_4079h */ { 1, { { 2, 3 }, } }, /* timedia_4085h */ { 2, { { 2, -1 }, { 4, -1 }, } }, /* timedia_4088a */ { 2, { { 2, 3 }, { 4, 5 }, } }, /* timedia_4089a */ { 2, { { 2, 3 }, { 4, 5 }, } }, /* timedia_4095a */ { 2, { { 2, 3 }, { 4, 5 }, } }, /* timedia_4096a */ { 2, { { 2, 3 }, { 4, 5 }, } }, /* timedia_4078u */ { 1, { { 2, -1 }, } }, /* timedia_4079a */ { 1, { { 2, 3 }, } }, /* timedia_4085u */ { 2, { { 2, -1 }, { 4, -1 }, } }, /* timedia_4079r */ { 1, { { 2, 3 }, } }, /* timedia_4079s */ { 1, { { 2, 3 }, } }, /* timedia_4079d */ { 1, { { 2, 3 }, } }, /* timedia_4079e */ { 1, { { 2, 3 }, } }, /* timedia_4079f */ { 1, { { 2, 3 }, } }, /* timedia_9079a */ { 1, { { 2, 3 }, } }, /* timedia_9079b */ { 1, { { 2, 3 }, } }, /* timedia_9079c */ { 1, { { 2, 3 }, } }, /* timedia_4006a */ { 1, { { 0, -1 }, } }, /* timedia_4014 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* timedia_4008a */ { 1, { { 0, 1 }, } }, /* timedia_4018 */ { 2, { { 0, 1 }, { 2, 3 }, } }, /* timedia_9018a */ { 2, { { 0, 1 }, { 2, 3 }, } }, /* SYBA uses fixed offsets in a 1K io window */ /* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } }, /* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } },};static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = { /* Super-IO onboard chips */ { 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a }, /* PCI cards */ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_550 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_650 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_850 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_10x }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_10x }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_550 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_650 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_850 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_20x }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_20x }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_550 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_650 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_850 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -