📄 parport_pc.c
字号:
const int fifo = FIFO (port); int poll_for = 8; /* 80 usecs */ const struct parport_pc_private *priv = port->physport->private_data; const int fifo_depth = priv->fifo_depth; port = port->physport; /* We don't want to be interrupted every character. */ parport_pc_disable_irq (port); frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ /* Forward mode. */ parport_pc_data_forward (port); /* Must be in PS2 mode */ while (left) { unsigned char byte; unsigned char ecrval = inb (ECONTROL (port)); int i = 0; if (current->need_resched && time_before (jiffies, expire)) /* Can't yield the port. */ schedule (); /* Anyone else waiting for the port? */ if (port->waithead) { printk (KERN_DEBUG "Somebody wants the port\n"); break; } if (ecrval & 0x02) { /* FIFO is full. Wait for interrupt. */ /* Clear serviceIntr */ outb (ecrval & ~(1<<2), ECONTROL (port)); false_alarm: ret = parport_wait_event (port, HZ); if (ret < 0) break; ret = 0; if (!time_before (jiffies, expire)) { /* Timed out. */ printk (KERN_DEBUG "FIFO write timed out\n"); break; } ecrval = inb (ECONTROL (port)); if (!(ecrval & (1<<2))) { if (current->need_resched && time_before (jiffies, expire)) schedule (); goto false_alarm; } continue; } /* Can't fail now. */ expire = jiffies + port->cad->timeout; poll: if (signal_pending (current)) break; if (ecrval & 0x01) { /* FIFO is empty. Blast it full. */ const int n = left < fifo_depth ? left : fifo_depth; outsb (fifo, bufp, n); bufp += n; left -= n; /* Adjust the poll time. */ if (i < (poll_for - 2)) poll_for--; continue; } else if (i++ < poll_for) { udelay (10); ecrval = inb (ECONTROL (port)); goto poll; } /* Half-full (call me an optimist) */ byte = *bufp++; outb (byte, fifo); left--; } return length - left;}static size_t parport_pc_fifo_write_block_dma (struct parport *port, const void *buf, size_t length){ int ret = 0; unsigned long dmaflag; size_t left = length; const struct parport_pc_private *priv = port->physport->private_data; dma_addr_t dma_addr, dma_handle; size_t maxlen = 0x10000; /* max 64k per DMA transfer */ unsigned long start = (unsigned long) buf; unsigned long end = (unsigned long) buf + length - 1; if (end < MAX_DMA_ADDRESS) { /* If it would cross a 64k boundary, cap it at the end. */ if ((start ^ end) & ~0xffffUL) maxlen = 0x10000 - (start & 0xffff); dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length, PCI_DMA_TODEVICE); } else { /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */ maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ dma_addr = priv->dma_handle; dma_handle = 0; } port = port->physport; /* We don't want to be interrupted every character. */ parport_pc_disable_irq (port); frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ /* Forward mode. */ parport_pc_data_forward (port); /* Must be in PS2 mode */ while (left) { long expire = jiffies + port->physport->cad->timeout; size_t count = left; if (count > maxlen) count = maxlen; if (!dma_handle) /* bounce buffer ! */ memcpy(priv->dma_buf, buf, count); dmaflag = claim_dma_lock(); disable_dma(port->dma); clear_dma_ff(port->dma); set_dma_mode(port->dma, DMA_MODE_WRITE); set_dma_addr(port->dma, dma_addr); set_dma_count(port->dma, count); /* Set DMA mode */ frob_econtrol (port, 1<<3, 1<<3); /* Clear serviceIntr */ frob_econtrol (port, 1<<2, 0); enable_dma(port->dma); release_dma_lock(dmaflag); /* assume DMA will be successful */ left -= count; buf += count; if (dma_handle) dma_addr += count; /* Wait for interrupt. */ false_alarm: ret = parport_wait_event (port, HZ); if (ret < 0) break; ret = 0; if (!time_before (jiffies, expire)) { /* Timed out. */ printk (KERN_DEBUG "DMA write timed out\n"); break; } /* Is serviceIntr set? */ if (!(inb (ECONTROL (port)) & (1<<2))) { if (current->need_resched) schedule (); goto false_alarm; } dmaflag = claim_dma_lock(); disable_dma(port->dma); clear_dma_ff(port->dma); count = get_dma_residue(port->dma); release_dma_lock(dmaflag); if (current->need_resched) /* Can't yield the port. */ schedule (); /* Anyone else waiting for the port? */ if (port->waithead) { printk (KERN_DEBUG "Somebody wants the port\n"); break; } /* update for possible DMA residue ! */ buf -= count; left += count; if (dma_handle) dma_addr -= count; } /* Maybe got here through break, so adjust for DMA residue! */ dmaflag = claim_dma_lock(); disable_dma(port->dma); clear_dma_ff(port->dma); left += get_dma_residue(port->dma); release_dma_lock(dmaflag); /* Turn off DMA mode */ frob_econtrol (port, 1<<3, 0); if (dma_handle) pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE); return length - left;}/* Parallel Port FIFO mode (ECP chipsets) */size_t parport_pc_compat_write_block_pio (struct parport *port, const void *buf, size_t length, int flags){ size_t written; int r; /* Special case: a timeout of zero means we cannot call schedule(). */ if (!port->physport->cad->timeout) return parport_ieee1284_write_compat (port, buf, length, flags); /* Set up parallel port FIFO mode.*/ parport_pc_data_forward (port); /* Must be in PS2 mode */ parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0); r = change_mode (port, ECR_PPF); /* Parallel port FIFO */ if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", port->name); port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; /* Write the data to the FIFO. */ if (port->dma != PARPORT_DMA_NONE) written = parport_pc_fifo_write_block_dma (port, buf, length); else written = parport_pc_fifo_write_block_pio (port, buf, length); /* Finish up. */ if (change_mode (port, ECR_PS2) == -EBUSY) { const struct parport_pc_private *priv = port->physport->private_data; printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); /* Prevent further data transfer. */ frob_econtrol (port, 0xe0, ECR_TST << 5); /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { if (inb (ECONTROL (port)) & 0x2) /* Full up. */ break; outb (0, FIFO (port)); } /* Reset the FIFO and return to PS2 mode. */ frob_econtrol (port, 0xe0, ECR_PS2 << 5); } r = parport_wait_peripheral (port, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY); if (r) printk (KERN_DEBUG "%s: BUSY timeout (%d) in compat_write_block_pio\n", port->name, r); port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; return written;}/* ECP */#ifdef CONFIG_PARPORT_1284size_t parport_pc_ecp_write_block_pio (struct parport *port, const void *buf, size_t length, int flags){ size_t written; int r; /* Special case: a timeout of zero means we cannot call schedule(). */ if (!port->physport->cad->timeout) return parport_ieee1284_ecp_write_data (port, buf, length, flags); /* Switch to forward mode if necessary. */ if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { /* Event 47: Set nInit high. */ parport_frob_control (port, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD); /* Event 49: PError goes high. */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (r) printk (KERN_DEBUG "%s: PError timeout (%d) " "in ecp_write_block_pio\n", port->name, r); } /* Set up ECP parallel port mode.*/ parport_pc_data_forward (port); /* Must be in PS2 mode */ parport_pc_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, 0); r = change_mode (port, ECR_ECP); /* ECP FIFO */ if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name); port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; /* Write the data to the FIFO. */ if (port->dma != PARPORT_DMA_NONE) written = parport_pc_fifo_write_block_dma (port, buf, length); else written = parport_pc_fifo_write_block_pio (port, buf, length); /* Finish up. */ if (change_mode (port, ECR_PS2) == -EBUSY) { const struct parport_pc_private *priv = port->physport->private_data; printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); /* Prevent further data transfer. */ frob_econtrol (port, 0xe0, ECR_TST << 5); /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { if (inb (ECONTROL (port)) & 0x2) /* Full up. */ break; outb (0, FIFO (port)); } /* Reset the FIFO and return to PS2 mode. */ frob_econtrol (port, 0xe0, ECR_PS2 << 5); /* Host transfer recovery. */ parport_pc_data_reverse (port); /* Must be in PS2 mode */ udelay (5); parport_frob_control (port, PARPORT_CONTROL_INIT, 0); r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); if (r) printk (KERN_DEBUG "%s: PE,1 timeout (%d) " "in ecp_write_block_pio\n", port->name, r); parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (r) printk (KERN_DEBUG "%s: PE,2 timeout (%d) " "in ecp_write_block_pio\n", port->name, r); } r = parport_wait_peripheral (port, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY); if(r) printk (KERN_DEBUG "%s: BUSY timeout (%d) in ecp_write_block_pio\n", port->name, r); port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; return written;}size_t parport_pc_ecp_read_block_pio (struct parport *port, void *buf, size_t length, int flags){ size_t left = length; size_t fifofull; int r; const int fifo = FIFO(port); const struct parport_pc_private *priv = port->physport->private_data; const int fifo_depth = priv->fifo_depth; char *bufp = buf; port = port->physport; /* Special case: a timeout of zero means we cannot call schedule(). */ if (!port->cad->timeout) return parport_ieee1284_ecp_read_data (port, buf, length, flags); fifofull = fifo_depth; if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) /* If the peripheral is allowed to send RLE compressed * data, it is possible for a byte to expand to 128 * bytes in the FIFO. */ fifofull = 128; /* If the caller wants less than a full FIFO's worth of data, * go through software emulation. Otherwise we may have to through * away data. */ if (length < fifofull) return parport_ieee1284_ecp_read_data (port, buf, length, flags); /* Switch to reverse mode if necessary. */ if ((port->ieee1284.phase != IEEE1284_PH_REV_IDLE) && (port->ieee1284.phase != IEEE1284_PH_REV_DATA)) { /* Event 38: Set nAutoFd low */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); parport_pc_data_reverse (port); /* Must be in PS2 mode */ udelay (5); /* Event 39: Set nInit low to initiate bus reversal */ parport_frob_control (port, PARPORT_CONTROL_INIT, 0); /* Event 40: PError goes low */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); if (r) printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) " "in ecp_read_block_pio\n", port->name, r); } /* Set up ECP FIFO mode.*/ parport_pc_data_reverse (port); /* Must be in PS2 mode */ parport_pc_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, 0); r = change_mode (port, ECR_ECP); /* ECP FIFO */ if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name); port->ieee1284.phase = IEEE1284_PH_REV_DATA; /* Do the transfer. */ while (left > fifofull) { int ret; long int expire = jiffies + port->cad->timeout; unsigned char ecrval = inb (ECONTROL (port)); if (current->need_resched && time_before (jiffies, expire)) /* Can't yield the port. */ schedule (); /* At this point, the FIFO may already be full. * Ideally, we'd be able to tell the port to hold on * for a second while we empty the FIFO, and we'd be * able to ensure that no data is lost. I'm not sure * that's the case. :-( It might be that you can play * games with STB, as in the forward case; someone should * look at a datasheet. */ if (ecrval & 0x01) { /* FIFO is empty. Wait for interrupt. */ /* Anyone else waiting for the port? */ if (port->waithead) { printk (KERN_DEBUG "Somebody wants the port\n"); break; } /* Clear serviceIntr */ outb (ecrval & ~(1<<2), ECONTROL (port)); false_alarm: ret = parport_wait_event (port, HZ); if (ret < 0) break; ret = 0; if (!time_before (jiffies, expire)) { /* Timed out. */ printk (KERN_DEBUG "PIO read timed out\n"); break; } ecrval = inb (ECONTROL (port)); if (!(ecrval & (1<<2))) { if (current->need_resched && time_before (jiffies, expire)) schedule (); goto false_alarm; } continue; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -