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