xref: /illumos-gate/usr/src/uts/common/io/i8237A.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
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 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 /*	Copyright (c) 1988, 1989 Intel Corp.			*/
32 /*	All Rights Reserved	*/
33 
34 /*
35  * Set features for each architecture.  List of features:
36  *	ADDR_32:	Address is 32 bits
37  *	COUNT_24:	Count is 24 bits
38  *	DMA_4CSCD:	DMA channel 4 is used for cascade of channels 0-3)
39  *	DMA_INTR:	DMA interrupt is available (always with DMA_BUF_CHAIN)
40  *	DMA_BUF_CHAIN:	DMA buffer chaining is available (always with DMA_INTR)
41  *	MEM_TO_MEM:	Memory to memory transfers available
42  *	NO_PROG_WIDTH:	Channel data width is NOT programmable
43  *	SCATER_GATHER	Scatter-gather DMA is available (code not implemented)
44  *	ISA_MODE	Standard ISA modes available
45  *	EISA_EXT_MODE:	EISA extension modes available
46  */
47 
48 /*
49  * Address is 24 bits (default) with no carry between lo word and hi byte
50  * Count is 16 bits (default)
51  */
52 #define	DMA_4CSCD
53 #define	NO_PROG_WIDTH
54 #define	ISA_MODE
55 
56 #include <sys/types.h>
57 #include <sys/cpuvar.h>
58 #include <sys/disp.h>
59 #include <sys/sunddi.h>
60 #include <sys/cmn_err.h>
61 #include <sys/dma_engine.h>
62 #include <sys/dma_i8237A.h>
63 
64 #if defined(DEBUG)
65 #include <sys/promif.h>
66 static int i8237debug = 0;
67 #define	dprintf(x)	if (i8237debug) (void)prom_printf x
68 #else
69 #define	dprintf(x)
70 #endif	/* defined(DEBUG) */
71 
72 
73 extern int EISA_chaining;
74 
75 /*
76  * data structures for maintaining the DMACs
77  */
78 static kmutex_t dma_engine_lock;
79 static struct d37A_chan_reg_addr chan_addr[] = { D37A_BASE_REGS_VALUES };
80 static ushort_t d37A_chnl_path[] = {
81 	DMAE_PATH_8,	/* first 4 DMA channels default to 8-bit xfers */
82 	DMAE_PATH_8,
83 	DMAE_PATH_8,
84 	DMAE_PATH_8,
85 	0,
86 	DMAE_PATH_16,	/* last 3 DMA channels default to 16-bit xfers */
87 	DMAE_PATH_16,
88 	DMAE_PATH_16};
89 static ushort_t d37A_chnl_mode[] = {
90 	DMAE_TRANS_SNGL, DMAE_TRANS_SNGL, DMAE_TRANS_SNGL, DMAE_TRANS_SNGL,
91 #ifdef DMA_4CSCD
92 	DMAE_TRANS_CSCD,
93 #else 	/* !DMA_4CSCD */
94 	DMAE_TRANS_SNGL,
95 #endif	/* !DMA_4CSCD */
96 	DMAE_TRANS_SNGL, DMAE_TRANS_SNGL, DMAE_TRANS_SNGL};
97 #ifdef DMA_BUF_CHAIN
98 static ddi_dma_cookie_t *d37A_next_cookie[] =
99 	{0, 0, 0, 0, 0, 0, 0, 0};
100 #endif	/* DMA_BUF_CHAIN */
101 
102 
103 #ifdef DMA_INTR
104 static uint_t d37A_intr(caddr_t);
105 #endif
106 static int d37A_set_mode(struct ddi_dmae_req *, int);
107 static int d37A_write_addr(ulong_t, int);
108 static ulong_t d37A_read_addr(int);
109 static int d37A_write_count(long, int);
110 static long d37A_read_count(int);
111 
112 #ifdef DMA_BUF_CHAIN
113 static void dEISA_setchain(ddi_dma_cookie_t *cp, int chnl);
114 #endif
115 
116 /*
117  *  Routine: d37A_init()
118  *  purpose: initializes the 8237A.
119  *  caller:  dma_init()
120  *  calls:   d37A macros, d37A_init()
121  */
122 
123 /*ARGSUSED*/
124 int
125 d37A_init(dev_info_t *dip)
126 {
127 #ifdef DMA_INTR
128 	ddi_iblock_cookie_t iblk_cookie = 0;
129 	int	error;
130 
131 	if ((error = ddi_add_intr(dip, (uint_t)0, &iblk_cookie,
132 	    (ddi_idevice_cookie_t *)0, d37A_intr, (caddr_t)NULL)) !=
133 	    DDI_SUCCESS) {
134 		if (error != DDI_INTR_NOTFOUND)
135 			cmn_err(CE_WARN, "!d37A_init: cannot add dma intr\n");
136 		EISA_chaining = 0;
137 	}
138 	mutex_init(&dma_engine_lock, NULL, MUTEX_DRIVER, (void *)iblk_cookie);
139 #else	/* !DMA_INTR */
140 	mutex_init(&dma_engine_lock, NULL, MUTEX_DRIVER, NULL);
141 #endif	/* !DMA_INTR */
142 
143 	return (DDI_SUCCESS);
144 }
145 
146 /*
147  *  Routine: d37A_valid()
148  *  purpose: validates the channel to be acquired.
149  *  caller:  i_dmae_acquire()
150  *  calls:
151  */
152 
153 int
154 d37A_dma_valid(int chnl)
155 {
156 #ifdef DMA_4CSCD
157 	if (chnl == 4)
158 		return (0);
159 #endif	/* DMA_4CSCD */
160 	return (1);
161 }
162 
163 /*
164  *  Routine: d37A_release()
165  *  purpose: resets the 8237A mode.
166  *  caller:  i_dmae_free()
167  *  calls:
168  */
169 
170 void
171 d37A_dma_release(int chnl)
172 {
173 #ifdef DMA_4CSCD
174 	if (chnl == 4)
175 		return;
176 #endif	/* DMA_4CSCD */
177 	d37A_chnl_mode[chnl] = DMAE_TRANS_SNGL;
178 }
179 
180 /*
181  *  routine: d37A_dma_disable()
182  *  purpose: Prevent the DMAC from responding to external hardware
183  *		requests for DMA service on the given channel
184  *  caller:  dma_disable()
185  *  calls:   d37A macros
186  */
187 void
188 d37A_dma_disable(int chnl)
189 {
190 	dprintf(("d37A_dma_disable: chnl=%d mask_reg=0x%x\n",
191 	    chnl, chan_addr[chnl].mask_reg));
192 
193 	outb(chan_addr[chnl].mask_reg, (chnl & 3) | DMA_SETMSK);
194 }
195 
196 
197 /*
198  *  routine: d37A_dma_enable()
199  *  purpose: Enable to DMAC to respond to hardware requests for DMA
200  *		service on the specified channel.
201  *  caller:  dma_enable()
202  *  calls:   d37A macros
203  */
204 
205 void
206 d37A_dma_enable(int chnl)
207 {
208 	dprintf(("d37A_dma_enable: chnl=%d mask_reg=0x%x val=0x%x\n",
209 	    chnl, chan_addr[chnl].mask_reg, chnl & 3));
210 
211 /*	mutex_enter(&dma_engine_lock);	*/
212 	outb(chan_addr[chnl].mask_reg, chnl & 3);
213 /*	mutex_exit(&dma_engine_lock);	*/
214 }
215 
216 
217 /*
218  *  routine: d37A_get_best_mode()
219  *  purpose: stub routine - determine optimum transfer method
220  *  caller:  dma_get_best_mode().
221  *  calls:
222  */
223 /* ARGSUSED */
224 uchar_t
225 d37A_get_best_mode(struct ddi_dmae_req *dmaereqp)
226 {
227 	return (DMAE_CYCLES_2);
228 }
229 
230 #ifdef DMA_INTR
231 /*
232  *  routine: d37A_intr()
233  *  purpose: stub routine
234  *  caller:
235  *  calls:  dma_intr().
236  */
237 /*ARGSUSED*/
238 static uint_t
239 d37A_intr(caddr_t arg)
240 {
241 	int chnl, istate, nstate;
242 	uint_t mask;
243 
244 	if ((istate = (inb(EISA_DMAIS) & 0xef)) != 0) {
245 		/* channel 4 can't interrupt */
246 		chnl = 0;
247 		nstate = istate;
248 		mutex_enter(&dma_engine_lock);
249 		do {
250 			if (istate & 1) {
251 				dEISA_setchain(d37A_next_cookie[chnl], chnl);
252 #ifdef DEBUG
253 				if (chnl < 4)
254 					mask = inb(DMAC1_ALLMASK) >> (chnl);
255 				else
256 					mask = inb(DMAC2_ALLMASK) >> (chnl - 4);
257 				if (mask & 1)
258 prom_printf("eisa: dma buffer chaining failure chnl %d!\n", chnl);
259 
260 #endif	/* DEBUG */
261 			}
262 			chnl++;
263 			istate >>= 1;
264 		} while (istate);
265 		chnl = 0;
266 		do {
267 			if ((nstate & 1) && d37A_next_cookie[chnl])
268 				d37A_next_cookie[chnl] = _dmae_nxcookie(chnl);
269 			chnl++;
270 			nstate >>= 1;
271 		} while (nstate);
272 		mutex_exit(&dma_engine_lock);
273 		return (DDI_INTR_CLAIMED);
274 	}
275 	return (DDI_INTR_UNCLAIMED);
276 }
277 #endif	/* DMA_INTR */
278 
279 
280 #ifdef DMA_BUF_CHAIN
281 /*
282  *  routine: dEISA_setchain()
283  *  purpose: Set next buffer address/count from chain
284  *  caller:  d37A_intr()
285  *  calls:   d37A macros
286  */
287 static void
288 dEISA_setchain(ddi_dma_cookie_t *cp, int chnl)
289 {
290 	if (cp) {
291 		dprintf(("dEISA_setchain: chnl=%d next_addr=%x count=%lx\n",
292 		    chnl, cp->dmac_address, cp->dmac_size));
293 		(void) d37A_write_addr(cp->dmac_address, chnl);
294 		(void) d37A_write_count(cp->dmac_size, chnl);
295 		outb(chan_addr[chnl].scm_reg, chnl | EISA_ENCM | EISA_CMOK);
296 	} else {
297 		/*
298 		 *  clear chain enable bit
299 		 */
300 		outb(chan_addr[chnl].scm_reg, chnl);
301 		dprintf(("dEISA_setchain: chnl=%d end\n", chnl));
302 	}
303 }
304 #endif	/* DMA_BUF_CHAIN */
305 
306 
307 /*
308  *  routine: d37A_prog_chan()
309  *  purpose: program the Mode registers and the Base registers of a
310  *		DMA channel for a subsequent hardware-initiated transfer.
311  *  caller:  dma_prog_chan()
312  *  calls:   d37A_write_addr(), d37A_write_count(), d37A macros.
313  */
314 
315 int
316 d37A_prog_chan(struct ddi_dmae_req *dmaereqp, ddi_dma_cookie_t *cp, int chnl)
317 {
318 	if (d37A_chnl_mode[chnl] == DMAE_TRANS_CSCD) {
319 		dprintf(("d37A_prog_chan err: chnl=%d in cascade mode\n",
320 		    chnl));
321 		return (DDI_FAILURE);
322 	}
323 #ifndef MEM_TO_MEM
324 	if (dmaereqp && dmaereqp->der_dest == DMAE_DEST_MEM) {
325 dprintf(("d37A_prog_chan err: memory to memory mode not supported.\n"));
326 		return (DDI_FAILURE);
327 	}
328 #endif	/* !MEM_TO_MEM */
329 
330 	dprintf(("d37A_prog_chan: chnl=%d dmaereq=%p\n",
331 	    chnl, (void *)dmaereqp));
332 
333 	if (dmaereqp) {
334 		switch (chnl) {
335 		case DMAE_CH0:
336 		case DMAE_CH1:
337 		case DMAE_CH2:
338 		case DMAE_CH3:
339 #ifdef NO_PROG_WIDTH
340 			if (dmaereqp->der_path &&
341 			    dmaereqp->der_path != DMAE_PATH_8) {
342 dprintf(("d37A_prog_chan err: chnl %d not programmed.\n", chnl));
343 				return (DDI_FAILURE);
344 			}
345 #endif	/* NO_PROG_WIDTH */
346 			break;
347 
348 #ifndef DMA_4CSCD
349 		case DMAE_CH4:
350 #endif	/* !DMA_4CSCD */
351 		case DMAE_CH5:
352 		case DMAE_CH6:
353 		case DMAE_CH7:
354 #ifdef NO_PROG_WIDTH
355 			if (dmaereqp->der_path &&
356 			    dmaereqp->der_path != DMAE_PATH_16) {
357 dprintf(("d37A_prog_chan err: chnl %d not programmed.\n", chnl));
358 				return (DDI_FAILURE);
359 			}
360 #endif	/* NO_PROG_WIDTH */
361 			break;
362 
363 		default:
364 dprintf(("d37A_prog_chan err: chnl %d not programmed.\n", chnl));
365 			return (DDI_FAILURE);
366 		}
367 	} else
368 		chnl &= 3;
369 	mutex_enter(&dma_engine_lock);
370 
371 	d37A_dma_disable(chnl);
372 	if (dmaereqp)
373 		(void) d37A_set_mode(dmaereqp, chnl);
374 
375 	if (cp) {
376 		(void) d37A_write_addr(cp->dmac_address, chnl);
377 		(void) d37A_write_count(cp->dmac_size, chnl);
378 
379 #ifdef DMA_BUF_CHAIN
380 		if (dmaereqp && dmaereqp->der_bufprocess == DMAE_BUF_CHAIN &&
381 		    (d37A_next_cookie[chnl] = _dmae_nxcookie(chnl))) {
382 			/*
383 			 * i/o operation has more than 1 cookie
384 			 * so enable dma buffer chaining
385 			 */
386 			drv_usecwait(10);
387 			outb(chan_addr[chnl].scm_reg, chnl | EISA_ENCM);
388 			drv_usecwait(15);
389 			dEISA_setchain(d37A_next_cookie[chnl], chnl);
390 			d37A_next_cookie[chnl] = _dmae_nxcookie(chnl);
391 		}
392 #endif	/* DMA_BUF_CHAIN */
393 	}
394 	mutex_exit(&dma_engine_lock);
395 	return (DDI_SUCCESS);
396 }
397 
398 
399 /*
400  *  routine: d37A_dma_swsetup()
401  *  purpose: program the Mode registers and the Base register for the
402  *		specified channel.
403  *  caller:  dma_swsetup()
404  *  calls:   d37A_write_addr(), d37A_write_count(), d37A macros.
405  */
406 
407 int
408 d37A_dma_swsetup(struct ddi_dmae_req *dmaereqp, ddi_dma_cookie_t *cp, int chnl)
409 {
410 	if (d37A_chnl_mode[chnl] == DMAE_TRANS_CSCD) {
411 		dprintf(("d37A_dma_swsetup err: chnl %d not programmed\n",
412 		    chnl));
413 		return (DDI_FAILURE);
414 	}
415 
416 	dprintf(("d37A_dma_swsetup: chnl=%d dmaereq=%p.\n",
417 	    chnl, (void *)dmaereqp));
418 
419 	/* MUST BE IN BLOCK MODE FOR SOFTWARE INITIATED REQUESTS */
420 	if (dmaereqp->der_trans != DMAE_TRANS_BLCK)
421 		dmaereqp->der_trans = DMAE_TRANS_BLCK;
422 
423 	switch (chnl) {
424 	case DMAE_CH0:
425 	case DMAE_CH1:
426 	case DMAE_CH2:
427 	case DMAE_CH3:
428 #ifdef NO_PROG_WIDTH
429 		if (dmaereqp->der_path && dmaereqp->der_path != DMAE_PATH_8) {
430 dprintf(("d37A_dma_swsetup err: chnl %d not programmed.\n", chnl));
431 			return (DDI_FAILURE);
432 		}
433 #endif	/* NO_PROG_WIDTH */
434 		break;
435 
436 #ifndef DMA_4CSCD
437 	case DMAE_CH4:
438 #endif	/* !DMA_4CSCD */
439 	case DMAE_CH5:
440 	case DMAE_CH6:
441 	case DMAE_CH7:
442 #ifdef NO_PROG_WIDTH
443 		if (dmaereqp->der_path && dmaereqp->der_path != DMAE_PATH_16) {
444 dprintf(("d37A_dma_swsetup err: chnl %d not programmed.\n", chnl));
445 			return (DDI_FAILURE);
446 		}
447 #endif	/* NO_PROG_WIDTH */
448 		break;
449 
450 	default:
451 		dprintf(("d37A_dma_swsetup err: chnl %d not set up.\n", chnl));
452 		return (DDI_FAILURE);
453 	};
454 
455 	mutex_enter(&dma_engine_lock);
456 
457 	d37A_dma_disable(chnl);
458 	(void) d37A_set_mode(dmaereqp, chnl);
459 
460 	(void) d37A_write_addr(cp->dmac_address, chnl);
461 	(void) d37A_write_count(cp->dmac_size, chnl);
462 
463 #ifdef DMA_BUF_CHAIN
464 	if (dmaereqp->der_bufprocess == DMAE_BUF_CHAIN &&
465 	    (d37A_next_cookie[chnl] = _dmae_nxcookie(chnl))) {
466 		/*
467 		 * i/o operation has more than 1 cookie
468 		 * so enable dma buffer chaining
469 		 */
470 		outb(chan_addr[chnl].scm_reg, chnl | EISA_ENCM);
471 		dEISA_setchain(d37A_next_cookie[chnl], chnl);
472 		d37A_next_cookie[chnl] = _dmae_nxcookie(chnl);
473 	}
474 #endif	/* DMA_BUF_CHAIN */
475 	mutex_exit(&dma_engine_lock);
476 	return (DDI_SUCCESS);
477 }
478 
479 
480 /*
481  *  routine: d37A_dma_swstart()
482  *  purpose: SW start transfer setup on the indicated channel.
483  *  caller:  dma_swstart()
484  *  calls:   d37A_dma_enable(), d37A macros
485  */
486 
487 void
488 d37A_dma_swstart(int chnl)
489 {
490 	dprintf(("d37A_dma_swstart: chnl=%d\n", chnl));
491 
492 	mutex_enter(&dma_engine_lock);
493 	d37A_dma_enable(chnl);
494 	outb(chan_addr[chnl].reqt_reg, DMA_SETMSK | chnl); /* set request bit */
495 	mutex_exit(&dma_engine_lock);
496 }
497 
498 
499 /*
500  *  routine: d37A_dma_stop()
501  *  purpose: Stop any activity on the indicated channel.
502  *  caller:  dma_stop()
503  *  calls:   d37A macros
504  */
505 
506 void
507 d37A_dma_stop(int chnl)
508 {
509 	dprintf(("d37A_dma_stop: chnl=%d\n", chnl));
510 
511 	mutex_enter(&dma_engine_lock);
512 	d37A_dma_disable(chnl);
513 	outb(chan_addr[chnl].reqt_reg, chnl & 3);    /* reset request bit */
514 	mutex_exit(&dma_engine_lock);
515 }
516 
517 
518 /*
519  *  routine: d37A_get_chan_stat()
520  *  purpose: retrieve the Current Address and Count registers for the
521  *		specified channel.
522  *  caller:  dma_get_chan_stat()
523  *  calls:   d37A_read_addr(), d37A_read_count().
524  */
525 void
526 d37A_get_chan_stat(int chnl, ulong_t *addressp, int *countp)
527 {
528 	ulong_t taddr;
529 	int tcount;
530 
531 	mutex_enter(&dma_engine_lock);
532 	taddr = d37A_read_addr(chnl);
533 	tcount = d37A_read_count(chnl);
534 	mutex_exit(&dma_engine_lock);
535 	if (addressp)
536 		*addressp = taddr;
537 	if (countp)
538 		*countp = tcount;
539 	dprintf(("d37A_get_chan_stat: chnl=%d address=%lx count=%x\n",
540 	    chnl, taddr, tcount));
541 }
542 
543 
544 /*
545  *  routine: d37A_set_mode()
546  *  purpose: program the Mode registers of the
547  *		DMAC for a subsequent hardware-initiated transfer.
548  *  caller:  d37A_prog_chan(), d37A_dma_swsetup
549  *  calls:
550  */
551 
552 static int
553 d37A_set_mode(struct ddi_dmae_req *dmaereqp, int chnl)
554 {
555 	uchar_t mode = 0, emode = 0;
556 
557 #ifdef ISA_MODE
558 #if defined(lint)
559 	emode = emode;
560 #endif
561 	mode = chnl & 3;
562 
563 	switch (dmaereqp->der_command) {
564 	case DMAE_CMD_READ:
565 		mode |= DMAMODE_READ;
566 		break;
567 	case DMAE_CMD_WRITE:
568 		mode |= DMAMODE_WRITE;
569 		break;
570 	case DMAE_CMD_VRFY:
571 		mode |= DMAMODE_VERF;
572 		break;
573 	case DMAE_CMD_TRAN:
574 		mode |= 0x0C;	/* for Adaptec 1st party DMA on chnl 0 */
575 		break;
576 	default:
577 		return (DDI_FAILURE);
578 	}
579 
580 	if (dmaereqp->der_bufprocess == DMAE_BUF_AUTO)
581 		mode |= DMAMODE_AUTO;
582 
583 	if (dmaereqp->der_step == DMAE_STEP_DEC)
584 		mode |= DMAMODE_DECR;
585 
586 	switch (dmaereqp->der_trans) {
587 	case DMAE_TRANS_SNGL:
588 		mode |= DMAMODE_SINGLE;
589 		break;
590 	case DMAE_TRANS_BLCK:
591 		mode |= DMAMODE_BLOCK;
592 		break;
593 	case DMAE_TRANS_DMND:
594 		break;
595 	case DMAE_TRANS_CSCD:
596 		mode |= DMAMODE_CASC;
597 		break;
598 	default:
599 		return (DDI_FAILURE);
600 	}
601 	d37A_chnl_mode[chnl] = dmaereqp->der_trans;
602 
603 	dprintf(("d37A_set_mode: chnl=%d mode_reg=0x%x mode=0x%x\n",
604 	    chnl, chan_addr[chnl].mode_reg, mode));
605 	outb(chan_addr[chnl].mode_reg, mode);
606 #endif	/* ISA_MODE */
607 
608 #ifdef EISA_EXT_MODE
609 	emode = chnl & 3;
610 	d37A_chnl_path[chnl] = dmaereqp->der_path;
611 
612 	switch (dmaereqp->der_path) {
613 	case DMAE_PATH_8:
614 		/* emode |= EISA_DMA_8; */
615 		break;
616 	case DMAE_PATH_16:
617 		emode |= EISA_DMA_16;
618 		break;
619 	case DMAE_PATH_32:
620 		emode |= EISA_DMA_32;
621 		break;
622 	case DMAE_PATH_16B:
623 		emode |= EISA_DMA_16B;
624 		break;
625 	default:
626 		switch (chnl) {
627 		case DMAE_CH0:
628 		case DMAE_CH1:
629 		case DMAE_CH2:
630 		case DMAE_CH3:
631 			d37A_chnl_path[chnl] = DMAE_PATH_8;
632 			/* emode |= EISA_DMA_8; */
633 			break;
634 		case DMAE_CH5:
635 		case DMAE_CH6:
636 		case DMAE_CH7:
637 			d37A_chnl_path[chnl] = DMAE_PATH_16;
638 			emode |= EISA_DMA_16;
639 			break;
640 		}
641 	}
642 	emode |= (dmaereqp->der_cycles & 3) << 4;
643 	outb(chan_addr[chnl].emode_reg, emode);
644 
645 	dprintf(("d37A_set_mode: chnl=%d em_reg=0x%x emode=0x%x\n",
646 	    chnl, chan_addr[chnl].emode_reg, emode));
647 #endif	/* EISA_EXT_MODE */
648 	return (DDI_SUCCESS);
649 }
650 
651 
652 /*
653  *  routine: d37A_write_addr()
654  *  purpose: write the 24- or 32-bit physical address into the Base Address
655  *		Register for the indicated channel.
656  *  caller:  d37A_prog_chan(), d37A_dma_swsetup().
657  *  calls:   d37A macros
658  */
659 
660 static int
661 d37A_write_addr(ulong_t paddress, int chnl)
662 {
663 	uchar_t *adr_byte;
664 
665 	dprintf(("d37A_write_addr: chnl=%d address=%lx\n", chnl, paddress));
666 
667 	switch (d37A_chnl_path[chnl]) {
668 	case DMAE_PATH_8:
669 	case DMAE_PATH_16B:
670 	case DMAE_PATH_32:
671 		/*
672 		 * program DMA controller with byte address
673 		 */
674 		break;
675 
676 	case DMAE_PATH_16:
677 		/*
678 		 * convert byte address to shifted word address
679 		 */
680 		paddress = (paddress & ~0x1ffff) | ((paddress & 0x1ffff) >> 1);
681 		break;
682 
683 	default:
684 		return (DDI_FAILURE);
685 	}
686 	kpreempt_disable();	/* don't preempt thread while using flip-flop */
687 	outb(chan_addr[chnl].ff_reg, 0);	/* set flipflop */
688 
689 	adr_byte = (uchar_t *)&paddress;
690 	outb(chan_addr[chnl].addr_reg, adr_byte[0]);
691 	outb(chan_addr[chnl].addr_reg, adr_byte[1]);
692 	outb(chan_addr[chnl].page_reg, adr_byte[2]);
693 #ifdef ADDR_32
694 	outb(chan_addr[chnl].hpage_reg, adr_byte[3]);
695 #endif	/* ADDR_32 */
696 
697 	kpreempt_enable();
698 	return (DDI_SUCCESS);
699 }
700 
701 
702 /*
703  *  routine: d37A_read_addr()
704  *  purpose: read the 24- or 32-bit physical address from the Current Address
705  *		Register for the indicated channel.
706  *  caller:  d37A_get_chan_stat().
707  *  calls:   d37A macros
708  */
709 
710 static ulong_t
711 d37A_read_addr(int chnl)
712 {
713 	ulong_t paddress = 0;
714 	uchar_t *adr_byte;
715 
716 	kpreempt_disable();	/* don't preempt thread while using flip-flop */
717 	adr_byte = (uchar_t *)&paddress;
718 	outb(chan_addr[chnl].ff_reg, 0);	/* set flipflop */
719 
720 	adr_byte[0] = inb(chan_addr[chnl].addr_reg);
721 	adr_byte[1] = inb(chan_addr[chnl].addr_reg);
722 	adr_byte[2] = inb(chan_addr[chnl].page_reg);
723 #ifdef ADDR_32
724 	adr_byte[3] = inb(chan_addr[chnl].hpage_reg);
725 #endif	/* ADDR_32 */
726 
727 	kpreempt_enable();
728 
729 	switch (d37A_chnl_path[chnl]) {
730 	case DMAE_PATH_8:
731 	case DMAE_PATH_16B:
732 	case DMAE_PATH_32:
733 		/*
734 		 * return with byte address
735 		 */
736 		break;
737 
738 	case DMAE_PATH_16:
739 		/*
740 		 * convert shifted word address to byte address
741 		 */
742 		paddress = (paddress & ~0x1ffff) | ((paddress & 0x0ffff) << 1);
743 		break;
744 
745 	default:
746 		return ((ulong_t)DDI_FAILURE);
747 	}
748 
749 	dprintf(("d37A_read_addr: chnl=%d address=%lx.\n", chnl, paddress));
750 	return (paddress);
751 }
752 
753 
754 /*
755  *  routine: d37A_write_count()
756  *  purpose: write the 16- or 24-bit count into the Base Count Register for
757  *		the indicated channel.
758  *  caller:  d37A_prog_chan(), d37A_dma_swsetup()
759  *  calls:   d37A macros
760  */
761 
762 static int
763 d37A_write_count(long count, int chnl)
764 {
765 	uchar_t *count_byte;
766 
767 	dprintf(("d37A_write_count: chnl=%d count=0x%lx\n", chnl, count));
768 
769 	switch (d37A_chnl_path[chnl]) {
770 	case DMAE_PATH_16:
771 		/*
772 		 * Convert byte count to word count
773 		 */
774 		count >>= 1;
775 		/* FALLTHROUGH */
776 	case DMAE_PATH_8:
777 	case DMAE_PATH_16B:
778 	case DMAE_PATH_32:
779 		--count;
780 		break;
781 
782 	default:
783 		return (DDI_FAILURE);
784 	}
785 
786 	kpreempt_disable();	/* don't preempt thread while using flip-flop */
787 	outb(chan_addr[chnl].ff_reg, 0);	/* set flipflop */
788 
789 	count_byte = (uchar_t *)&count;
790 	outb(chan_addr[chnl].cnt_reg, count_byte[0]);
791 	outb(chan_addr[chnl].cnt_reg, count_byte[1]);
792 #ifdef COUNT_24
793 	outb(chan_addr[chnl].hcnt_reg, count_byte[2]);
794 #endif	/* COUNT_24 */
795 
796 	kpreempt_enable();
797 	return (DDI_SUCCESS);
798 }
799 
800 
801 /*
802  *  routine: d37A_read_count()
803  *  purpose: read the 16- or 24-bit count from the Current Count Register for
804  *		the indicated channel
805  *  caller:  d37A_get_chan_stat()
806  *  calls:   d37A macros
807  */
808 
809 static long
810 d37A_read_count(int chnl)
811 {
812 	long count = 0;
813 	uchar_t *count_byte;
814 
815 	kpreempt_disable();	/* don't preempt thread while using flip-flop */
816 	count_byte = (uchar_t *)&count;
817 	outb(chan_addr[chnl].ff_reg, 0);	/* set flipflop */
818 
819 	count_byte[0] = inb(chan_addr[chnl].cnt_reg);
820 	count_byte[1] = inb(chan_addr[chnl].cnt_reg);
821 #ifdef COUNT_24
822 	count_byte[2] = inb(chan_addr[chnl].hcnt_reg);
823 #endif	/* COUNT_24 */
824 
825 #ifdef COUNT_24
826 	if ((ulong_t)count == 0xffffff)
827 #else	/* !COUNT_24 */
828 	if ((ulong_t)count == 0xffff)
829 #endif	/* !COUNT_24 */
830 		count = -1;
831 
832 	kpreempt_enable();
833 
834 	switch (d37A_chnl_path[chnl]) {
835 	case DMAE_PATH_8:
836 	case DMAE_PATH_16B:
837 	case DMAE_PATH_32:
838 		++count;
839 		break;
840 
841 	case DMAE_PATH_16:
842 		/*
843 		 * Convert incremented word count to byte count
844 		 */
845 		count = (count + 1) << 1;
846 		break;
847 	}
848 	dprintf(("d37A_read_count: chnl=%d count=0x%lx\n", chnl, count));
849 	return (count);
850 }
851