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

📄 parport_pc.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -