summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/ecppvar.h
blob: e17be987311c832fc45ffd159ad78f65a6799430 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_SYS_ECPPVAR_H
#define	_SYS_ECPPVAR_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/note.h>

#ifdef	__cplusplus
extern "C" {
#endif

struct ecppunit;

/*
 * Hardware-abstraction structure
 */
struct ecpp_hw {
	int	(*map_regs)(struct ecppunit *);		/* map registers */
	void	(*unmap_regs)(struct ecppunit *);	/* unmap registers */
	int	(*config_chip)(struct ecppunit *);	/* configure SuperIO */
	void	(*config_mode)(struct ecppunit *);	/* config new mode */
	void	(*mask_intr)(struct ecppunit *);	/* mask interrupts */
	void	(*unmask_intr)(struct ecppunit *);	/* unmask interrupts */
	int	(*dma_start)(struct ecppunit *);	/* start DMA transfer */
	int	(*dma_stop)(struct ecppunit *, size_t *); /* stop DMA xfer */
	size_t	(*dma_getcnt)(struct ecppunit *);	/* get DMA counter */
	ddi_dma_attr_t	*attr;				/* DMA attributes */
};

#define	ECPP_MAP_REGS(pp)		(pp)->hw->map_regs(pp)
#define	ECPP_UNMAP_REGS(pp)		(pp)->hw->unmap_regs(pp)
#define	ECPP_CONFIG_CHIP(pp)		(pp)->hw->config_chip(pp)
#define	ECPP_CONFIG_MODE(pp)		(pp)->hw->config_mode(pp)
#define	ECPP_MASK_INTR(pp)		(pp)->hw->mask_intr(pp)
#define	ECPP_UNMASK_INTR(pp)		(pp)->hw->unmask_intr(pp)
#define	ECPP_DMA_START(pp)		(pp)->hw->dma_start(pp)
#define	ECPP_DMA_STOP(pp, cnt)		(pp)->hw->dma_stop(pp, cnt)
#define	ECPP_DMA_GETCNT(pp)		(pp)->hw->dma_getcnt(pp)

/* NSC 87332/97317 and EBus DMAC */
struct ecpp_ebus {
	struct config_reg	*c_reg; 	/* configuration registers */
	ddi_acc_handle_t	c_handle;	/* handle for conf regs */
	struct cheerio_dma_reg	*dmac;		/* ebus dmac registers */
	ddi_acc_handle_t	d_handle;	/* handle for dmac registers */
	struct config2_reg	*c2_reg; 	/* 97317 2nd level conf regs */
	ddi_acc_handle_t	c2_handle;	/* handle for c2_reg */
};

/* Southbridge SuperIO and 8237 DMAC */
struct ecpp_m1553 {
	struct isaspace		*isa_space;	/* all of isa space */
	ddi_acc_handle_t	d_handle;	/* handle for isa space */
	uint8_t			chn;		/* 8237 dma channel */
	int			isadma_entered;	/* Southbridge DMA workaround */
};

#if defined(__x86)
struct ecpp_x86 {
	uint8_t			chn;
};
#endif

/*
 * Hardware binding structure
 */
struct ecpp_hw_bind {
	char		*name;		/* binding name */
	struct ecpp_hw	*hw;		/* hw description */
	char		*info;		/* info string */
};

/*
 * ecpp soft state structure
 */
struct ecppunit {
	kmutex_t	umutex;		/* lock for this structure */
	int		instance;	/* instance number */
	dev_info_t	*dip;		/* device information */
	ddi_iblock_cookie_t ecpp_trap_cookie;	/* interrupt cookie */
	boolean_t	e_busy;		/* ecpp busy flag */
	kcondvar_t	pport_cv;	/* cv to signal idle state */
	/*
	 * common SuperIO registers
	 */
	struct info_reg		*i_reg; 	/* info registers */
	struct fifo_reg		*f_reg; 	/* fifo register */
	ddi_acc_handle_t	i_handle;
	ddi_acc_handle_t	f_handle;
	/*
	 * DMA support
	 */
	ddi_dma_handle_t	dma_handle;	/* DMA handle */
	ddi_dma_cookie_t	dma_cookie;	/* current cookie */
	uint_t			dma_cookie_count;	/* # of cookies */
	uint_t			dma_nwin;	/* # of DMA windows */
	uint_t			dma_curwin;	/* current window number */
	uint_t			dma_dir;	/* transfer direction */
	/*
	 * hardware-dependent stuff
	 */
	struct ecpp_hw	*hw;		/* operations/attributes */
	union {				/* hw-dependent data */
		struct ecpp_ebus	ebus;
		struct ecpp_m1553	m1553;
#if defined(__x86)
		struct ecpp_x86 	x86;
#endif
	} uh;
	/*
	 * DDI/STREAMS stuff
	 */
	boolean_t	oflag;		/* instance open flag */
	queue_t		*readq;		/* pointer to readq */
	queue_t		*writeq;	/* pointer to writeq */
	mblk_t		*msg;		/* current message block */
	boolean_t	suspended;	/* driver suspended status */
	/*
	 * Modes of operation
	 */
	int		current_mode;	/* 1284 mode */
	uchar_t		current_phase;	/* 1284 phase */
	uchar_t		backchannel;	/* backchannel mode supported */
	uchar_t		io_mode;	/* transfer mode: PIO/DMA */
	/*
	 * Ioctls support
	 */
	struct ecpp_transfer_parms xfer_parms;	/* transfer parameters */
	struct ecpp_regs regs;		/* control/status registers */
	uint8_t		saved_dsr;	/* store the dsr returned from TESTIO */
	boolean_t	timeout_error;	/* store the timeout for GETERR */
	uchar_t		port;		/* xfer type: dma/pio/tfifo */
	struct prn_timeouts prn_timeouts; /* prnio timeouts */
	/*
	 * ecpp.conf parameters
	 */
	uchar_t		init_seq;	/* centronics init seq */
	uint32_t	wsrv_retry;	/* delay (ms) before next wsrv */
	uint32_t	wait_for_busy;	/* wait for BUSY to deassert */
	uint32_t	data_setup_time; /* pio centronics handshake */
	uint32_t	strobe_pulse_width; /* pio centronics handshake */
	uint8_t		fast_centronics; /* DMA/PIO centronics */
	uint8_t		fast_compat;	/* DMA/PIO 1284 compatible mode */
	uint32_t	ecp_rev_speed;	/* rev xfer speed in ECP, bytes/sec */
	uint32_t	rev_watchdog;	/* rev xfer watchdog period, ms */
	/*
	 * Timeouts
	 */
	timeout_id_t	timeout_id;	/* io transfers timer */
	timeout_id_t	fifo_timer_id;	/* drain SuperIO FIFO */
	timeout_id_t	wsrv_timer_id;	/* wsrv timeout */
	/*
	 * Softintr data
	 */
	ddi_softintr_t	softintr_id;
	int		softintr_flags;	/* flags indicating softintr task */
	uint8_t		softintr_pending;
	/*
	 * Misc stuff
	 */
	caddr_t		ioblock;	/* transfer buffer block */
	size_t		xfercnt;	/* # of bytes to transfer */
	size_t		resid;		/* # of bytes not transferred */
	caddr_t		next_byte;	/* next byte for PIO transfer */
	caddr_t		last_byte;	/* last byte for PIO transfer */
	uint32_t	ecpp_drain_counter;	/* allows fifo to drain */
	uchar_t		dma_cancelled;	/* flushed while dma'ing */
	uint8_t		tfifo_intr;	/* TFIFO switch interrupt workaround */
	size_t		nread;		/* requested read */
	size_t		last_dmacnt;	/* DMA counter value for rev watchdog */
	uint32_t	rev_timeout_cnt; /* number of watchdog invocations */
	/*
	 * Spurious interrupt detection
	 */
	hrtime_t	lastspur;	/* last time spurious intrs started */
	long		nspur;		/* spurious intrs counter */
	/*
	 * Statistics
	 */
	kstat_t		*ksp;		/* kstat pointer */
	kstat_t		*intrstats;	/* kstat interrupt counter */
	/*
	 * number of bytes, transferred in and out in each mode
	 */
	uint32_t	ctxpio_obytes;
	uint32_t	obytes[ECPP_EPP_MODE+1];
	uint32_t	ibytes[ECPP_EPP_MODE+1];
	/*
	 * other stats
	 */
	uint32_t	to_mode[ECPP_EPP_MODE+1]; /* # transitions to mode */
	uint32_t	xfer_tout;	/* # transfer timeouts */
	uint32_t	ctx_cf;		/* # periph check failures */
	uint32_t	joblen;		/* of bytes xfer'd since open */
	uint32_t	isr_reattempt_high;	/* max times isr has looped */
	/*
	 * interrupt stats
	 */
	uint_t		intr_hard;
	uint_t		intr_spurious;
	uint_t		intr_soft;
	/*
	 * identify second register set for ecp mode on Sx86
	 */
	int		noecpregs;
};

_NOTE(MUTEX_PROTECTS_DATA(ecppunit::umutex, ecppunit))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::dip))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::instance))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::i_reg))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::f_reg))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::i_handle))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::f_handle))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::ecpp_trap_cookie))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::readq))
_NOTE(DATA_READABLE_WITHOUT_LOCK(ecppunit::writeq))

/*
 * current_phase values
 */
#define	ECPP_PHASE_INIT		0x00	/* initialization */
#define	ECPP_PHASE_NEGO		0x01	/* negotiation */
#define	ECPP_PHASE_TERM		0x02	/* termination */
#define	ECPP_PHASE_PO		0x03	/* power-on */

#define	ECPP_PHASE_C_FWD_DMA	0x10	/* cntrx/compat fwd dma xfer */
#define	ECPP_PHASE_C_FWD_PIO	0x11	/* cntrx/compat fwd PIO xfer */
#define	ECPP_PHASE_C_IDLE	0x12	/* cntrx/compat idle */

#define	ECPP_PHASE_NIBT_REVDATA	0x20	/* nibble/byte reverse data */
#define	ECPP_PHASE_NIBT_AVAIL	0x21	/* nibble/byte reverse data available */
#define	ECPP_PHASE_NIBT_NAVAIL	0x22	/* nibble/byte reverse data not avail */
#define	ECPP_PHASE_NIBT_REVIDLE	0x22	/* nibble/byte reverse idle */
#define	ECPP_PHASE_NIBT_REVINTR	0x23	/* nibble/byte reverse interrupt */

#define	ECPP_PHASE_ECP_SETUP	0x30	/* ecp setup */
#define	ECPP_PHASE_ECP_FWD_XFER	0x31	/* ecp forward transfer */
#define	ECPP_PHASE_ECP_FWD_IDLE	0x32	/* ecp forward idle */
#define	ECPP_PHASE_ECP_FWD_REV	0x33	/* ecp forward to reverse */
#define	ECPP_PHASE_ECP_REV_XFER	0x34	/* ecp reverse transfer */
#define	ECPP_PHASE_ECP_REV_IDLE	0x35	/* ecp reverse idle */
#define	ECPP_PHASE_ECP_REV_FWD	0x36	/* ecp reverse to forward */

#define	ECPP_PHASE_EPP_INIT_IDLE 0x40	/* epp init phase */
#define	ECPP_PHASE_EPP_IDLE	0x41	/* epp all-round phase */

#define	FAILURE_PHASE		0x80
#define	UNDEFINED_PHASE		0x81

/* ecpp return values */
#define	SUCCESS		1
#define	FAILURE		2

/* ecpp e_busy states */
#define	ECPP_IDLE	1 /* No ongoing transfers */
#define	ECPP_BUSY	2 /* Ongoing transfers on the cable */
#define	ECPP_DATA	3 /* Not used */
#define	ECPP_ERR	4 /* Bad status in Centronics mode */
#define	ECPP_FLUSH	5 /* Currently flushing the q */

#define	TRUE		1
#define	FALSE		0

/* message type */
#define	ECPP_BACKCHANNEL	0x45

/* transfer modes */
#define	ECPP_DMA		0x1
#define	ECPP_PIO		0x2

/* tuneable timing defaults */
#define	CENTRONICS_RETRY	750	/* 750 milliseconds */
#define	WAIT_FOR_BUSY		1000	/* 1000 microseconds */
#define	SUSPEND_TOUT		10	/* # seconds before suspend fails */

/* Centronics hanshaking defaults */
#define	DATA_SETUP_TIME		2	/* 2 uSec Data Setup Time (2x min) */
#define	STROBE_PULSE_WIDTH	2	/* 2 uSec Strobe Pulse (2x min) */

/* 1284 Extensibility Request values */
#define	ECPP_XREQ_NIBBLE	0x00    /* Nibble Mode Rev Channel Transfer */
#define	ECPP_XREQ_BYTE		0x01    /* Byte Mode Rev Channel Transfer */
#define	ECPP_XREQ_ID		0x04    /* Request Device ID */
#define	ECPP_XREQ_ECP		0x10    /* Request ECP Mode */
#define	ECPP_XREQ_ECPRLE	0x30    /* Request ECP Mode with RLE */
#define	ECPP_XREQ_EPP		0x40	/* Request EPP Mode */
#define	ECPP_XREQ_XLINK		0x80    /* Request Extensibility Link */

/* softintr flags */
#define	ECPP_SOFTINTR_PIONEXT	0x1	/* write next byte in PIO mode */

/* Stream  defaults */
#define	IO_BLOCK_SZ	1024 * 128	/* transfer buffer size */
#define	ECPPHIWAT	32 * 1024  * 6
#define	ECPPLOWAT	32 * 1024  * 4

/* Loop timers */
#define	ECPP_REG_WRITE_MAX_LOOP	100	/* cpu is faster than superio */
#define	ECPP_ISR_MAX_DELAY	30	/* DMAC slow PENDING status */

/* misc constants */
#define	ECPP_FIFO_SZ		16	/* FIFO size */
#define	FIFO_DRAIN_PERIOD	250000	/* max FIFO drain period in usec */
#define	NIBBLE_REV_BLKSZ	1024	/* send up to # bytes at a time */
#define	FWD_TIMEOUT_DEFAULT	90	/* forward xfer timeout in seconds */
#define	REV_TIMEOUT_DEFAULT	0	/* reverse xfer timeout in seconds */

/* ECP mode constants */
#define	ECP_REV_BLKSZ		1024	/* send up to # bytes at a time */
#define	ECP_REV_BLKSZ_MAX	(4 * 1024)	/* maximum of # bytes */
#define	ECP_REV_SPEED		(1 * 1024 * 1024)	/* bytes/sec */
#define	ECP_REV_MINTOUT		5	/* min ECP rev xfer timeout in ms */
#define	REV_WATCHDOG		100	/* poll DMA counter every # ms */

/* spurious interrupt detection */
#define	SPUR_CRITICAL		100	/* number of interrupts... */
#define	SPUR_PERIOD		1000000000 /* in # ns */

/*
 * Copyin/copyout states
 */
#define	ECPP_STRUCTIN		0
#define	ECPP_STRUCTOUT		1
#define	ECPP_ADDRIN 		2
#define	ECPP_ADDROUT		3

/*
 * As other ioctls require the same structure, put inner struct's into union
 */
struct ecpp_copystate {
	int	state;		/* see above */
	void	*uaddr;		/* user address of the following structure */
	union {
		struct ecpp_device_id		devid;
		struct prn_1284_device_id	prn_devid;
		struct prn_interface_info	prn_if;
	} un;
};

/*
 * The structure is dynamically created for each M_IOCTL and is bound to mblk
 */
_NOTE(SCHEME_PROTECTS_DATA("unique per call", ecpp_copystate))

/* kstat structure */
struct ecppkstat {
	/*
	 * number of bytes, transferred in and out in each mode
	 */
	struct kstat_named	ek_ctx_obytes;
	struct kstat_named	ek_ctxpio_obytes;
	struct kstat_named	ek_nib_ibytes;
	struct kstat_named	ek_ecp_obytes;
	struct kstat_named	ek_ecp_ibytes;
	struct kstat_named	ek_epp_obytes;
	struct kstat_named	ek_epp_ibytes;
	struct kstat_named	ek_diag_obytes;
	/*
	 * number of transitions to particular mode
	 */
	struct kstat_named	ek_to_ctx;
	struct kstat_named	ek_to_nib;
	struct kstat_named	ek_to_ecp;
	struct kstat_named	ek_to_epp;
	struct kstat_named	ek_to_diag;
	/*
	 * other stats
	 */
	struct kstat_named	ek_xfer_tout;	/* # transfer timeouts */
	struct kstat_named	ek_ctx_cf;	/* # periph check failures */
	struct kstat_named	ek_joblen;	/* # bytes xfer'd since open */
	struct kstat_named	ek_isr_reattempt_high;	/* max # times */
							/* isr has looped */
	struct kstat_named	ek_mode;	/* 1284 mode */
	struct kstat_named	ek_phase;	/* 1284 ECP phase */
	struct kstat_named	ek_backchan;	/* backchannel mode supported */
	struct kstat_named	ek_iomode;	/* transfer mode: pio/dma */
	struct kstat_named	ek_state;	/* ecpp busy flag */
};

/* Macros for superio programming */
#define	PP_PUTB(x, y, z)  	ddi_put8(x, y, z)
#define	PP_GETB(x, y)		ddi_get8(x, y)

#define	DSR_READ(pp)		PP_GETB((pp)->i_handle, &(pp)->i_reg->dsr)
#define	DCR_READ(pp)		PP_GETB((pp)->i_handle, &(pp)->i_reg->dcr)
#define	ECR_READ(pp)		\
	(pp->noecpregs) ? 0xff : PP_GETB((pp)->f_handle, &(pp)->f_reg->ecr)
#define	DATAR_READ(pp)		PP_GETB((pp)->i_handle, &(pp)->i_reg->ir.datar)
#define	DFIFO_READ(pp)		\
	(pp->noecpregs) ? 0xff : PP_GETB((pp)->f_handle, &(pp)->f_reg->fr.dfifo)
