|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1993 NeXT Computer, Inc. ! 3: * ! 4: * Driver class for SMC EtherCard Plus Elite16 adaptors. ! 5: * ! 6: * HISTORY ! 7: * ! 8: * 19 Apr 1993 ! 9: * Added multicast & promiscuous mode support. ! 10: * ! 11: * 26 Jan 1993 ! 12: * Created. ! 13: */ ! 14: ! 15: #define MACH_USER_API 1 ! 16: ! 17: #import <driverkit/generalFuncs.h> ! 18: #import <driverkit/IONetbufQueue.h> ! 19: ! 20: #import "SMC16.h" ! 21: #import "SMC16IOInline.h" ! 22: #import "SMC16Private.h" ! 23: ! 24: #import <kernserv/kern_server_types.h> ! 25: #import <kernserv/prototypes.h> ! 26: #import <kernserv/i386/spl.h> ! 27: ! 28: @implementation SMC16 ! 29: ! 30: /* ! 31: * Private Instance Methods ! 32: */ ! 33: ! 34: /* ! 35: * _memAvail ! 36: * Returns the amount of onboard memory not currently in use. ! 37: * Never returns less than zero. ! 38: */ ! 39: - (SMC16_len_t)_memAvail ! 40: { ! 41: int available; ! 42: ! 43: available = (memtotal - memused); ! 44: ! 45: return ((SMC16_len_t) ((available < 0)? 0: available)); ! 46: } ! 47: ! 48: /* ! 49: * _memRegion ! 50: * Returns the next available NIC_PAGE_SIZE chunk of onboard memory. ! 51: */ ! 52: - (SMC16_off_t)_memRegion:(SMC16_len_t)length ! 53: { ! 54: if ([self _memAvail] < length) ! 55: IOPanic("SMC16: onboard memory exhausted"); ! 56: ! 57: return ((SMC16_off_t) (memused / NIC_PAGE_SIZE)); ! 58: } ! 59: ! 60: /* ! 61: * _memAlloc ! 62: * Allocates onboard memory in chunks of NIC_PAGE_SIZE ! 63: */ ! 64: - (SMC16_off_t)_memAlloc:(SMC16_len_t)length ! 65: { ! 66: SMC16_off_t region; ! 67: ! 68: /* ! 69: * Round up to the next multiple of NIC_PAGE_SIZE ! 70: */ ! 71: length = ((length + NIC_PAGE_SIZE - 1) & ~(NIC_PAGE_SIZE - 1)); ! 72: ! 73: region = [self _memRegion:length]; ! 74: ! 75: memused += length; ! 76: ! 77: return (region); ! 78: } ! 79: ! 80: /* ! 81: * _initializeHardware ! 82: * Resets the SMC adaptor. Disables interrupts, resets the NIC, and ! 83: * configures the onboard memory. ! 84: */ ! 85: - (void)_initializeHardware ! 86: { ! 87: setIRQ(irq, YES, base); ! 88: ! 89: resetNIC(base); ! 90: ! 91: memtotal = setupRAM(membase, memsize, base); ! 92: memused = 0; ! 93: } ! 94: ! 95: /* ! 96: * _receiveInitialize ! 97: * Prepares the card for receive operations. Allocates as many NIC_PAGE_SIZE ! 98: * buffers from the available onboard memory. ! 99: */ ! 100: - (void)_receiveInitialize ! 101: { ! 102: SMC16_len_t avail = [self _memAvail]; ! 103: ! 104: rstart = [self _memAlloc:avail]; ! 105: rstop = rstart + (avail / NIC_PAGE_SIZE); ! 106: ! 107: /* ! 108: * Setup the receive ring ! 109: */ ! 110: put_rstart_reg(rstart, base); put_rstop_reg(rstop, base); ! 111: ! 112: /* ! 113: * Reset the boundary buffer pointer ! 114: */ ! 115: put_bound_reg(rstart, base); ! 116: ! 117: rnext = rstart + 1; ! 118: ! 119: /* ! 120: * Reset the current buffer pointer ! 121: */ ! 122: (void)sel_reg_page(REG_PAGE1, base); ! 123: put_curr_reg(rnext, base); ! 124: (void)sel_reg_page(REG_PAGE0, base); ! 125: } ! 126: ! 127: /* ! 128: * _transmitInitialize ! 129: * Prepares for transmit operations. We use 1 transmit buffer of maximum ! 130: * size. ! 131: */ ! 132: - (void)_transmitInitialize ! 133: { ! 134: tstart = [self _memAlloc:ETHERMAXPACKET]; ! 135: } ! 136: ! 137: /* ! 138: * _initializeSoftware ! 139: * Prepare the adaptor for network operations and start them. ! 140: */ ! 141: - (void)_initializeSoftware ! 142: { ! 143: setStationAddress(&myAddress, base); ! 144: ! 145: [self _transmitInitialize]; ! 146: [self _receiveInitialize]; ! 147: ! 148: startNIC(base, rconsave); ! 149: } ! 150: ! 151: /* ! 152: * _receiveInterruptOccurred ! 153: * This method handles the process of moving received frames from ! 154: * onboard adaptor memory to netbufs and handing them up to the network ! 155: * object. ! 156: */ ! 157: - (void)_receiveInterruptOccurred ! 158: { ! 159: nic_recv_hdr_t *rhdr; ! 160: netbuf_t pkt; ! 161: int pkt_len, pre_wrap_len; ! 162: void *pkt_data = NULL; ! 163: ! 164: #ifdef DEBUG ! 165: ! 166: /* ! 167: * Change this to 1 to be inundated with messages. ! 168: */ ! 169: boolean_t SMC16_recvTrace = 0; ! 170: ! 171: #endif DEBUG ! 172: ! 173: ! 174: /* ! 175: * Grab buffers until we point to the next available one. ! 176: */ ! 177: while (rnext != getCurrentBuffer(base)) { ! 178: ! 179: /* ! 180: * Point to the receive header in this buffer. ! 181: */ ! 182: rhdr = (nic_recv_hdr_t *)nic_page_addr(rnext,membase); ! 183: ! 184: #ifdef DEBUG ! 185: if (SMC16_recvTrace) { ! 186: IOLog("[rstat %02x next %02x len %03x rnext " ! 187: "%02x bound %02x curr %02x]\n", ! 188: *(unsigned char *)&rhdr->rstat, ! 189: rhdr->next, rhdr->len, rnext, ! 190: get_bound_reg(base), getCurrentBuffer(base)); ! 191: } ! 192: #endif DEBUG ! 193: ! 194: ! 195: /* ! 196: * Display a somewhat cryptic message if the prx bit is set. ! 197: */ ! 198: if (!rhdr->rstat.prx) { ! 199: IOLog("rhdr1 rstat %02x next %02x len %x\n", ! 200: *(unsigned char *)&rhdr->rstat, rhdr->next, rhdr->len); ! 201: [network incrementInputErrors]; ! 202: rnext = rhdr->next; ! 203: continue; ! 204: } ! 205: ! 206: /* ! 207: * Display a slightly different, equally cryptic message ! 208: * if the pointer to the next buffer in this header is outside ! 209: * the range configured buffers. If this is the case, force a ! 210: * reset by invoking -timeoutOccurred. ! 211: */ ! 212: if (rhdr->next >= rstop || rhdr->next < rstart) { ! 213: IOLog("rhdr2 rstat %02x next %02x len %x\n", ! 214: *(unsigned char *)&rhdr->rstat, rhdr->next, rhdr->len); ! 215: [network incrementInputErrors]; ! 216: [self timeoutOccurred]; ! 217: return; ! 218: } ! 219: ! 220: /* ! 221: * Get the overall packet length and the length between ! 222: * the start of the packet and the end of onboard memory. ! 223: * Any packet data beyond that will wrap back to the start ! 224: * of onboard memory. ! 225: */ ! 226: pkt_len = rhdr->len - ETHERCRC; ! 227: pre_wrap_len = nic_page_addr(rstop,membase) - ! 228: nic_page_addr(rnext,membase) - ! 229: sizeof (*rhdr); ! 230: ! 231: /* ! 232: * If the packet length looks reasonable, allocate a net buffer ! 233: * for it and establish a pointer to the data in that net buffer. ! 234: */ ! 235: if (pkt_len >= (ETHERMINPACKET - ETHERCRC) && ! 236: pkt_len <= ETHERMAXPACKET) { ! 237: pkt = nb_alloc(pkt_len); ! 238: if (pkt) ! 239: pkt_data = nb_map(pkt); ! 240: } ! 241: else { ! 242: [network incrementInputErrors]; ! 243: pkt = 0; ! 244: } ! 245: ! 246: /* ! 247: * If none of the packet wraps around the ring, just ! 248: * copy it into the netbuf. ! 249: */ ! 250: if (pkt_len <= pre_wrap_len) { ! 251: if (pkt) ! 252: IOCopyMemory( ! 253: (void *)nic_page_addr(rnext,membase) + sizeof (*rhdr), ! 254: pkt_data, ! 255: pkt_len, ! 256: sizeof(short)); ! 257: /* ! 258: * Otherwise, copy up to the end of memory, then copy the remaining ! 259: * portion from the start of memory. ! 260: */ ! 261: } ! 262: else { ! 263: if (pkt) { ! 264: IOCopyMemory( ! 265: (void *)nic_page_addr(rnext,membase) + sizeof (*rhdr), ! 266: pkt_data, ! 267: pre_wrap_len, ! 268: sizeof(short)); ! 269: IOCopyMemory( ! 270: (void *)nic_page_addr(rstart,membase), ! 271: pkt_data + pre_wrap_len, ! 272: pkt_len - pre_wrap_len, ! 273: sizeof(short)); ! 274: } ! 275: } ! 276: ! 277: /* ! 278: * Increment the ring buffer pointers. ! 279: */ ! 280: rnext = rhdr->next; ! 281: if ((rnext - 1) >= rstart) ! 282: put_bound_reg(rnext - 1, base); ! 283: else ! 284: put_bound_reg(rstop - 1, base); ! 285: ! 286: /* ! 287: * We only pass packets upward if they pass thru multicast filter. ! 288: */ ! 289: if(pkt) { ! 290: if(rconsave.prom == 0 && [super ! 291: isUnwantedMulticastPacket:(ether_header_t *)nb_map(pkt)]) { ! 292: nb_free(pkt); ! 293: } ! 294: else { ! 295: ! 296: [network handleInputPacket:pkt extra:0]; ! 297: ! 298: } ! 299: } ! 300: } ! 301: ! 302: } ! 303: ! 304: /* ! 305: * _receiveOverwriteOccurred ! 306: * Called when the adaptor tells us that we haven't fetched frames from ! 307: * onboard memory fast enough, so it's overwritten an old frame with a new ! 308: * one. Oh well... ! 309: */ ! 310: - (void)_receiveOverwriteOccurred ! 311: { ! 312: #ifdef DEBUG ! 313: IOLog("overwrite bound %02x curr %02x rnext %02x\n", get_bound_reg(base), getCurrentBuffer(base), rnext); ! 314: [network incrementInputErrors]; ! 315: #endif DEBUG ! 316: } ! 317: ! 318: /* ! 319: * _transmitInterruptOccurred ! 320: * Called when the adaptor indicated a transmit operation is complete. Check ! 321: * tstat register and increment the appropriate counters. Clear the ! 322: * timeout we set when we initiated the transmit and clear the transmitActive ! 323: * flag. Finally, if there are any outgoing packets in the queue, send the ! 324: * next one. ! 325: */ ! 326: - (void)_transmitInterruptOccurred ! 327: { ! 328: nic_tstat_reg_t tstat_reg; ! 329: netbuf_t pkt; ! 330: ! 331: if (transmitActive) { ! 332: tstat_reg = get_tstat_reg(base); ! 333: ! 334: /* ! 335: * Always check transmit status (if available) here. On a ! 336: * transmit error, increment statistics and reset the ! 337: * adaptor if necessary (not for SMC). NEVER TRY TO ! 338: * RETRANSMIT A PACKET. Leave this up to higher level ! 339: * software, which should insure reliability when ! 340: * it's needed. ! 341: */ ! 342: if (tstat_reg.ptx) ! 343: [network incrementOutputPackets]; ! 344: else ! 345: [network incrementOutputErrors]; ! 346: ! 347: if (tstat_reg.abort || tstat_reg.twc) ! 348: [network incrementCollisions]; ! 349: ! 350: [self clearTimeout]; ! 351: transmitActive = NO; ! 352: } ! 353: ! 354: if (pkt = [transmitQueue dequeue]) ! 355: [self transmit:pkt]; ! 356: } ! 357: ! 358: /* ! 359: * Public Factory Methods ! 360: */ ! 361: ! 362: + (BOOL)probe:(IODeviceDescription *)devDesc ! 363: { ! 364: SMC16 *dev = [self alloc]; ! 365: IOEISADeviceDescription ! 366: *deviceDescription = (IOEISADeviceDescription *)devDesc; ! 367: IORange *io; ! 368: ! 369: if (dev == nil) ! 370: return NO; ! 371: ! 372: /* ! 373: * Valid configuration? ! 374: */ ! 375: if ( [deviceDescription numPortRanges] < 1 ! 376: || ! 377: [deviceDescription numMemoryRanges] < 1 ! 378: || ! 379: [deviceDescription numInterrupts] < 1) { ! 380: [dev free]; ! 381: return NO; ! 382: } ! 383: ! 384: /* ! 385: * Make sure we're configured for 16K (even though we can only use 8) ! 386: */ ! 387: io = [deviceDescription memoryRangeList]; ! 388: if (io->size < 16*1024) { ! 389: [dev free]; ! 390: return NO; ! 391: } ! 392: ! 393: /* ! 394: * More configuration validation ! 395: */ ! 396: io = [deviceDescription portRangeList]; ! 397: if (io->size < 16) { ! 398: [dev free]; ! 399: return NO; ! 400: } ! 401: ! 402: /* ! 403: * Configuration checks out so let's actually probe for hardware. ! 404: */ ! 405: if (!checksumLAR(io->start)) { ! 406: IOLog("SMC16: Adaptor not present or invalid EEROM checksum.\n"); ! 407: [dev free]; ! 408: return NO; ! 409: } ! 410: ! 411: if (!checkBoardRev(io->start)) { ! 412: IOLog("SMC16: Unsupported board revision.\n"); ! 413: [dev free]; ! 414: return NO; ! 415: } ! 416: ! 417: return [dev initFromDeviceDescription:devDesc] != nil; ! 418: } ! 419: ! 420: /* ! 421: * Public Instance Methods ! 422: */ ! 423: ! 424: - initFromDeviceDescription:(IODeviceDescription *)devDesc ! 425: { ! 426: IOEISADeviceDescription ! 427: *deviceDescription = (IOEISADeviceDescription *)devDesc; ! 428: IORange *io; ! 429: ! 430: if ([super initFromDeviceDescription:devDesc] == nil) ! 431: return nil; ! 432: ! 433: /* ! 434: * Initialize ivars ! 435: */ ! 436: irq = [deviceDescription interrupt]; ! 437: ! 438: io = [deviceDescription portRangeList]; ! 439: base = io->start; ! 440: ! 441: io = [deviceDescription memoryRangeList]; ! 442: membase = io->start; ! 443: memsize = io->size; ! 444: ! 445: /* ! 446: * Broadcasts should be enabled ! 447: */ ! 448: rconsave.broad = 1; ! 449: ! 450: /* ! 451: * Reset the adaptor, but don't enable yet. We'll receive ! 452: * -resetAndEnable:YES as a side effect of calling ! 453: * -attachToNetworkWithAddress: ! 454: */ ! 455: [self resetAndEnable:NO]; ! 456: ! 457: IOLog("SMC16 at port %x irq %d\n",base, irq); ! 458: ! 459: transmitQueue = [[IONetbufQueue alloc] initWithMaxCount:32]; ! 460: ! 461: network = [super attachToNetworkWithAddress:myAddress]; ! 462: return self; ! 463: } ! 464: ! 465: - free ! 466: { ! 467: [transmitQueue free]; ! 468: ! 469: return [super free]; ! 470: } ! 471: ! 472: - (IOReturn)enableAllInterrupts ! 473: { ! 474: unmaskInterrupts(base); ! 475: ! 476: setIRQ(irq, YES, base); ! 477: ! 478: return [super enableAllInterrupts]; ! 479: } ! 480: ! 481: - (void)disableAllInterrupts ! 482: { ! 483: setIRQ(irq, NO, base); ! 484: ! 485: [super disableAllInterrupts]; ! 486: } ! 487: ! 488: - (BOOL)resetAndEnable:(BOOL)enable ! 489: { ! 490: [self disableAllInterrupts]; ! 491: ! 492: transmitActive = NO; ! 493: ! 494: [self _initializeHardware]; ! 495: ! 496: getStationAddress(&myAddress, base); ! 497: ! 498: [self _initializeSoftware]; ! 499: ! 500: if (enable && [self enableAllInterrupts] != IO_R_SUCCESS) { ! 501: [self setRunning:NO]; ! 502: return NO; ! 503: } ! 504: ! 505: [self setRunning:enable]; ! 506: return YES; ! 507: } ! 508: ! 509: - (void)timeoutOccurred ! 510: { ! 511: netbuf_t pkt = NULL; ! 512: ! 513: if ([self isRunning]) { ! 514: if ([self resetAndEnable:YES]) { ! 515: ! 516: if (pkt = [transmitQueue dequeue]) ! 517: [self transmit:pkt]; ! 518: } ! 519: } ! 520: /* ! 521: * Value of [self isRunning] may have been modified by ! 522: * resetAndEnable: ! 523: */ ! 524: if (![self isRunning]) { ! 525: /* ! 526: * Free any packets in the queue since we're not running. ! 527: */ ! 528: if ([transmitQueue count]) { ! 529: transmitActive = NO; ! 530: while (pkt = [transmitQueue dequeue]) ! 531: nb_free(pkt); ! 532: } ! 533: } ! 534: } ! 535: ! 536: /* ! 537: * Called by our IOThread when it receives a message signifying ! 538: * an interrupt. We check the istat register and vector off ! 539: * to the appropriate handler routines. ! 540: */ ! 541: - (void)interruptOccurred ! 542: { ! 543: nic_istat_reg_t istat_reg; ! 544: ! 545: istat_reg = get_istat_reg(base); ! 546: put_istat_reg(istat_reg, base); ! 547: ! 548: if (istat_reg.ovw) ! 549: [self _receiveOverwriteOccurred]; ! 550: ! 551: if (istat_reg.prx) ! 552: [self _receiveInterruptOccurred]; ! 553: ! 554: if (istat_reg.ptx || istat_reg.txe) ! 555: [self _transmitInterruptOccurred]; ! 556: } ! 557: ! 558: ! 559: /* ! 560: * Enable promiscuous mode (invoked by superclass). ! 561: */ ! 562: - (BOOL)enablePromiscuousMode ! 563: { ! 564: int old_page = sel_reg_page(REG_PAGE0, base); ! 565: ! 566: rconsave.prom = 1; ! 567: put_rcon_reg(rconsave, base); ! 568: sel_reg_page(old_page, base); ! 569: ! 570: return YES; ! 571: } ! 572: ! 573: /* ! 574: * Disable promiscuous mode (invoked by superclass). ! 575: */ ! 576: - (void)disablePromiscuousMode ! 577: { ! 578: int old_page = sel_reg_page(REG_PAGE0, base); ! 579: ! 580: rconsave.prom = 0; ! 581: put_rcon_reg(rconsave, base); ! 582: sel_reg_page(old_page, base); ! 583: ! 584: } ! 585: ! 586: ! 587: - (BOOL)enableMulticastMode ! 588: { ! 589: int old_page = sel_reg_page(REG_PAGE0, base); ! 590: ! 591: rconsave.group = 1; ! 592: put_rcon_reg(rconsave, base); ! 593: sel_reg_page(old_page, base); ! 594: ! 595: return YES; ! 596: } ! 597: ! 598: - (void)disableMulticastMode ! 599: { ! 600: int old_page = sel_reg_page(REG_PAGE0, base); ! 601: ! 602: rconsave.group = 0; ! 603: put_rcon_reg(rconsave, base); ! 604: sel_reg_page(old_page, base); ! 605: ! 606: } ! 607: ! 608: - (void)transmit:(netbuf_t)pkt ! 609: { ! 610: int pkt_len; ! 611: ! 612: /* ! 613: * If we're already transmitting, just queue up the packet. ! 614: */ ! 615: if (transmitActive) ! 616: [transmitQueue enqueue:pkt]; ! 617: else { ! 618: ! 619: /* ! 620: * We execute a softare loopback since this adaptor doesn't ! 621: * deal with this in hardware. ! 622: */ ! 623: [self performLoopback:pkt]; ! 624: ! 625: /* ! 626: * Copy the packet into our transmit buffer, then free it. ! 627: */ ! 628: pkt_len = nb_size(pkt); ! 629: IOCopyMemory( ! 630: nb_map(pkt), ! 631: (void *)nic_page_addr(tstart,membase), ! 632: pkt_len, ! 633: sizeof(short)); ! 634: ! 635: /* ! 636: * Once the packet is copied out to the adaptor's onboard RAM, ! 637: * always free the packet. DON'T SAVE A REFERENCE FOR ! 638: * RETRANSMISSION PURPOSES. Retransmission should be handled ! 639: * at the higher levels. ! 640: */ ! 641: nb_free(pkt); ! 642: ! 643: /* ! 644: * Setup up and initiate the transmit operation ! 645: */ ! 646: put_tcnt_reg(pkt_len, base); ! 647: put_tstart_reg(tstart, base); ! 648: startTransmit(base); ! 649: ! 650: /* ! 651: * Start a timer whose expiration will call -timeoutOccurred, then ! 652: * set the transmitActive flag so we don't step on this operation. ! 653: */ ! 654: [self setRelativeTimeout:3000]; ! 655: transmitActive = YES; ! 656: } ! 657: } ! 658: ! 659: ! 660: @end ! 661: ! 662: /* ! 663: * Private Functions ! 664: */ ! 665: ! 666: static BOOL ! 667: checksumLAR( ! 668: IOEISAPortAddress base ! 669: ) ! 670: { ! 671: IOEISAPortAddress offset; ! 672: unsigned char sum = 0; ! 673: ! 674: for (offset = BIC_LAR_OFF; offset <= BIC_LAR_CKSUM_OFF; offset++) ! 675: sum += inb(base + SMC16_BIC_OFF + offset); ! 676: ! 677: return (sum == 0xff); ! 678: } ! 679: ! 680: static void ! 681: getStationAddress( ! 682: enet_addr_t *ea, ! 683: IOEISAPortAddress base ! 684: ) ! 685: { ! 686: int i; ! 687: unsigned char *enaddr = (unsigned char *)ea; ! 688: ! 689: for (i = 0; i < sizeof (*ea); i++) ! 690: *(enaddr + i) = inb(base + SMC16_BIC_OFF + BIC_LAR_OFF + i); ! 691: } ! 692: ! 693: static void ! 694: setStationAddress( ! 695: enet_addr_t *ea, ! 696: IOEISAPortAddress base ! 697: ) ! 698: { ! 699: int i, old_page; ! 700: unsigned char *enaddr = (unsigned char *)ea; ! 701: ! 702: old_page = sel_reg_page(REG_PAGE1, base); ! 703: ! 704: for (i = 0; i < sizeof (*ea); i++) ! 705: outb(base + SMC16_NIC_OFF + NIC_STA_REG_OFF + i, *(enaddr + i)); ! 706: ! 707: (void)sel_reg_page(old_page, base); ! 708: } ! 709: ! 710: static BOOL ! 711: checkBoardRev( ! 712: IOEISAPortAddress base ! 713: ) ! 714: { ! 715: unsigned int bid; ! 716: ! 717: bid = get_bid(base); ! 718: ! 719: if (SMC16_REV(bid) < 2) ! 720: return NO; ! 721: ! 722: return YES; ! 723: } ! 724: ! 725: static void ! 726: resetNIC( ! 727: IOEISAPortAddress base ! 728: ) ! 729: { ! 730: bic_msr_t msr = { 0 }; ! 731: nic_istat_reg_t istat_reg; ! 732: ! 733: /* ! 734: * Perform HW Reset of NIC ! 735: */ ! 736: msr.rst = 1; put_msr(msr, base); ! 737: IODelay(500); ! 738: msr.rst = 0; put_msr(msr, base); ! 739: ! 740: /* ! 741: * Wait for NIC to enter stopped state ! 742: */ ! 743: do { ! 744: istat_reg = get_istat_reg(base); ! 745: } while (istat_reg.rst == 0); ! 746: } ! 747: ! 748: static SMC16_len_t ! 749: setupRAM( ! 750: vm_offset_t addr, ! 751: vm_size_t size, ! 752: IOEISAPortAddress base ! 753: ) ! 754: { ! 755: SMC16_len_t total; ! 756: SMC16_off_t block_addr; ! 757: bic_laar_t laar; ! 758: bic_msr_t msr; ! 759: #ifdef SIXTEEN_BIT_MODE ! 760: bic_icr_t icr; ! 761: #endif SIXTEEN_BIT_MODE ! 762: union { ! 763: struct { ! 764: unsigned int :13, ! 765: madr :6, ! 766: ladr :5, ! 767: :8; ! 768: } bic_addr; ! 769: struct { ! 770: unsigned int :16, ! 771: block :8, ! 772: :8; ! 773: } nic_addr; ! 774: unsigned int address; ! 775: } _mconv; ! 776: ! 777: /* ! 778: * NOTE: We cannot put the card into 16-bit (and therefore 16K) mode because ! 779: * the bus interface chip will behave as though a full 64K is mapped, even ! 780: * though only 16K exists on the board. Needless to say this causes problems, ! 781: * whether something else is mapped into the top 3/4 of that 64K or not. ! 782: * Unless the hardware changes, we're limited to using 8K of onboard memory ! 783: * and 8-bit transfer mode. ! 784: */ ! 785: ! 786: #ifdef SIXTEEN_BIT_MODE ! 787: icr = get_icr(base); ! 788: ! 789: total = (icr.msz ? 16 : 64) * 1024; ! 790: ! 791: if (total > 16 * 1024) ! 792: total = 16 * 1024; ! 793: #else // SIXTEEN_BIT_MODE ! 794: total = 8 * 1024; ! 795: #endif SIXTEEN_BIT_MODE ! 796: ! 797: if (total > size) ! 798: total = size; ! 799: ! 800: #ifdef DEBUG ! 801: IOLog("SMC16: using %d bytes of onboard memory\n",total); ! 802: #endif DEBUG ! 803: ! 804: _mconv.address = addr; ! 805: ! 806: laar = get_laar(base); ! 807: #ifdef SIXTEEN_BIT_MODE ! 808: laar.zws16 = TRUE; ! 809: laar.l16en = TRUE; ! 810: laar.m16en = TRUE; ! 811: #endif SIXTEEN_BIT_MODE ! 812: laar.ladr = _mconv.bic_addr.ladr; ! 813: put_laar(laar, base); ! 814: ! 815: msr = get_msr(base); ! 816: msr.madr = _mconv.bic_addr.madr; ! 817: msr.menb = TRUE; ! 818: put_msr(msr, base); ! 819: ! 820: block_addr = _mconv.nic_addr.block; ! 821: put_block_reg(block_addr, base); ! 822: ! 823: return (total); ! 824: } ! 825: ! 826: static void ! 827: startNIC( ! 828: IOEISAPortAddress base, ! 829: nic_rcon_reg_t rcon_reg ! 830: ) ! 831: { ! 832: nic_cmd_reg_t cmd_reg = { 0 }; ! 833: nic_enh_reg_t enh_reg = { 0 }; ! 834: nic_dcon_reg_t dcon_reg = { 0 }; ! 835: nic_tcon_reg_t tcon_reg = { 0 }; ! 836: nic_istat_reg_t istat_reg; ! 837: ! 838: enh_reg.slot = NIC_SLOT_512_BIT; ! 839: enh_reg.wait = 0; ! 840: put_enh_reg(enh_reg, base); ! 841: ! 842: dcon_reg.bsize = NIC_DMA_BURST_8b; ! 843: #ifdef SIXTEEN_BIT_MODE ! 844: dcon_reg.bus16 = TRUE; ! 845: #endif SIXTEEN_BIT_MODE ! 846: put_dcon_reg(dcon_reg, base); ! 847: ! 848: put_tcon_reg(tcon_reg, base); ! 849: ! 850: istat_reg = get_istat_reg(base); ! 851: put_istat_reg(istat_reg, base); ! 852: ! 853: cmd_reg.sta = 1; ! 854: put_cmd_reg(cmd_reg, base); ! 855: ! 856: put_rcon_reg(rcon_reg, base); ! 857: } ! 858: ! 859: static void ! 860: unmaskInterrupts( ! 861: IOEISAPortAddress base ! 862: ) ! 863: { ! 864: nic_imask_reg_t imask_reg = { 0 }; ! 865: ! 866: /* ! 867: * Receive conditions ! 868: */ ! 869: imask_reg.prxe = imask_reg.rxee = imask_reg.ovwe = TRUE; ! 870: ! 871: /* ! 872: * Transmit conditions ! 873: */ ! 874: imask_reg.ptxe = imask_reg.txee = TRUE; ! 875: ! 876: put_imask_reg(imask_reg, base); ! 877: } ! 878: ! 879: static SMC16_off_t ! 880: getCurrentBuffer( ! 881: IOEISAPortAddress base ! 882: ) ! 883: { ! 884: SMC16_off_t curr; ! 885: int old_page; ! 886: ! 887: old_page = sel_reg_page(REG_PAGE1, base); ! 888: curr = get_curr_reg(base); ! 889: if (old_page != REG_PAGE1) ! 890: sel_reg_page(old_page, base); ! 891: ! 892: return (curr); ! 893: } ! 894: ! 895: static void ! 896: startTransmit( ! 897: IOEISAPortAddress base ! 898: ) ! 899: { ! 900: nic_cmd_reg_t cmd_reg = { 0 }; ! 901: ! 902: cmd_reg.txp = 1; ! 903: cmd_reg.sta = 1; ! 904: put_cmd_reg(cmd_reg, base); ! 905: } ! 906: ! 907: static void ! 908: setIRQ( ! 909: int irq, ! 910: BOOL enable, ! 911: IOEISAPortAddress base ! 912: ) ! 913: { ! 914: bic_irr_t irr; ! 915: bic_icr_t icr; ! 916: static char _irx_map[16] = { -1, ! 917: -1, ! 918: -1, ! 919: BIC_IRX_3, ! 920: BIC_IRX_4, ! 921: BIC_IRX_5, ! 922: -1, ! 923: BIC_IRX_7, ! 924: -1, ! 925: BIC_IRX_9, ! 926: BIC_IRX_10, ! 927: BIC_IRX_11, ! 928: -1, ! 929: -1, ! 930: -1, ! 931: BIC_IRX_15 }; ! 932: static char _ir2_map[16] = { -1, ! 933: -1, ! 934: -1, ! 935: ICR_IR2_3, ! 936: ICR_IR2_4, ! 937: ICR_IR2_5, ! 938: -1, ! 939: ICR_IR2_7, ! 940: -1, ! 941: ICR_IR2_9, ! 942: ICR_IR2_10, ! 943: ICR_IR2_11, ! 944: -1, ! 945: -1, ! 946: -1, ! 947: ICR_IR2_15 }; ! 948: ! 949: irr = get_irr(base); ! 950: irr.irx = _irx_map[irq]; ! 951: irr.ien = FALSE; ! 952: put_irr(irr, base); ! 953: ! 954: icr = get_icr(base); ! 955: icr.ir2 = _ir2_map[irq]; ! 956: put_icr(icr, base); ! 957: ! 958: irr.ien = enable; ! 959: put_irr(irr, base); ! 960: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.