|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1992 NeXT Computer, Inc. ! 27: * ! 28: * dma.c -- DMA Routines. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 08 Jan 1993 David Somayajulu at NeXT ! 33: * added functions is_dma_done, get_dma_addr, get_dma_count ! 34: * ! 35: * 13 July 1992 ? at NeXT ! 36: * Created. ! 37: */ ! 38: ! 39: #import <mach/mach_types.h> ! 40: ! 41: #import <machdep/i386/dma.h> ! 42: #import <machdep/i386/dma_internal.h> ! 43: #import <machdep/i386/dma_inline.h> ! 44: #import <machdep/i386/dma_exported.h> ! 45: ! 46: struct _dma_chan_port _dma_chan_port[DMA_NCHAN] = { ! 47: { ! 48: DMA_CHAN0_ADDR_PORT, ! 49: DMA_CHAN0_PAGE_PORT, DMA_CHAN0_HIPAGE_PORT, ! 50: DMA_CHAN0_COUNT_PORT, DMA_CHAN0_HICOUNT_PORT }, ! 51: { ! 52: DMA_CHAN1_ADDR_PORT, ! 53: DMA_CHAN1_PAGE_PORT, DMA_CHAN1_HIPAGE_PORT, ! 54: DMA_CHAN1_COUNT_PORT, DMA_CHAN1_HICOUNT_PORT }, ! 55: { ! 56: DMA_CHAN2_ADDR_PORT, ! 57: DMA_CHAN2_PAGE_PORT, DMA_CHAN2_HIPAGE_PORT, ! 58: DMA_CHAN2_COUNT_PORT, DMA_CHAN2_HICOUNT_PORT }, ! 59: { ! 60: DMA_CHAN3_ADDR_PORT, ! 61: DMA_CHAN3_PAGE_PORT, DMA_CHAN3_HIPAGE_PORT, ! 62: DMA_CHAN3_COUNT_PORT, DMA_CHAN3_HICOUNT_PORT }, ! 63: { ! 64: /* CASCADE channel */ ! 65: }, ! 66: { ! 67: DMA2_CHAN1_ADDR_PORT, ! 68: DMA2_CHAN1_PAGE_PORT, DMA2_CHAN1_HIPAGE_PORT, ! 69: DMA2_CHAN1_COUNT_PORT, DMA2_CHAN1_HICOUNT_PORT }, ! 70: { ! 71: DMA2_CHAN2_ADDR_PORT, ! 72: DMA2_CHAN2_PAGE_PORT, DMA2_CHAN2_HIPAGE_PORT, ! 73: DMA2_CHAN2_COUNT_PORT, DMA2_CHAN2_HICOUNT_PORT }, ! 74: { ! 75: DMA2_CHAN3_ADDR_PORT, ! 76: DMA2_CHAN3_PAGE_PORT, DMA2_CHAN3_HIPAGE_PORT, ! 77: DMA2_CHAN3_COUNT_PORT, DMA2_CHAN3_HICOUNT_PORT }, ! 78: }; ! 79: ! 80: struct _dma_chip_port _dma_chip_port[] = { ! 81: { ! 82: DMA_CMD_STATUS_PORT, DMA_REQ_PORT, DMA_MASK_PORT, DMA_MODE_PORT, ! 83: DMA_CLEAR_FF_PORT, DMA_MASTER_RESET_PORT, DMA_EXTEND_MODE_PORT }, ! 84: { ! 85: DMA2_CMD_STATUS_PORT, DMA2_REQ_PORT, DMA2_MASK_PORT, DMA2_MODE_PORT, ! 86: DMA2_CLEAR_FF_PORT, DMA2_MASTER_RESET_PORT, DMA2_EXTEND_MODE_PORT } ! 87: }; ! 88: ! 89: unsigned char dma_assigned_bits; ! 90: struct dma_write_regs dma_write_regs[DMA_NCHAN]; ! 91: dma_cmd_reg_t dma_cmd_regs[DMA_NCHIPS]; ! 92: ! 93: unsigned prev_tcstatus0, /* previous transfer count status of ! 94: DMA Chip Port 0,for channels 0-3*/ ! 95: prev_tcstatus1; /* previous transfer count status of ! 96: DMA Chip Port 1,for channels 5-7*/ ! 97: /* The TC bits in the status register get cleared ! 98: when it is read. Hence we need to keep track of it ! 99: seperately */ ! 100: ! 101: static void dma_init_extend_mode(int chan); ! 102: ! 103: #define PRIORITY_ROTATING 1 ! 104: ! 105: void ! 106: dma_initialize( ! 107: void ! 108: ) ! 109: { ! 110: dma_cmd_reg_t cmd = { 0 }; ! 111: int chan; ! 112: ! 113: dma_master_reset(); ! 114: prev_tcstatus0 = 0; ! 115: prev_tcstatus1 = 0; ! 116: ! 117: #if PRIORITY_ROTATING ! 118: cmd.priority = DMA_PRIO_ROTATING; ! 119: #else PRIORITY_ROTATING ! 120: cmd.priority = DMA_PRIO_FIXED; ! 121: #endif PRIORITY_ROTATING ! 122: dma_set_cmd(0, cmd); ! 123: dma_set_cmd(1, cmd); ! 124: dma_cmd_regs[0] = cmd; ! 125: dma_cmd_regs[1] = cmd; ! 126: ! 127: for (chan = 0; chan < DMA_NCHAN; chan++) { ! 128: (void) dma_assign_chan(chan); ! 129: ! 130: if (chan != DMA_CASCADE_CHAN) { ! 131: dma_deassign_chan(chan); // does an unmask ! 132: dma_init_extend_mode(chan); ! 133: } ! 134: else { ! 135: dma_chan_xfer_mode(chan, DMA_MODE_CASCADE); ! 136: dma_unmask_chan(chan); // unmask and leave ! 137: // assigned ! 138: } ! 139: } ! 140: dma_buf_initialize(); ! 141: } ! 142: ! 143: /* ! 144: * Initialize extended mode register to defaults. ! 145: */ ! 146: static void ! 147: dma_init_extend_mode( ! 148: int chan ! 149: ) ! 150: { ! 151: dma_write_regs[chan].extend_mode.dma_timing = ! 152: DMA_TIMING_COMPAT; ! 153: dma_write_regs[chan].extend_mode.eop_io = ! 154: DMA_EOP_OUT; ! 155: dma_write_regs[chan].extend_mode.stop_enable = ! 156: DMA_STOP_DISABLE; ! 157: if (!eisa_present()) { ! 158: /* on ISA, use this to indicate transfer mode, ! 159: * but don't actually try to set the mode in hardware ! 160: */ ! 161: if (chan < 4) ! 162: dma_write_regs[chan].extend_mode.xfer_width = ! 163: DMA_XFR_8_BIT; ! 164: else ! 165: dma_write_regs[chan].extend_mode.xfer_width = ! 166: DMA_XFR_16_BIT_WORD; ! 167: } else { ! 168: dma_write_regs[chan].extend_mode.xfer_width = ! 169: DMA_XFR_8_BIT; ! 170: dma_set_chan_extend_mode(chan, dma_write_regs[chan].extend_mode); ! 171: } ! 172: } ! 173: boolean_t ! 174: dma_assign_chan( ! 175: int chan ! 176: ) ! 177: { ! 178: if (DMA_CHAN_IS_ASSIGNED(chan)) ! 179: return (FALSE); ! 180: ! 181: dma_assigned_bits |= (1 << chan); ! 182: ! 183: return (TRUE); ! 184: } ! 185: ! 186: void ! 187: dma_deassign_chan( ! 188: int chan ! 189: ) ! 190: { ! 191: dma_mask_chan(chan); ! 192: ! 193: dma_assigned_bits &= ~(1 << chan); ! 194: } ! 195: ! 196: void ! 197: dma_mask_chan( ! 198: int chan ! 199: ) ! 200: { ! 201: dma_mask_reg_t mask = { 0 }; ! 202: ! 203: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 204: return; ! 205: ! 206: mask.mask = DMA_MASK_SET; ! 207: mask.chan_sel = chan; ! 208: ! 209: dma_set_chan_mask(chan, mask); ! 210: } ! 211: ! 212: void ! 213: dma_unmask_chan( ! 214: int chan ! 215: ) ! 216: { ! 217: dma_mask_reg_t mask = { 0 }; ! 218: ! 219: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 220: return; ! 221: ! 222: mask.mask = DMA_MASK_CLEAR; ! 223: mask.chan_sel = chan; ! 224: ! 225: dma_set_chan_mask(chan, mask); ! 226: } ! 227: ! 228: void ! 229: dma_chan_xfer_mode( ! 230: int chan, ! 231: int xfer_mode ! 232: ) ! 233: { ! 234: dma_mode_reg_t mode; ! 235: ! 236: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 237: return; ! 238: ! 239: dma_write_regs[chan].mode.xfer_mode = xfer_mode; ! 240: ! 241: mode = dma_write_regs[chan].mode; ! 242: mode.chan_sel = chan; ! 243: ! 244: dma_set_chan_mode(chan, mode); ! 245: } ! 246: ! 247: void ! 248: dma_chan_autoinit( ! 249: int chan, ! 250: boolean_t autoinit) ! 251: { ! 252: dma_mode_reg_t mode; ! 253: ! 254: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 255: return; ! 256: ! 257: dma_write_regs[chan].mode.autoinit = autoinit; ! 258: mode = dma_write_regs[chan].mode; ! 259: mode.chan_sel = chan; ! 260: dma_set_chan_mode(chan, mode); ! 261: } ! 262: ! 263: void ! 264: dma_chan_adrs_dir( ! 265: int chan, ! 266: boolean_t adrs_dir) ! 267: { ! 268: dma_mode_reg_t mode; ! 269: ! 270: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 271: return; ! 272: ! 273: dma_write_regs[chan].mode.adrs_dir = adrs_dir ? 1 : 0; ! 274: mode = dma_write_regs[chan].mode; ! 275: mode.chan_sel = chan; ! 276: dma_set_chan_mode(chan, mode); ! 277: } ! 278: ! 279: void ! 280: dma_chan_xfer_dir( ! 281: int chan, ! 282: int xfer_dir ! 283: ) ! 284: { ! 285: dma_mode_reg_t mode; ! 286: ! 287: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 288: return; ! 289: ! 290: dma_write_regs[chan].mode.xfer_dir = xfer_dir; ! 291: ! 292: mode = dma_write_regs[chan].mode; ! 293: mode.chan_sel = chan; ! 294: ! 295: dma_set_chan_mode(chan, mode); ! 296: } ! 297: ! 298: boolean_t ! 299: dma_xfer_chan( ! 300: int chan, ! 301: dma_xfer_t *xfer ! 302: ) ! 303: { ! 304: vm_offset_t phys; ! 305: extern boolean_t isEISA; ! 306: ! 307: // REMOVE THIS ! 308: caddr_t dma_addr; ! 309: unsigned dma_count; ! 310: ! 311: ! 312: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 313: return (FALSE); ! 314: ! 315: if (!eisa_present()) ! 316: xfer->lower16 = xfer->bound64 = TRUE; ! 317: ! 318: if (!dma_xfer(xfer, &phys)) ! 319: return (FALSE); ! 320: ! 321: xfer->chan = chan; xfer->use_chan = TRUE; ! 322: ! 323: (void) dma_mask_chan(chan); ! 324: ! 325: if (xfer->read) ! 326: dma_chan_xfer_dir(chan, DMA_XFER_WRITE);/* dma write to memory */ ! 327: else ! 328: dma_chan_xfer_dir(chan, DMA_XFER_READ);/* dma read from memory */ ! 329: ! 330: dma_set_chan_addr(chan, phys); ! 331: ! 332: #if DMA_DEBUG ! 333: dma_addr = get_dma_addr(2); ! 334: dma_count = get_dma_count(2); ! 335: #endif ! 336: dma_set_chan_count(chan, xfer->len); ! 337: ! 338: #if DMA_DEBUG ! 339: dma_count = get_dma_count(2); ! 340: #endif ! 341: /* ! 342: * Clear the shadow "channel done" bit. ! 343: */ ! 344: if(chan <= 3) { ! 345: prev_tcstatus0 &= ~(1 << chan); ! 346: } ! 347: else { ! 348: prev_tcstatus1 &= ~(1 << (chan - 4)); ! 349: } ! 350: (void) dma_unmask_chan(chan); ! 351: ! 352: #if DMA_DEBUG ! 353: dma_count = get_dma_count(2); ! 354: #endif ! 355: ! 356: return (TRUE); ! 357: } ! 358: ! 359: boolean_t ! 360: dma_xfer( ! 361: dma_xfer_t *xfer, ! 362: vm_offset_t *rphys ! 363: ) ! 364: { ! 365: dma_buf_t *buf = &xfer->buf; ! 366: ! 367: /* Allocate DMA-able memory if we need to, ! 368: * and if a buffer has not already been allocated for this xfer. ! 369: */ ! 370: if (xfer->lower16 && ((xfer->phys )>= (16*1024*1024)) ! 371: && !xfer->buffered) { ! 372: vm_offset_t phys; ! 373: ! 374: if (!dma_buf_alloc(buf, xfer->len)) ! 375: return (FALSE); ! 376: ! 377: xfer->buffered = TRUE; ! 378: ! 379: phys = (vm_offset_t)buf->_ptr; ! 380: ! 381: if (!xfer->read) ! 382: bcopy( ! 383: pmap_phys_to_kern(xfer->phys), ! 384: pmap_phys_to_kern(phys), ! 385: xfer->len); ! 386: ! 387: *rphys = phys; ! 388: } ! 389: else ! 390: *rphys = xfer->phys; ! 391: ! 392: xfer->active = TRUE; ! 393: ! 394: return (TRUE); ! 395: } ! 396: ! 397: void ! 398: dma_xfer_done( ! 399: dma_xfer_t *xfer ! 400: ) ! 401: { ! 402: if (xfer->active) { ! 403: if (xfer->buffered) { ! 404: dma_buf_t *buf = &xfer->buf; ! 405: vm_offset_t phys; ! 406: ! 407: phys = (vm_offset_t)buf->_ptr; ! 408: ! 409: if (xfer->read) ! 410: bcopy( ! 411: pmap_phys_to_kern(phys), ! 412: pmap_phys_to_kern(xfer->phys), ! 413: xfer->len); ! 414: ! 415: dma_buf_free(buf); ! 416: } ! 417: ! 418: xfer->active = xfer->buffered = FALSE; ! 419: } ! 420: } ! 421: ! 422: void ! 423: dma_xfer_abort( ! 424: dma_xfer_t *xfer ! 425: ) ! 426: { ! 427: if (xfer->active) { ! 428: if (xfer->buffered) ! 429: dma_buf_free(&xfer->buf); ! 430: ! 431: xfer->active = xfer->buffered = FALSE; ! 432: } ! 433: } ! 434: ! 435: /* ! 436: * Extended Mode register manipulation ! 437: */ ! 438: void ! 439: dma_xfer_width( ! 440: int chan, ! 441: int xfer_width ! 442: ) ! 443: { ! 444: dma_extend_mode_reg_t extend_mode; ! 445: ! 446: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 447: return; ! 448: ! 449: dma_write_regs[chan].extend_mode.xfer_width = xfer_width; ! 450: extend_mode = dma_write_regs[chan].extend_mode; ! 451: extend_mode.chan_sel = chan; ! 452: dma_set_chan_extend_mode(chan, extend_mode); ! 453: } ! 454: ! 455: /* ! 456: * Get the current transfer width for a channel. ! 457: */ ! 458: int ! 459: get_dma_xfer_width( ! 460: int chan ! 461: ) ! 462: { ! 463: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 464: return -1; ! 465: return dma_write_regs[chan].extend_mode.xfer_width; ! 466: } ! 467: ! 468: ! 469: void ! 470: dma_timing( ! 471: int chan, ! 472: int dma_timing ! 473: ) ! 474: { ! 475: dma_extend_mode_reg_t extend_mode; ! 476: ! 477: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 478: return; ! 479: ! 480: dma_write_regs[chan].extend_mode.dma_timing = dma_timing; ! 481: extend_mode = dma_write_regs[chan].extend_mode; ! 482: extend_mode.chan_sel = chan; ! 483: dma_set_chan_extend_mode(chan, extend_mode); ! 484: } ! 485: ! 486: void ! 487: dma_eop_in( ! 488: int chan, ! 489: int eop_io ! 490: ) ! 491: { ! 492: dma_extend_mode_reg_t extend_mode; ! 493: ! 494: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 495: return; ! 496: ! 497: dma_write_regs[chan].extend_mode.eop_io = eop_io; ! 498: extend_mode = dma_write_regs[chan].extend_mode; ! 499: extend_mode.chan_sel = chan; ! 500: dma_set_chan_extend_mode(chan, extend_mode); ! 501: } ! 502: ! 503: void ! 504: dma_stop_enable( ! 505: int chan, ! 506: int stop_enable ! 507: ) ! 508: { ! 509: dma_extend_mode_reg_t extend_mode; ! 510: ! 511: if (!DMA_CHAN_IS_ASSIGNED(chan)) ! 512: return; ! 513: ! 514: dma_write_regs[chan].extend_mode.stop_enable = stop_enable; ! 515: extend_mode = dma_write_regs[chan].extend_mode; ! 516: extend_mode.chan_sel = chan; ! 517: dma_set_chan_extend_mode(chan, extend_mode); ! 518: } ! 519: ! 520: /* returns the status register contents for the corresponding channel */ ! 521: boolean_t is_dma_done(int chan) ! 522: { ! 523: unsigned char status; ! 524: ! 525: DMA_DELAY; ! 526: status = (unsigned char)(inb(DMA_CHIP_PORT(chan, cmd_status))); ! 527: ! 528: /* ! 529: * Save the volatile bits we just read and OR in shadow ! 530: * bits for current test. ! 531: */ ! 532: if (chan <= 3) { ! 533: prev_tcstatus0 |= (status & 0xf); ! 534: return (prev_tcstatus0 & (1 << chan)) ? TRUE : FALSE; ! 535: ! 536: }else { ! 537: chan = chan - 4; ! 538: prev_tcstatus1 |= (status & 0xf); ! 539: return (prev_tcstatus1 & (1 << chan)) ? TRUE : FALSE; ! 540: } ! 541: } ! 542: ! 543: vm_offset_t get_dma_addr(int chan) ! 544: { ! 545: union { ! 546: vm_offset_t addr; ! 547: struct { ! 548: vm_offset_t addr_byte0 :8, ! 549: addr_byte1 :8, ! 550: page :8, ! 551: hipage :8; ! 552: } data; ! 553: struct { ! 554: vm_offset_t addr :16, ! 555: page :8, ! 556: hipage :8; ! 557: } isa_data; ! 558: } tconv; ! 559: tconv.addr = 0; ! 560: dma_chip_disable(chan); ! 561: ! 562: DMA_DELAY; ! 563: outb(DMA_CHIP_PORT(chan, clear_ff), 0xff); ! 564: DMA_DELAY; ! 565: tconv.data.addr_byte0 = inb(DMA_CHAN_PORT(chan, addr)); ! 566: dprintf(("reading from port =0x%x value = 0x%x\n", ! 567: DMA_CHAN_PORT(chan, addr), tconv.data.addr_byte0)); ! 568: DMA_DELAY; ! 569: tconv.data.addr_byte1 = inb(DMA_CHAN_PORT(chan, addr)); ! 570: dprintf(("reading from port =0x%x value = 0x%x\n", ! 571: DMA_CHAN_PORT(chan, addr), tconv.data.addr_byte1)); ! 572: DMA_DELAY; ! 573: tconv.data.page = inb(DMA_CHAN_PORT(chan, page)); ! 574: dprintf(("reading from port =0x%x value = 0x%x\n", ! 575: DMA_CHAN_PORT(chan, page), tconv.data.page)); ! 576: if(eisa_present()){ ! 577: DMA_DELAY; ! 578: tconv.data.hipage = inb(DMA_CHAN_PORT(chan, hipage)); ! 579: dprintf(("reading from port =0x%x value = 0x%x\n", ! 580: DMA_CHAN_PORT(chan, hipage), tconv.data.hipage)); ! 581: } ! 582: dma_chip_enable(chan); ! 583: if (dma_write_regs[chan].extend_mode.xfer_width == ! 584: DMA_XFR_16_BIT_WORD) { ! 585: tconv.isa_data.addr <<= 1; ! 586: } ! 587: return(tconv.addr); ! 588: } ! 589: ! 590: vm_size_t get_dma_count(int chan) ! 591: { ! 592: union { ! 593: vm_size_t count; ! 594: struct { ! 595: vm_size_t count_byte0 :8, ! 596: count_byte1 :8, ! 597: hicount :8, ! 598: :8; ! 599: } data; ! 600: } tconv; ! 601: ! 602: dma_chip_disable(chan); ! 603: tconv.count = 0x00; ! 604: DMA_DELAY; ! 605: outb(DMA_CHIP_PORT(chan, clear_ff), 0xff); ! 606: ! 607: DMA_DELAY; ! 608: tconv.data.count_byte0 = inb(DMA_CHAN_PORT(chan, count)); ! 609: dprintf(("reading from port =0x%x value = 0x%x\n", ! 610: DMA_CHAN_PORT(chan, count), tconv.data.count_byte0)); ! 611: ! 612: DMA_DELAY; ! 613: tconv.data.count_byte1 = inb(DMA_CHAN_PORT(chan, count)); ! 614: dprintf(("reading from port =0x%x value = 0x%x\n", ! 615: DMA_CHAN_PORT(chan, count), tconv.data.count_byte1)); ! 616: if (eisa_present()){ ! 617: tconv.data.hicount = inb(DMA_CHAN_PORT(chan, hicount)); ! 618: dprintf(("reading from port =0x%x value = 0x%x\n", ! 619: DMA_CHAN_PORT(chan, hicount), tconv.data.hicount)); ! 620: dma_chip_enable(chan); ! 621: ! 622: if (tconv.count == 0xFFFFFF) { ! 623: tconv.count = 0; ! 624: } ! 625: else { ! 626: ++tconv.count; ! 627: } ! 628: } else { ! 629: dma_chip_enable(chan); ! 630: if (tconv.count == 0xFFFF) { ! 631: tconv.count = 0; ! 632: } ! 633: else { ! 634: ++tconv.count; ! 635: } ! 636: } ! 637: if (dma_write_regs[chan].extend_mode.xfer_width == ! 638: DMA_XFR_16_BIT_WORD) { ! 639: tconv.count <<= 1; ! 640: } ! 641: ! 642: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.