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

📄 parport_ip32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Low-level parallel port routines for built-in port on SGI IP32 * * Author: Arnaud Giersch <arnaud.giersch@free.fr> * * Based on parport_pc.c by *	Phil Blundell, Tim Waugh, Jose Renau, David Campbell, *	Andrea Arcangeli, et al. * * Thanks to Ilya A. Volynets-Evenbakh for his help. * * Copyright (C) 2005, 2006 Arnaud Giersch. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Current status: * *	Basic SPP and PS2 modes are supported. *	Support for parallel port IRQ is present. *	Hardware SPP (a.k.a. compatibility), EPP, and ECP modes are *	supported. *	SPP/ECP FIFO can be driven in PIO or DMA mode.  PIO mode can work with *	or without interrupt support. * *	Hardware ECP mode is not fully implemented (ecp_read_data and *	ecp_write_addr are actually missing). * * To do: * *	Fully implement ECP mode. *	EPP and ECP mode need to be tested.  I currently do not own any *	peripheral supporting these extended mode, and cannot test them. *	If DMA mode works well, decide if support for PIO FIFO modes should be *	dropped. *	Use the io{read,write} family functions when they become available in *	the linux-mips.org tree.  Note: the MIPS specific functions readsb() *	and writesb() are to be translated by ioread8_rep() and iowrite8_rep() *	respectively. *//* The built-in parallel port on the SGI 02 workstation (a.k.a. IP32) is an * IEEE 1284 parallel port driven by a Texas Instrument TL16PIR552PH chip[1]. * This chip supports SPP, bidirectional, EPP and ECP modes.  It has a 16 byte * FIFO buffer and supports DMA transfers. * * [1] http://focus.ti.com/docs/prod/folders/print/tl16pir552.html * * Theoretically, we could simply use the parport_pc module.  It is however * not so simple.  The parport_pc code assumes that the parallel port * registers are port-mapped.  On the O2, they are memory-mapped. * Furthermore, each register is replicated on 256 consecutive addresses (as * it is for the built-in serial ports on the same chip). *//*--- Some configuration defines ---------------------------------------*//* DEBUG_PARPORT_IP32 *	0	disable debug *	1	standard level: pr_debug1 is enabled *	2	parport_ip32_dump_state is enabled *	>=3	verbose level: pr_debug is enabled */#if !defined(DEBUG_PARPORT_IP32)#	define DEBUG_PARPORT_IP32  0	/* 0 (disabled) for production */#endif/*----------------------------------------------------------------------*//* Setup DEBUG macros.  This is done before any includes, just in case we * activate pr_debug() with DEBUG_PARPORT_IP32 >= 3. */#if DEBUG_PARPORT_IP32 == 1#	warning DEBUG_PARPORT_IP32 == 1#elif DEBUG_PARPORT_IP32 == 2#	warning DEBUG_PARPORT_IP32 == 2#elif DEBUG_PARPORT_IP32 >= 3#	warning DEBUG_PARPORT_IP32 >= 3#	if !defined(DEBUG)#		define DEBUG /* enable pr_debug() in kernel.h */#	endif#endif#include <linux/completion.h>#include <linux/delay.h>#include <linux/dma-mapping.h>#include <linux/err.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/jiffies.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/parport.h>#include <linux/sched.h>#include <linux/spinlock.h>#include <linux/stddef.h>#include <linux/types.h>#include <asm/io.h>#include <asm/ip32/ip32_ints.h>#include <asm/ip32/mace.h>/*--- Global variables -------------------------------------------------*//* Verbose probing on by default for debugging. */#if DEBUG_PARPORT_IP32 >= 1#	define DEFAULT_VERBOSE_PROBING	1#else#	define DEFAULT_VERBOSE_PROBING	0#endif/* Default prefix for printk */#define PPIP32 "parport_ip32: "/* * These are the module parameters: * @features:		bit mask of features to enable/disable *			(all enabled by default) * @verbose_probing:	log chit-chat during initialization */#define PARPORT_IP32_ENABLE_IRQ	(1U << 0)#define PARPORT_IP32_ENABLE_DMA	(1U << 1)#define PARPORT_IP32_ENABLE_SPP	(1U << 2)#define PARPORT_IP32_ENABLE_EPP	(1U << 3)#define PARPORT_IP32_ENABLE_ECP	(1U << 4)static unsigned int features =	~0U;static int verbose_probing =	DEFAULT_VERBOSE_PROBING;/* We do not support more than one port. */static struct parport *this_port = NULL;/* Timing constants for FIFO modes.  */#define FIFO_NFAULT_TIMEOUT	100	/* milliseconds */#define FIFO_POLLING_INTERVAL	50	/* microseconds *//*--- I/O register definitions -----------------------------------------*//** * struct parport_ip32_regs - virtual addresses of parallel port registers * @data:	Data Register * @dsr:	Device Status Register * @dcr:	Device Control Register * @eppAddr:	EPP Address Register * @eppData0:	EPP Data Register 0 * @eppData1:	EPP Data Register 1 * @eppData2:	EPP Data Register 2 * @eppData3:	EPP Data Register 3 * @ecpAFifo:	ECP Address FIFO * @fifo:	General FIFO register.  The same address is used for: *		- cFifo, the Parallel Port DATA FIFO *		- ecpDFifo, the ECP Data FIFO *		- tFifo, the ECP Test FIFO * @cnfgA:	Configuration Register A * @cnfgB:	Configuration Register B * @ecr:	Extended Control Register */struct parport_ip32_regs {	void __iomem *data;	void __iomem *dsr;	void __iomem *dcr;	void __iomem *eppAddr;	void __iomem *eppData0;	void __iomem *eppData1;	void __iomem *eppData2;	void __iomem *eppData3;	void __iomem *ecpAFifo;	void __iomem *fifo;	void __iomem *cnfgA;	void __iomem *cnfgB;	void __iomem *ecr;};/* Device Status Register */#define DSR_nBUSY		(1U << 7)	/* PARPORT_STATUS_BUSY */#define DSR_nACK		(1U << 6)	/* PARPORT_STATUS_ACK */#define DSR_PERROR		(1U << 5)	/* PARPORT_STATUS_PAPEROUT */#define DSR_SELECT		(1U << 4)	/* PARPORT_STATUS_SELECT */#define DSR_nFAULT		(1U << 3)	/* PARPORT_STATUS_ERROR */#define DSR_nPRINT		(1U << 2)	/* specific to TL16PIR552 *//* #define DSR_reserved		(1U << 1) */#define DSR_TIMEOUT		(1U << 0)	/* EPP timeout *//* Device Control Register *//* #define DCR_reserved		(1U << 7) | (1U <<  6) */#define DCR_DIR			(1U << 5)	/* direction */#define DCR_IRQ			(1U << 4)	/* interrupt on nAck */#define DCR_SELECT		(1U << 3)	/* PARPORT_CONTROL_SELECT */#define DCR_nINIT		(1U << 2)	/* PARPORT_CONTROL_INIT */#define DCR_AUTOFD		(1U << 1)	/* PARPORT_CONTROL_AUTOFD */#define DCR_STROBE		(1U << 0)	/* PARPORT_CONTROL_STROBE *//* ECP Configuration Register A */#define CNFGA_IRQ		(1U << 7)#define CNFGA_ID_MASK		((1U << 6) | (1U << 5) | (1U << 4))#define CNFGA_ID_SHIFT		4#define CNFGA_ID_16		(00U << CNFGA_ID_SHIFT)#define CNFGA_ID_8		(01U << CNFGA_ID_SHIFT)#define CNFGA_ID_32		(02U << CNFGA_ID_SHIFT)/* #define CNFGA_reserved	(1U << 3) */#define CNFGA_nBYTEINTRANS	(1U << 2)#define CNFGA_PWORDLEFT		((1U << 1) | (1U << 0))/* ECP Configuration Register B */#define CNFGB_COMPRESS		(1U << 7)#define CNFGB_INTRVAL		(1U << 6)#define CNFGB_IRQ_MASK		((1U << 5) | (1U << 4) | (1U << 3))#define CNFGB_IRQ_SHIFT		3#define CNFGB_DMA_MASK		((1U << 2) | (1U << 1) | (1U << 0))#define CNFGB_DMA_SHIFT		0/* Extended Control Register */#define ECR_MODE_MASK		((1U << 7) | (1U << 6) | (1U << 5))#define ECR_MODE_SHIFT		5#define ECR_MODE_SPP		(00U << ECR_MODE_SHIFT)#define ECR_MODE_PS2		(01U << ECR_MODE_SHIFT)#define ECR_MODE_PPF		(02U << ECR_MODE_SHIFT)#define ECR_MODE_ECP		(03U << ECR_MODE_SHIFT)#define ECR_MODE_EPP		(04U << ECR_MODE_SHIFT)/* #define ECR_MODE_reserved	(05U << ECR_MODE_SHIFT) */#define ECR_MODE_TST		(06U << ECR_MODE_SHIFT)#define ECR_MODE_CFG		(07U << ECR_MODE_SHIFT)#define ECR_nERRINTR		(1U << 4)#define ECR_DMAEN		(1U << 3)#define ECR_SERVINTR		(1U << 2)#define ECR_F_FULL		(1U << 1)#define ECR_F_EMPTY		(1U << 0)/*--- Private data -----------------------------------------------------*//** * enum parport_ip32_irq_mode - operation mode of interrupt handler * @PARPORT_IP32_IRQ_FWD:	forward interrupt to the upper parport layer * @PARPORT_IP32_IRQ_HERE:	interrupt is handled locally */enum parport_ip32_irq_mode { PARPORT_IP32_IRQ_FWD, PARPORT_IP32_IRQ_HERE };/** * struct parport_ip32_private - private stuff for &struct parport * @regs:		register addresses * @dcr_cache:		cached contents of DCR * @dcr_writable:	bit mask of writable DCR bits * @pword:		number of bytes per PWord * @fifo_depth:		number of PWords that FIFO will hold * @readIntrThreshold:	minimum number of PWords we can read *			if we get an interrupt * @writeIntrThreshold:	minimum number of PWords we can write *			if we get an interrupt * @irq_mode:		operation mode of interrupt handler for this port * @irq_complete:	mutex used to wait for an interrupt to occur */struct parport_ip32_private {	struct parport_ip32_regs	regs;	unsigned int			dcr_cache;	unsigned int			dcr_writable;	unsigned int			pword;	unsigned int			fifo_depth;	unsigned int			readIntrThreshold;	unsigned int			writeIntrThreshold;	enum parport_ip32_irq_mode	irq_mode;	struct completion		irq_complete;};/*--- Debug code -------------------------------------------------------*//* * pr_debug1 - print debug messages * * This is like pr_debug(), but is defined for %DEBUG_PARPORT_IP32 >= 1 */#if DEBUG_PARPORT_IP32 >= 1#	define pr_debug1(...)	printk(KERN_DEBUG __VA_ARGS__)#else /* DEBUG_PARPORT_IP32 < 1 */#	define pr_debug1(...)	do { } while (0)#endif/* * pr_trace, pr_trace1 - trace function calls * @p:		pointer to &struct parport * @fmt:	printk format string * @...:	parameters for format string * * Macros used to trace function calls.  The given string is formatted after * function name.  pr_trace() uses pr_debug(), and pr_trace1() uses * pr_debug1().  __pr_trace() is the low-level macro and is not to be used * directly. */#define __pr_trace(pr, p, fmt, ...)					\	pr("%s: %s" fmt "\n",						\	   ({ const struct parport *__p = (p);				\		   __p ? __p->name : "parport_ip32"; }),		\	   __func__ , ##__VA_ARGS__)#define pr_trace(p, fmt, ...)	__pr_trace(pr_debug, p, fmt , ##__VA_ARGS__)#define pr_trace1(p, fmt, ...)	__pr_trace(pr_debug1, p, fmt , ##__VA_ARGS__)/* * __pr_probe, pr_probe - print message if @verbose_probing is true * @p:		pointer to &struct parport * @fmt:	printk format string * @...:	parameters for format string * * For new lines, use pr_probe().  Use __pr_probe() for continued lines. */#define __pr_probe(...)							\	do { if (verbose_probing) printk(__VA_ARGS__); } while (0)#define pr_probe(p, fmt, ...)						\	__pr_probe(KERN_INFO PPIP32 "0x%lx: " fmt, (p)->base , ##__VA_ARGS__)/* * parport_ip32_dump_state - print register status of parport * @p:		pointer to &struct parport * @str:	string to add in message * @show_ecp_config:	shall we dump ECP configuration registers too? * * This function is only here for debugging purpose, and should be used with * care.  Reading the parallel port registers may have undesired side effects. * Especially if @show_ecp_config is true, the parallel port is resetted. * This function is only defined if %DEBUG_PARPORT_IP32 >= 2. */#if DEBUG_PARPORT_IP32 >= 2static void parport_ip32_dump_state(struct parport *p, char *str,				    unsigned int show_ecp_config){	struct parport_ip32_private * const priv = p->physport->private_data;	unsigned int i;	printk(KERN_DEBUG PPIP32 "%s: state (%s):\n", p->name, str);	{		static const char ecr_modes[8][4] = {"SPP", "PS2", "PPF",						     "ECP", "EPP", "???",						     "TST", "CFG"};		unsigned int ecr = readb(priv->regs.ecr);		printk(KERN_DEBUG PPIP32 "    ecr=0x%02x", ecr);		printk(" %s",		       ecr_modes[(ecr & ECR_MODE_MASK) >> ECR_MODE_SHIFT]);		if (ecr & ECR_nERRINTR)			printk(",nErrIntrEn");		if (ecr & ECR_DMAEN)			printk(",dmaEn");		if (ecr & ECR_SERVINTR)			printk(",serviceIntr");		if (ecr & ECR_F_FULL)			printk(",f_full");		if (ecr & ECR_F_EMPTY)			printk(",f_empty");		printk("\n");	}	if (show_ecp_config) {		unsigned int oecr, cnfgA, cnfgB;		oecr = readb(priv->regs.ecr);		writeb(ECR_MODE_PS2, priv->regs.ecr);		writeb(ECR_MODE_CFG, priv->regs.ecr);		cnfgA = readb(priv->regs.cnfgA);		cnfgB = readb(priv->regs.cnfgB);		writeb(ECR_MODE_PS2, priv->regs.ecr);		writeb(oecr, priv->regs.ecr);		printk(KERN_DEBUG PPIP32 "    cnfgA=0x%02x", cnfgA);		printk(" ISA-%s", (cnfgA & CNFGA_IRQ) ? "Level" : "Pulses");		switch (cnfgA & CNFGA_ID_MASK) {		case CNFGA_ID_8:			printk(",8 bits");			break;		case CNFGA_ID_16:			printk(",16 bits");			break;		case CNFGA_ID_32:			printk(",32 bits");			break;		default:			printk(",unknown ID");			break;		}		if (!(cnfgA & CNFGA_nBYTEINTRANS))			printk(",ByteInTrans");		if ((cnfgA & CNFGA_ID_MASK) != CNFGA_ID_8)			printk(",%d byte%s left", cnfgA & CNFGA_PWORDLEFT,			       ((cnfgA & CNFGA_PWORDLEFT) > 1) ? "s" : "");		printk("\n");		printk(KERN_DEBUG PPIP32 "    cnfgB=0x%02x", cnfgB);		printk(" irq=%u,dma=%u",		       (cnfgB & CNFGB_IRQ_MASK) >> CNFGB_IRQ_SHIFT,		       (cnfgB & CNFGB_DMA_MASK) >> CNFGB_DMA_SHIFT);		printk(",intrValue=%d", !!(cnfgB & CNFGB_INTRVAL));		if (cnfgB & CNFGB_COMPRESS)			printk(",compress");		printk("\n");	}	for (i = 0; i < 2; i++) {		unsigned int dcr = i ? priv->dcr_cache : readb(priv->regs.dcr);		printk(KERN_DEBUG PPIP32 "    dcr(%s)=0x%02x",		       i ? "soft" : "hard", dcr);		printk(" %s", (dcr & DCR_DIR) ? "rev" : "fwd");		if (dcr & DCR_IRQ)			printk(",ackIntEn");		if (!(dcr & DCR_SELECT))			printk(",nSelectIn");		if (dcr & DCR_nINIT)			printk(",nInit");		if (!(dcr & DCR_AUTOFD))			printk(",nAutoFD");		if (!(dcr & DCR_STROBE))			printk(",nStrobe");		printk("\n");	}#define sep (f++ ? ',' : ' ')	{		unsigned int f = 0;		unsigned int dsr = readb(priv->regs.dsr);		printk(KERN_DEBUG PPIP32 "    dsr=0x%02x", dsr);		if (!(dsr & DSR_nBUSY))			printk("%cBusy", sep);		if (dsr & DSR_nACK)			printk("%cnAck", sep);		if (dsr & DSR_PERROR)			printk("%cPError", sep);		if (dsr & DSR_SELECT)			printk("%cSelect", sep);		if (dsr & DSR_nFAULT)

⌨️ 快捷键说明

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