1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#ifndef	_SYS_ECPPVAR_H
28#define	_SYS_ECPPVAR_H
29
30#include <sys/note.h>
31#include <sys/sysmacros.h>
32
33#ifdef	__cplusplus
34extern "C" {
35#endif
36
37struct ecppunit;
38
39/*
40 * Hardware-abstraction structure
41 */
42struct ecpp_hw {
43	int	(*map_regs)(struct ecppunit *);		/* map registers */
44	void	(*unmap_regs)(struct ecppunit *);	/* unmap registers */
45	int	(*config_chip)(struct ecppunit *);	/* configure SuperIO */
46	void	(*config_mode)(struct ecppunit *);	/* config new mode */
47	void	(*mask_intr)(struct ecppunit *);	/* mask interrupts */
48	void	(*unmask_intr)(struct ecppunit *);	/* unmask interrupts */
49	int	(*dma_start)(struct ecppunit *);	/* start DMA transfer */
50	int	(*dma_stop)(struct ecppunit *, size_t *); /* stop DMA xfer */
51	size_t	(*dma_getcnt)(struct ecppunit *);	/* get DMA counter */
52	ddi_dma_attr_t	*attr;				/* DMA attributes */
53};
54
55#define	ECPP_MAP_REGS(pp)		(pp)->hw->map_regs(pp)
56#define	ECPP_UNMAP_REGS(pp)		(pp)->hw->unmap_regs(pp)
57#define	ECPP_CONFIG_CHIP(pp)		(pp)->hw->config_chip(pp)
58#define	ECPP_CONFIG_MODE(pp)		(pp)->hw->config_mode(pp)
59#define	ECPP_MASK_INTR(pp)		(pp)->hw->mask_intr(pp)
60#define	ECPP_UNMASK_INTR(pp)		(pp)->hw->unmask_intr(pp)
61#define	ECPP_DMA_START(pp)		(pp)->hw->dma_start(pp)
62#define	ECPP_DMA_STOP(pp, cnt)		(pp)->hw->dma_stop(pp, cnt)
63#define	ECPP_DMA_GETCNT(pp)		(pp)->hw->dma_getcnt(pp)
64
65/* NSC 87332/97317 and EBus DMAC */
66struct ecpp_ebus {
67	struct config_reg	*c_reg; 	/* configuration registers */
68	ddi_acc_handle_t	c_handle;	/* handle for conf regs */
69	struct cheerio_dma_reg	*dmac;		/* ebus dmac registers */
70	ddi_acc_handle_t	d_handle;	/* handle for dmac registers */
71	struct config2_reg	*c2_reg; 	/* 97317 2nd level conf regs */
72	ddi_acc_handle_t	c2_handle;	/* handle for c2_reg */
73};
74
75/* Southbridge SuperIO and 8237 DMAC */
76struct ecpp_m1553 {
77	struct isaspace		*isa_space;	/* all of isa space */
78	ddi_acc_handle_t	d_handle;	/* handle for isa space */
79	uint8_t			chn;		/* 8237 dma channel */
80	int			isadma_entered;	/* Southbridge DMA workaround */
81};
82
83#if defined(__x86)
84struct ecpp_x86 {
85	uint8_t			chn;
86};
87#endif
88
89/*
90 * Hardware binding structure
91 */
92struct ecpp_hw_bind {
93	char		*name;		/* binding name */
94	struct ecpp_hw	*hw;		/* hw description */
95	char		*info;		/* info string */
96};
97
98/* ecpp e_busy states */
99typedef enum {
100	ECPP_IDLE = 1,	/* No ongoing transfers */
101	ECPP_BUSY = 2,	/* Ongoing transfers on the cable */
102	ECPP_DATA = 3,	/* Not used */
103	ECPP_ERR = 4,	/* Bad status in Centronics mode */
104	ECPP_FLUSH = 5	/* Currently flushing the q */
105} ecpp_busy_t;
106
107/*
108 * ecpp soft state structure
109 */
110struct ecppunit {
111	kmutex_t	umutex;		/* lock for this structure */
112	int		instance;	/* instance number */
113	dev_info_t	*dip;		/* device information */
114	ddi_iblock_cookie_t ecpp_trap_cookie;	/* interrupt cookie */
115	ecpp_busy_t	e_busy;		/* ecpp busy flag */
116	kcondvar_t	pport_cv;	/* cv to signal idle state */
117	/*
118	 * common SuperIO registers
119	 */
120	struct info_reg		*i_reg; 	/* info registers */
121	struct fifo_reg		*f_reg; 	/* fifo register */
122	ddi_acc_handle_t	i_handle;
123	ddi_acc_handle_t	f_handle;
124	/*
125	 * DMA support
126	 */
127	ddi_dma_handle_t	dma_handle;	/* DMA handle */
128	ddi_dma_cookie_t	dma_cookie;	/* current cookie */
129	uint_t			dma_cookie_count;	/* # of cookies */
130	uint_t			dma_nwin;	/* # of DMA windows */
131	uint_t			dma_curwin;	/* current window number */
132	uint_t			dma_dir;	/* transfer direction */
133	/*
134	 * hardware-dependent stuff
135	 */
136	struct ecpp_hw	*hw;		/* operations/attributes */
137	union {				/* hw-dependent data */
138		struct ecpp_ebus	ebus;
139		struct ecpp_m1553	m1553;
140#if defined(__x86)
141		struct ecpp_x86 	x86;
142#endif
143	} uh;
144	/*
145	 * DDI/STREAMS stuff
146	 */
147	boolean_t	oflag;		/* instance open flag */
148	queue_t		*readq;		/* pointer to readq */
149	queue_t		*writeq;	/* pointer to writeq */
150	mblk_t		*msg;		/* current message block */
151	boolean_t	suspended;	/* driver suspended status */
152	/*
153	 * Modes of operation
154	 */
155	int		current_mode;	/* 1284 mode */
156	uchar_t		current_phase;	/* 1284 phase */
157	uchar_t		backchannel;	/* backchannel mode supported */
158	uchar_t		io_mode;	/* transfer mode: PIO/DMA */
159	/*
160	 * Ioctls support
161	 */
162	struct ecpp_transfer_parms xfer_parms;	/* transfer parameters */
163	struct ecpp_regs regs;		/* control/status registers */
164	uint8_t		saved_dsr;	/* store the dsr returned from TESTIO */
165	boolean_t	timeout_error;	/* store the timeout for GETERR */
166	uchar_t		port;		/* xfer type: dma/pio/tfifo */
167	struct prn_timeouts prn_timeouts; /* prnio timeouts */
168	/*
169	 * ecpp.conf parameters
170	 */
171	uchar_t		init_seq;	/* centronics init seq */
172	uint32_t	wsrv_retry;	/* delay (ms) before next wsrv */
173	uint32_t	wait_for_busy;	/* wait for BUSY to deassert */
174	uint32_t	data_setup_time; /* pio centronics handshake */
175	uint32_t	strobe_pulse_width; /* pio centronics handshake */
176	uint8_t		fast_centronics; /* DMA/PIO centronics */
177	uint8_t		fast_compat;	/* DMA/PIO 1284 compatible mode */
178	uint32_t	ecp_rev_speed;	/* rev xfer speed in ECP, bytes/sec */
179	uint32_t	rev_watchdog;	/* rev xfer watchdog period, ms */
180	/*
181	 * Timeouts
182	 */
183	timeout_id_t	timeout_id;	/* io transfers timer */
184	timeout_id_t	fifo_timer_id;	/* drain SuperIO FIFO */
185	timeout_id_t	wsrv_timer_id;	/* wsrv timeout */
186	/*
187	 * Softintr data
188	 */
189	ddi_softintr_t	softintr_id;
190	int		softintr_flags;	/* flags indicating softintr task */
191	uint8_t		softintr_pending;
192	/*
193	 * Misc stuff
194	 */
195	caddr_t		ioblock;	/* transfer buffer block */
196	size_t		xfercnt;	/* # of bytes to transfer */
197	size_t		resid;		/* # of bytes not transferred */
198	caddr_t		next_byte;	/* next byte for PIO transfer */
199	caddr_t		last_byte;	/* last byte for PIO transfer */
200	uint32_t	ecpp_drain_counter;	/* allows fifo to drain */
201	uchar_t		dma_cancelled;	/* flushed while dma'ing */
202	uint8_t		tfifo_intr;	/* TFIFO switch interrupt workaround */
203	size_t		nread;		/* requested read */
204	size_t		last_dmacnt;	/* DMA counter value for rev watchdog */
205	uint32_t	rev_timeout_cnt; /* number of watchdog invocations */
206	/*
207	 * Spurious interrupt detection
208	 */
209	hrtime_t	lastspur;	/* last time spurious intrs started */
210	long		nspur;		/* spurious intrs counter */
211	/*
212	 * Statistics
213	 */
214	kstat_t		*ksp;		/* kstat pointer */
215	kstat_t		*intrstats;	/* kstat interrupt counter */
216	/*
217	 * number of bytes, transferred in and out in each mode
218	 */
219	uint32_t	ctxpio_obytes;
220	uint32_t	obytes[ECPP_EPP_MODE+1];
221	uint32_t	ibytes[ECPP_EPP_MODE+1];
222	/*
223	 * other stats
224	 */
225	uint32_t	to_mode[ECPP_EPP_MODE+1]; /* # transitions to mode */
226	uint32_t	xfer_tout;	/* # transfer timeouts */
227	uint32_t	ctx_cf;		/* # periph check failures */
228	uint32_t	joblen;		/* of bytes xfer'd since open */
229	uint32_t	isr_reattempt_high;	/* max times isr has looped */
230	/*
231	 * interrupt stats
232	 */
233	uint_t		intr_hard;
234	uint_t		intr_spurious;
235	uint_t		intr_soft;
236	/*
237	 * identify second register set for ecp mode on Sx86
238	 */
239	int		noecpregs;
240};
241
242_NOTE(MUTEX_PROTECTS_DATA(ecppunit::umutex, ecppunit))
243_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::dip))
244_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::instance))
245_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::i_reg))
246_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::f_reg))
247_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::i_handle))
248_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::f_handle))
249_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::ecpp_trap_cookie))
250_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::readq))
251_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::writeq))
252
253/*
254 * current_phase values
255 */
256#define	ECPP_PHASE_INIT		0x00	/* initialization */
257#define	ECPP_PHASE_NEGO		0x01	/* negotiation */
258#define	ECPP_PHASE_TERM		0x02	/* termination */
259#define	ECPP_PHASE_PO		0x03	/* power-on */
260
261#define	ECPP_PHASE_C_FWD_DMA	0x10	/* cntrx/compat fwd dma xfer */
262#define	ECPP_PHASE_C_FWD_PIO	0x11	/* cntrx/compat fwd PIO xfer */
263#define	ECPP_PHASE_C_IDLE	0x12	/* cntrx/compat idle */
264
265#define	ECPP_PHASE_NIBT_REVDATA	0x20	/* nibble/byte reverse data */
266#define	ECPP_PHASE_NIBT_AVAIL	0x21	/* nibble/byte reverse data available */
267#define	ECPP_PHASE_NIBT_NAVAIL	0x22	/* nibble/byte reverse data not avail */
268#define	ECPP_PHASE_NIBT_REVIDLE	0x22	/* nibble/byte reverse idle */
269#define	ECPP_PHASE_NIBT_REVINTR	0x23	/* nibble/byte reverse interrupt */
270
271#define	ECPP_PHASE_ECP_SETUP	0x30	/* ecp setup */
272#define	ECPP_PHASE_ECP_FWD_XFER	0x31	/* ecp forward transfer */
273#define	ECPP_PHASE_ECP_FWD_IDLE	0x32	/* ecp forward idle */
274#define	ECPP_PHASE_ECP_FWD_REV	0x33	/* ecp forward to reverse */
275#define	ECPP_PHASE_ECP_REV_XFER	0x34	/* ecp reverse transfer */
276#define	ECPP_PHASE_ECP_REV_IDLE	0x35	/* ecp reverse idle */
277#define	ECPP_PHASE_ECP_REV_FWD	0x36	/* ecp reverse to forward */
278
279#define	ECPP_PHASE_EPP_INIT_IDLE 0x40	/* epp init phase */
280#define	ECPP_PHASE_EPP_IDLE	0x41	/* epp all-round phase */
281
282#define	FAILURE_PHASE		0x80
283#define	UNDEFINED_PHASE		0x81
284
285/* ecpp return values */
286#define	SUCCESS		1
287#define	FAILURE		2
288
289#define	TRUE		1
290#define	FALSE		0
291
292/* message type */
293#define	ECPP_BACKCHANNEL	0x45
294
295/* transfer modes */
296#define	ECPP_DMA		0x1
297#define	ECPP_PIO		0x2
298
299/* tuneable timing defaults */
300#define	CENTRONICS_RETRY	750	/* 750 milliseconds */
301#define	WAIT_FOR_BUSY		1000	/* 1000 microseconds */
302#define	SUSPEND_TOUT		10	/* # seconds before suspend fails */
303
304/* Centronics hanshaking defaults */
305#define	DATA_SETUP_TIME		2	/* 2 uSec Data Setup Time (2x min) */
306#define	STROBE_PULSE_WIDTH	2	/* 2 uSec Strobe Pulse (2x min) */
307
308/* 1284 Extensibility Request values */
309#define	ECPP_XREQ_NIBBLE	0x00    /* Nibble Mode Rev Channel Transfer */
310#define	ECPP_XREQ_BYTE		0x01    /* Byte Mode Rev Channel Transfer */
311#define	ECPP_XREQ_ID		0x04    /* Request Device ID */
312#define	ECPP_XREQ_ECP		0x10    /* Request ECP Mode */
313#define	ECPP_XREQ_ECPRLE	0x30    /* Request ECP Mode with RLE */
314#define	ECPP_XREQ_EPP		0x40	/* Request EPP Mode */
315#define	ECPP_XREQ_XLINK		0x80    /* Request Extensibility Link */
316
317/* softintr flags */
318#define	ECPP_SOFTINTR_PIONEXT	0x1	/* write next byte in PIO mode */
319
320/* Stream  defaults */
321#define	IO_BLOCK_SZ	1024 * 128	/* transfer buffer size */
322#define	ECPPHIWAT	32 * 1024  * 6
323#define	ECPPLOWAT	32 * 1024  * 4
324
325/* Loop timers */
326#define	ECPP_REG_WRITE_MAX_LOOP	100	/* cpu is faster than superio */
327#define	ECPP_ISR_MAX_DELAY	30	/* DMAC slow PENDING status */
328
329/* misc constants */
330#define	ECPP_FIFO_SZ		16	/* FIFO size */
331#define	FIFO_DRAIN_PERIOD	250000	/* max FIFO drain period in usec */
332#define	NIBBLE_REV_BLKSZ	1024	/* send up to # bytes at a time */
333#define	FWD_TIMEOUT_DEFAULT	90	/* forward xfer timeout in seconds */
334#define	REV_TIMEOUT_DEFAULT	0	/* reverse xfer timeout in seconds */
335
336/* ECP mode constants */
337#define	ECP_REV_BLKSZ		1024	/* send up to # bytes at a time */
338#define	ECP_REV_BLKSZ_MAX	(4 * 1024)	/* maximum of # bytes */
339#define	ECP_REV_SPEED		(1 * 1024 * 1024)	/* bytes/sec */
340#define	ECP_REV_MINTOUT		5	/* min ECP rev xfer timeout in ms */
341#define	REV_WATCHDOG		100	/* poll DMA counter every # ms */
342
343/* spurious interrupt detection */
344#define	SPUR_CRITICAL		100	/* number of interrupts... */
345#define	SPUR_PERIOD		1000000000 /* in # ns */
346
347/*
348 * Copyin/copyout states
349 */
350#define	ECPP_STRUCTIN		0
351#define	ECPP_STRUCTOUT		1
352#define	ECPP_ADDRIN 		2
353#define	ECPP_ADDROUT		3
354
355/*
356 * As other ioctls require the same structure, put inner struct's into union
357 */
358struct ecpp_copystate {
359	int	state;		/* see above */
360	void	*uaddr;		/* user address of the following structure */
361	union {
362		struct ecpp_device_id		devid;
363		struct prn_1284_device_id	prn_devid;
364		struct prn_interface_info	prn_if;
365	} un;
366};
367
368/*
369 * The structure is dynamically created for each M_IOCTL and is bound to mblk
370 */
371_NOTE(SCHEME_PROTECTS_DATA("unique per call", ecpp_copystate))
372
373/* kstat structure */
374struct ecppkstat {
375	/*
376	 * number of bytes, transferred in and out in each mode
377	 */
378	struct kstat_named	ek_ctx_obytes;
379	struct kstat_named	ek_ctxpio_obytes;
380	struct kstat_named	ek_nib_ibytes;
381	struct kstat_named	ek_ecp_obytes;
382	struct kstat_named	ek_ecp_ibytes;
383	struct kstat_named	ek_epp_obytes;
384	struct kstat_named	ek_epp_ibytes;
385	struct kstat_named	ek_diag_obytes;
386	/*
387	 * number of transitions to particular mode
388	 */
389	struct kstat_named	ek_to_ctx;
390	struct kstat_named	ek_to_nib;
391	struct kstat_named	ek_to_ecp;
392	struct kstat_named	ek_to_epp;
393	struct kstat_named	ek_to_diag;
394	/*
395	 * other stats
396	 */
397	struct kstat_named	ek_xfer_tout;	/* # transfer timeouts */
398	struct kstat_named	ek_ctx_cf;	/* # periph check failures */
399	struct kstat_named	ek_joblen;	/* # bytes xfer'd since open */
400	struct kstat_named	ek_isr_reattempt_high;	/* max # times */
401							/* isr has looped */
402	struct kstat_named	ek_mode;	/* 1284 mode */
403	struct kstat_named	ek_phase;	/* 1284 ECP phase */
404	struct kstat_named	ek_backchan;	/* backchannel mode supported */
405	struct kstat_named	ek_iomode;	/* transfer mode: pio/dma */
406	struct kstat_named	ek_state;	/* ecpp busy flag */
407};
408
409/* Macros for superio programming */
410#define	PP_PUTB(x, y, z)  	ddi_put8(x, y, z)
411#define	PP_GETB(x, y)		ddi_get8(x, y)
412
413#define	DSR_READ(pp)		PP_GETB((pp)->i_handle, &(pp)->i_reg->dsr)
414#define	DCR_READ(pp)		PP_GETB((pp)->i_handle, &(pp)->i_reg->dcr)
415#define	ECR_READ(pp)		\
416	(pp->noecpregs) ? 0xff : PP_GETB((pp)->f_handle, &(pp)->f_reg->ecr)
417#define	DATAR_READ(pp)		PP_GETB((pp)->i_handle, &(pp)->i_reg->ir.datar)
418#define	DFIFO_READ(pp)		\
419	(pp->noecpregs) ? 0xff : PP_GETB((pp)->f_handle, &(pp)->f_reg->fr.dfifo)
420#define	TFIFO_READ(pp)		\
421	(pp->noecpregs) ? 0xff : PP_GETB((pp)->f_handle, &(pp)->f_reg->fr.tfifo)
422
423#define	DCR_WRITE(pp, val)	PP_PUTB((pp)->i_handle, &(pp)->i_reg->dcr, val)
424#define	ECR_WRITE(pp, val)	\
425	if (!pp->noecpregs) PP_PUTB((pp)->f_handle, &(pp)->f_reg->ecr, val)
426#define	DATAR_WRITE(pp, val)	\
427			PP_PUTB((pp)->i_handle, &(pp)->i_reg->ir.datar, val)
428#define	DFIFO_WRITE(pp, val)	\
429	if (!pp->noecpregs) PP_PUTB((pp)->f_handle, &(pp)->f_reg->fr.dfifo, val)
430#define	TFIFO_WRITE(pp, val)	\
431	if (!pp->noecpregs) PP_PUTB((pp)->f_handle, &(pp)->f_reg->fr.tfifo, val)
432
433/*
434 * Macros to manipulate register bits
435 */
436#define	OR_SET_BYTE_R(handle, addr, val) \
437{		\
438	uint8_t tmpval;					\
439	tmpval = ddi_get8(handle, (uint8_t *)addr);	\
440	tmpval |= val;					\
441	ddi_put8(handle, (uint8_t *)addr, tmpval);	\
442}
443
444#define	OR_SET_LONG_R(handle, addr, val) \
445{		\
446	uint32_t tmpval;				\
447	tmpval = ddi_get32(handle, (uint32_t *)addr);	\
448	tmpval |= val;					\
449	ddi_put32(handle, (uint32_t *)addr, tmpval);	\
450}
451
452#define	AND_SET_BYTE_R(handle, addr, val) \
453{		\
454	uint8_t tmpval;					\
455	tmpval = ddi_get8(handle, (uint8_t *)addr);	\
456	tmpval &= val; 					\
457	ddi_put8(handle, (uint8_t *)addr, tmpval);	\
458}
459
460#define	AND_SET_LONG_R(handle, addr, val) \
461{		\
462	uint32_t tmpval;				\
463	tmpval = ddi_get32(handle, (uint32_t *)addr);	\
464	tmpval &= val; 					\
465	ddi_put32(handle, (uint32_t *)addr, tmpval);	\
466}
467
468#define	NOR_SET_LONG_R(handle, addr, val, mask) \
469{		\
470	uint32_t tmpval;				\
471	tmpval = ddi_get32(handle, (uint32_t *)addr);	\
472	tmpval &= ~(mask);				\
473	tmpval |= val;					\
474	ddi_put32(handle, (uint32_t *)addr, tmpval);	\
475}
476
477/*
478 * Macros for Cheerio/RIO DMAC programming
479 */
480#define	SET_DMAC_CSR(pp, val)	ddi_put32(pp->uh.ebus.d_handle, \
481				((uint32_t *)&pp->uh.ebus.dmac->csr), \
482				((uint32_t)val))
483#define	GET_DMAC_CSR(pp)	ddi_get32(pp->uh.ebus.d_handle, \
484				(uint32_t *)&(pp->uh.ebus.dmac->csr))
485
486#define	SET_DMAC_ACR(pp, val)	ddi_put32(pp->uh.ebus.d_handle, \
487				((uint32_t *)&pp->uh.ebus.dmac->acr), \
488				((uint32_t)val))
489
490#define	GET_DMAC_ACR(pp)	ddi_get32(pp->uh.ebus.d_handle, \
491				(uint32_t *)&pp->uh.ebus.dmac->acr)
492
493#define	SET_DMAC_BCR(pp, val)	ddi_put32(pp->uh.ebus.d_handle, \
494				((uint32_t *)&pp->uh.ebus.dmac->bcr), \
495				((uint32_t)val))
496
497#define	GET_DMAC_BCR(pp)	ddi_get32(pp->uh.ebus.d_handle, \
498				((uint32_t *)&pp->uh.ebus.dmac->bcr))
499
500#define	DMAC_RESET_TIMEOUT	10000	/* in usec */
501
502/*
503 * Macros to distinguish between PIO and DMA Compatibility mode
504 */
505#define	COMPAT_PIO(pp) (((pp)->io_mode == ECPP_PIO) &&		\
506		    ((pp)->current_mode == ECPP_CENTRONICS ||	\
507		    (pp)->current_mode == ECPP_COMPAT_MODE))
508
509#define	COMPAT_DMA(pp) (((pp)->io_mode == ECPP_DMA) &&		\
510		    ((pp)->current_mode == ECPP_CENTRONICS ||	\
511		    (pp)->current_mode == ECPP_COMPAT_MODE))
512
513/*
514 * Other useful macros
515 */
516#define	NELEM(a)	(sizeof (a) / sizeof (*(a)))
517
518#ifdef	__cplusplus
519}
520#endif
521
522#endif	/* _SYS_ECPPVAR_H */
523