#define	TFIFO_READ(pp)		\
	(pp->noecpregs) ? 0xff : PP_GETB((pp)->f_handle, &(pp)->f_reg->fr.tfifo)

#define	DCR_WRITE(pp, val)	PP_PUTB((pp)->i_handle, &(pp)->i_reg->dcr, val)
#define	ECR_WRITE(pp, val)	\
	if (!pp->noecpregs) PP_PUTB((pp)->f_handle, &(pp)->f_reg->ecr, val)
#define	DATAR_WRITE(pp, val)	\
			PP_PUTB((pp)->i_handle, &(pp)->i_reg->ir.datar, val)
#define	DFIFO_WRITE(pp, val)	\
	if (!pp->noecpregs) PP_PUTB((pp)->f_handle, &(pp)->f_reg->fr.dfifo, val)
#define	TFIFO_WRITE(pp, val)	\
	if (!pp->noecpregs) PP_PUTB((pp)->f_handle, &(pp)->f_reg->fr.tfifo, val)

/*
 * Macros to manipulate register bits
 */
#define	OR_SET_BYTE_R(handle, addr, val) \
{		\
	uint8_t tmpval;					\
	tmpval = ddi_get8(handle, (uint8_t *)addr);	\
	tmpval |= val;					\
	ddi_put8(handle, (uint8_t *)addr, tmpval);	\
}

#define	OR_SET_LONG_R(handle, addr, val) \
{		\
	uint32_t tmpval;				\
	tmpval = ddi_get32(handle, (uint32_t *)addr);	\
	tmpval |= val;					\
	ddi_put32(handle, (uint32_t *)addr, tmpval);	\
}

#define	AND_SET_BYTE_R(handle, addr, val) \
{		\
	uint8_t tmpval;					\
	tmpval = ddi_get8(handle, (uint8_t *)addr);	\
	tmpval &= val; 					\
	ddi_put8(handle, (uint8_t *)addr, tmpval);	\
}

#define	AND_SET_LONG_R(handle, addr, val) \
{		\
	uint32_t tmpval;				\
	tmpval = ddi_get32(handle, (uint32_t *)addr);	\
	tmpval &= val; 					\
	ddi_put32(handle, (uint32_t *)addr, tmpval);	\
}

#define	NOR_SET_LONG_R(handle, addr, val, mask) \
{		\
	uint32_t tmpval;				\
	tmpval = ddi_get32(handle, (uint32_t *)addr);	\
	tmpval &= ~(mask);				\
	tmpval |= val;					\
	ddi_put32(handle, (uint32_t *)addr, tmpval);	\
}

/*
 * Macros for Cheerio/RIO DMAC programming
 */
#define	SET_DMAC_CSR(pp, val)	ddi_put32(pp->uh.ebus.d_handle, \
				((uint32_t *)&pp->uh.ebus.dmac->csr), \
				((uint32_t)val))
#define	GET_DMAC_CSR(pp)	ddi_get32(pp->uh.ebus.d_handle, \
				(uint32_t *)&(pp->uh.ebus.dmac->csr))

#define	SET_DMAC_ACR(pp, val)	ddi_put32(pp->uh.ebus.d_handle, \
				((uint32_t *)&pp->uh.ebus.dmac->acr), \
				((uint32_t)val))

#define	GET_DMAC_ACR(pp)	ddi_get32(pp->uh.ebus.d_handle, \
				(uint32_t *)&pp->uh.ebus.dmac->acr)

#define	SET_DMAC_BCR(pp, val)	ddi_put32(pp->uh.ebus.d_handle, \
				((uint32_t *)&pp->uh.ebus.dmac->bcr), \
				((uint32_t)val))

#define	GET_DMAC_BCR(pp)	ddi_get32(pp->uh.ebus.d_handle, \
				((uint32_t *)&pp->uh.ebus.dmac->bcr))

#define	DMAC_RESET_TIMEOUT	10000	/* in usec */

/*
 * Macros to distinguish between PIO and DMA Compatibility mode
 */
#define	COMPAT_PIO(pp) (((pp)->io_mode == ECPP_PIO) &&		\
		    ((pp)->current_mode == ECPP_CENTRONICS ||	\
		    (pp)->current_mode == ECPP_COMPAT_MODE))

#define	COMPAT_DMA(pp) (((pp)->io_mode == ECPP_DMA) &&		\
		    ((pp)->current_mode == ECPP_CENTRONICS ||	\
		    (pp)->current_mode == ECPP_COMPAT_MODE))

/*
 * Other useful macros
 */
#define	NELEM(a)	(sizeof (a) / sizeof (*(a)))
#define	offsetof(s, m)	((size_t)(&(((s *)0)->m)))

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_ECPPVAR_H */