|
|
1.1.1.3 ! root 1: /* $Id: 3c400.c,v 1.8 2004/04/30 11:51:29 fredette Exp $ */ 1.1 root 2: 3: /* bus/multibus/3c400.c - implementation of the Multibus 3c400 emulation: */ 4: 5: /* 6: * Copyright (c) 2003 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: #include <tme/common.h> 1.1.1.3 ! root 37: _TME_RCSID("$Id: 3c400.c,v 1.8 2004/04/30 11:51:29 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/generic/bus-device.h> 41: #include <tme/generic/ethernet.h> 42: 43: /* macros: */ 44: 45: /* register offsets and sizes: */ 46: #define TME_3C400_REG_CSR (0) 47: #define TME_3C400_SIZ_CSR (sizeof(tme_uint16_t)) 48: #define TME_3C400_REG_BACKOFF (2) 49: #define TME_3C400_SIZ_BACKOFF (sizeof(tme_uint16_t)) 50: #define TME_3C400_REG_AROM (1024) 51: #define TME_3C400_SIZ_AROM (TME_ETHERNET_ADDR_SIZE) 52: #define TME_3C400_REG_ARAM (1536) 53: #define TME_3C400_SIZ_ARAM (TME_ETHERNET_ADDR_SIZE) 54: #define TME_3C400_REG_TBUF (2048) 55: #define TME_3C400_SIZ_BUF (2048) 56: #define TME_3C400_REG_ABUF (TME_3C400_REG_TBUF + TME_3C400_SIZ_BUF) 57: #define TME_3C400_REG_BBUF (TME_3C400_REG_ABUF + TME_3C400_SIZ_BUF) 58: #define TME_3C400_SIZ_CARD (TME_3C400_REG_BBUF + TME_3C400_SIZ_BUF) 59: 60: /* the bits in the Control/Status Register. software can set and 61: clear bits covered by TME_3C400_CSR_INTPA. software can set, but 62: not clear, bits not covered by TME_3C400_CSR_INTPA: */ 63: #define TME_3C400_CSR_BBSW (0x8000) /* B buffer empty (belongs to card) */ 64: #define TME_3C400_CSR_ABSW (0x4000) /* A buffer empty (belongs to card) */ 65: #define TME_3C400_CSR_TBSW (0x2000) /* T buffer full (belongs to card) */ 66: #define TME_3C400_CSR_JAM (0x1000) /* Ethernet jammed (collision) */ 67: #define TME_3C400_CSR_AMSW (0x0800) /* address RAM belongs to ether */ 68: #define TME_3C400_CSR_RBBA (0x0400) /* B buffer received before A */ 69: #define TME_3C400_CSR_RESET (0x0100) /* reset the card */ 70: #define TME_3C400_CSR_INTPA (0x00ff) /* mask for interrupt and PA fields */ 71: #define TME_3C400_CSR_BINT (0x0080) /* B buffer interrupt enable */ 72: #define TME_3C400_CSR_AINT (0x0040) /* A buffer interrupt enable */ 73: #define TME_3C400_CSR_TINT (0x0020) /* T buffer interrupt enable */ 74: #define TME_3C400_CSR_JINT (0x0010) /* jam interrupt enable */ 75: #define TME_3C400_CSR_PAMASK (0x000f) /* PA field */ 76: #define TME_3C400_CSR_PA (0x0007) /* receive mine+broadcast-errors */ 77: #define TME_3C400_CSR_PROMISC (0x0001) /* receive all-errors */ 78: 79: /* the first 16 bits of all buffers are a status word: */ 80: #define TME_3C400_SIZ_BUF_STATUS (sizeof(tme_uint16_t)) 81: 82: /* the bits of a receive buffer status word: */ 83: /* Frame Check Sequence (CRC) error */ 84: #define TME_3C400_RBUF_FCSERR (0x8000) 85: /* this packet was broadcast: */ 86: #define TME_3C400_RBUF_BROADCAST (0x4000) 87: /* this packet had a "range error": */ 88: #define TME_3C400_RBUF_RGERR (0x2000) 89: /* this packet matched our address: */ 90: #define TME_3C400_RBUF_ADDRMATCH (0x1000) 91: /* this packet had a framing error: */ 92: #define TME_3C400_RBUF_FRERR (0x0800) 93: /* the first byte after the frame in the buffer: */ 94: #define TME_3C400_RBUF_DOFF_MASK (0x07ff) 95: 96: /* these get and put the CSR: */ 97: #define TME_3C400_CSR_GET(_3c400) \ 98: tme_betoh_u16(*((tme_uint16_t *) &(_3c400)->tme_3c400_card[TME_3C400_REG_CSR])) 99: #define TME_3C400_CSR_PUT(_3c400, csr) \ 1.1.1.2 root 100: (*((tme_uint16_t *) &(_3c400)->tme_3c400_card[TME_3C400_REG_CSR]) = tme_htobe_u16(csr)) 1.1 root 101: 102: /* the callout flags: */ 103: #define TME_3C400_CALLOUT_CHECK (0) 104: #define TME_3C400_CALLOUT_RUNNING TME_BIT(0) 105: #define TME_3C400_CALLOUTS_MASK (-2) 106: #define TME_3C400_CALLOUT_CTRL TME_BIT(1) 107: #define TME_3C400_CALLOUT_CONFIG TME_BIT(2) 108: #define TME_3C400_CALLOUT_READ TME_BIT(3) 109: #define TME_3C400_CALLOUT_INT TME_BIT(4) 110: 111: /* structures: */ 112: 113: /* the card: */ 114: struct tme_3c400 { 115: 116: /* our simple bus device header: */ 117: struct tme_bus_device tme_3c400_device; 118: #define tme_3c400_element tme_3c400_device.tme_bus_device_element 119: 120: /* the mutex protecting the card: */ 121: tme_mutex_t tme_3c400_mutex; 122: 123: /* the rwlock protecting the card: */ 124: tme_rwlock_t tme_3c400_rwlock; 125: 126: /* the Ethernet connection: */ 127: struct tme_ethernet_connection *tme_3c400_eth_connection; 128: 129: /* the callout flags: */ 130: int tme_3c400_callout_flags; 131: 132: /* if our interrupt line is currently asserted: */ 133: int tme_3c400_int_asserted; 134: 135: /* it's easiest to just model the card as a chunk of memory: */ 136: tme_uint8_t tme_3c400_card[TME_3C400_SIZ_CARD]; 137: 138: #ifndef TME_NO_LOG 139: tme_uint16_t tme_3c400_last_log_csr; 140: #endif /* !TME_NO_LOG */ 141: }; 142: 143: /* this resets the card: */ 144: static void 145: _tme_3c400_reset(struct tme_3c400 *_3c400) 146: { 147: tme_uint16_t csr; 148: 149: /* the reset CSR value: */ 150: csr = 0; 151: 152: /* set the CSR: */ 153: TME_3C400_CSR_PUT(_3c400, csr); 154: 155: /* clear all pending callouts: */ 156: _3c400->tme_3c400_callout_flags &= TME_3C400_CALLOUTS_MASK; 157: 158: /* if the interrupt line is currently asserted, negate it: */ 159: if (_3c400->tme_3c400_int_asserted) { 160: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_INT; 161: } 162: } 163: 164: /* the _3c400 callout function. it must be called with the mutex locked: */ 165: static void 166: _tme_3c400_callout(struct tme_3c400 *_3c400, int new_callouts) 167: { 168: struct tme_ethernet_connection *conn_eth; 169: struct tme_bus_connection *conn_bus; 170: tme_uint16_t csr, csr_rbba, recv_buffer; 171: int callouts, later_callouts; 172: unsigned int ctrl; 173: struct tme_ethernet_config config; 174: int rc; 175: const tme_uint8_t *addrs[2]; 176: tme_ethernet_fid_t frame_id; 177: tme_uint8_t *rbuf; 178: tme_uint16_t status; 179: struct tme_ethernet_frame_chunk *frame_chunk, frame_chunk_buffer; 180: int int_asserted; 181: 182: /* add in any new callouts: */ 183: _3c400->tme_3c400_callout_flags |= new_callouts; 184: 185: /* if this function is already running in another thread, simply 186: return now. the other thread will do our work: */ 187: if (_3c400->tme_3c400_callout_flags & TME_3C400_CALLOUT_RUNNING) { 188: return; 189: } 190: 191: /* callouts are now running: */ 192: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_RUNNING; 193: 194: /* assume that we won't need any later callouts: */ 195: later_callouts = 0; 196: 197: /* loop while callouts are needed: */ 198: for (; (callouts = _3c400->tme_3c400_callout_flags) & TME_3C400_CALLOUTS_MASK; ) { 199: 200: /* clear the needed callouts: */ 201: _3c400->tme_3c400_callout_flags = callouts & ~TME_3C400_CALLOUTS_MASK; 202: callouts &= TME_3C400_CALLOUTS_MASK; 203: 204: /* get this card's connection: */ 205: conn_eth = _3c400->tme_3c400_eth_connection; 206: 207: /* if we need to call out new control information: */ 208: if (callouts & TME_3C400_CALLOUT_CTRL) { 209: 210: /* get the current CSR value: */ 211: csr = TME_3C400_CSR_GET(_3c400); 212: 213: /* form the new ctrl: */ 214: ctrl = 0; 215: if (csr & TME_3C400_CSR_TBSW) { 216: ctrl |= TME_ETHERNET_CTRL_OK_READ; 217: } 218: 219: /* unlock the mutex: */ 220: tme_mutex_unlock(&_3c400->tme_3c400_mutex); 221: 222: /* do the callout: */ 223: rc = (conn_eth != NULL 224: ? ((*conn_eth->tme_ethernet_connection_ctrl) 225: (conn_eth, 226: ctrl)) 227: : TME_OK); 228: 229: /* lock the mutex: */ 230: tme_mutex_lock(&_3c400->tme_3c400_mutex); 231: 232: /* if the callout was unsuccessful, remember that at some later 233: time this callout should be attempted again: */ 234: if (rc != TME_OK) { 235: later_callouts |= TME_3C400_CALLOUT_CTRL; 236: } 237: } 238: 239: /* if we need to call out new config information: */ 240: if (callouts & TME_3C400_CALLOUT_CONFIG) { 241: 242: /* get the current CSR value: */ 243: csr = TME_3C400_CSR_GET(_3c400); 244: 245: /* form the new config: */ 246: memset(&config, 0, sizeof(config)); 247: 248: /* our Ethernet address: */ 249: config.tme_ethernet_config_addr_count = 0; 250: addrs[config.tme_ethernet_config_addr_count++] 251: = tme_ethernet_addr_broadcast; 252: if (csr & TME_3C400_CSR_AMSW) { 253: addrs[config.tme_ethernet_config_addr_count++] 254: = &_3c400->tme_3c400_card[TME_3C400_REG_ARAM]; 255: } 256: config.tme_ethernet_config_addrs = addrs; 257: 258: /* our config flags: */ 259: config.tme_ethernet_config_flags = TME_ETHERNET_CONFIG_NORMAL; 260: switch (csr & TME_3C400_CSR_PAMASK) { 261: case 0: 262: config.tme_ethernet_config_addr_count = 0; 263: break; 264: case TME_3C400_CSR_PA: 265: break; 266: case TME_3C400_CSR_PROMISC: 267: config.tme_ethernet_config_flags |= TME_ETHERNET_CONFIG_PROMISC; 268: break; 269: default: abort(); 270: } 271: 272: /* unlock the mutex: */ 273: tme_mutex_unlock(&_3c400->tme_3c400_mutex); 274: 275: /* do the callout: */ 276: rc = (conn_eth == NULL 277: ? TME_OK 278: : ((*conn_eth->tme_ethernet_connection_config) 279: (conn_eth, 280: &config))); 281: 282: /* lock the mutex: */ 283: tme_mutex_lock(&_3c400->tme_3c400_mutex); 284: 285: /* if the callout was unsuccessful, remember that at some later 286: time this callout should be attempted again: */ 287: if (rc != TME_OK) { 288: later_callouts |= TME_3C400_CALLOUT_CONFIG; 289: } 290: } 291: 292: /* if the Ethernet is readable: */ 293: if (callouts & TME_3C400_CALLOUT_READ) { 294: 295: /* get the current CSR value: */ 296: csr = TME_3C400_CSR_GET(_3c400); 297: 298: /* try to find an empty buffer: */ 299: switch (csr & (TME_3C400_CSR_BBSW | TME_3C400_CSR_ABSW)) { 300: default: 301: /* both buffers are full: */ 302: recv_buffer = 0; 303: csr_rbba = (csr & TME_3C400_CSR_RBBA); 304: break; 305: case TME_3C400_CSR_BBSW: 306: /* the A buffer is full but the B buffer is empty: */ 307: recv_buffer = TME_3C400_CSR_BBSW; 308: csr_rbba = 0; 309: break; 310: case TME_3C400_CSR_ABSW: 311: /* the B buffer is full but the A buffer is empty: */ 312: recv_buffer = TME_3C400_CSR_ABSW; 313: csr_rbba = TME_3C400_CSR_RBBA; 314: break; 315: case TME_3C400_CSR_ABSW | TME_3C400_CSR_BBSW: 316: /* both buffers are empty: */ 317: recv_buffer = TME_3C400_CSR_ABSW; 318: csr_rbba = 0; 319: break; 320: } 321: 322: /* unlock the mutex: */ 323: tme_mutex_unlock(&_3c400->tme_3c400_mutex); 324: 325: /* make a frame chunk to receive this frame. remember that the 326: first two bytes of our card's buffers are a status word: */ 327: if (recv_buffer == 0) { 328: rbuf = NULL; 329: frame_chunk = NULL; 330: } 331: else { 332: rbuf = 333: &_3c400->tme_3c400_card[(recv_buffer == TME_3C400_CSR_ABSW 334: ? TME_3C400_REG_ABUF 335: : TME_3C400_REG_BBUF)]; 336: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL; 337: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes 338: = rbuf + TME_3C400_SIZ_BUF_STATUS; 339: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count 340: = TME_3C400_SIZ_BUF; 341: frame_chunk = &frame_chunk_buffer; 342: } 343: 344: /* do the callout: */ 345: rc = (conn_eth == NULL 346: ? TME_OK 347: : ((*conn_eth->tme_ethernet_connection_read) 348: (conn_eth, 349: &frame_id, 350: frame_chunk, 351: TME_ETHERNET_READ_NEXT))); 352: 353: /* lock the mutex: */ 354: tme_mutex_lock(&_3c400->tme_3c400_mutex); 355: 356: /* get the current CSR value: */ 357: csr = TME_3C400_CSR_GET(_3c400); 358: 359: /* if the read was successful: */ 360: if (rc > 0) { 361: 362: /* if this frame was received into a buffer: */ 363: if (recv_buffer != 0) { 364: 365: /* form the status word for this buffer: */ 366: status = 0; 367: 368: /* the first thing in the frame is the destination address, 369: which we check against our address and the broadcast 370: address: */ 371: if (memcmp(rbuf + TME_3C400_SIZ_BUF_STATUS, 372: &_3c400->tme_3c400_card[TME_3C400_REG_ARAM], 373: TME_ETHERNET_ADDR_SIZE) == 0) { 374: status |= TME_3C400_RBUF_ADDRMATCH; 375: } 376: else if (memcmp(rbuf + TME_3C400_SIZ_BUF_STATUS, 377: tme_ethernet_addr_broadcast, 378: TME_ETHERNET_ADDR_SIZE) == 0) { 379: status |= TME_3C400_RBUF_BROADCAST; 380: } 381: 382: /* put in the offset of the first free byte in the status. 383: make sure we present a packet that is at least as big 384: as the smallest Ethernet frame: */ 385: rc = TME_MAX(rc, TME_ETHERNET_FRAME_MIN - TME_ETHERNET_CRC_SIZE); 386: status |= TME_3C400_SIZ_BUF_STATUS + rc; 387: 388: /* put in the status: */ 389: *((tme_uint16_t *) rbuf) = tme_htobe_u16(status); 390: 391: /* update the CSR to reflect the new packet: */ 392: csr = (csr & ~(recv_buffer | TME_3C400_CSR_RBBA)) | csr_rbba; 393: TME_3C400_CSR_PUT(_3c400, csr); 394: 395: /* if interrupts are enabled on this buffer, mark that we need 396: to callout an interrupt: */ 397: if (csr & (recv_buffer >> 8)) { 398: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_INT; 399: } 400: } 401: 402: /* mark that we need to loop to callout to read more frames: */ 403: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_READ; 404: } 405: 406: /* otherwise, the read failed. convention dictates that we 407: forget that the connection was readable, which we already 408: have done by clearing the CALLOUT_READ flag: */ 409: } 410: 411: /* if we need to call out a possible change to our interrupt 412: signal: */ 413: if (callouts & TME_3C400_CALLOUT_INT) { 414: 415: /* get the current CSR value: */ 416: csr = TME_3C400_CSR_GET(_3c400); 417: 418: /* see if the interrupt signal should be asserted or negated: */ 419: int_asserted = ((~(csr & (TME_3C400_CSR_BBSW 420: | TME_3C400_CSR_ABSW 421: | TME_3C400_CSR_TBSW))) 422: & ((csr & (TME_3C400_CSR_BINT 423: | TME_3C400_CSR_AINT 424: | TME_3C400_CSR_TINT)) << 8)); 425: 426: /* if the interrupt signal doesn't already have the right state: */ 427: if (!int_asserted != !_3c400->tme_3c400_int_asserted) { 428: 429: /* unlock our mutex: */ 430: tme_mutex_unlock(&_3c400->tme_3c400_mutex); 431: 432: /* get our bus connection: */ 433: conn_bus = TME_ATOMIC_READ(struct tme_bus_connection *, 434: _3c400->tme_3c400_device.tme_bus_device_connection); 435: 436: /* call out the bus interrupt signal edge: */ 437: rc = (*conn_bus->tme_bus_signal) 438: (conn_bus, 439: TME_BUS_SIGNAL_INT_UNSPEC 440: | (int_asserted 441: ? TME_BUS_SIGNAL_LEVEL_ASSERTED 1.1.1.3 ! root 442: : TME_BUS_SIGNAL_LEVEL_NEGATED)); 1.1 root 443: 444: /* lock our mutex: */ 445: tme_mutex_lock(&_3c400->tme_3c400_mutex); 446: 447: /* if this callout was successful, note the new state of the 448: interrupt signal: */ 449: if (rc == TME_OK) { 450: _3c400->tme_3c400_int_asserted = int_asserted; 451: } 452: 453: /* otherwise, remember that at some later time this callout 454: should be attempted again: */ 455: else { 456: later_callouts |= TME_3C400_CALLOUT_INT; 457: } 458: } 459: } 460: } 461: 462: /* put in any later callouts, and clear that callouts are running: */ 463: _3c400->tme_3c400_callout_flags = later_callouts; 464: } 465: 466: /* the _3c400 bus cycle handler: */ 467: static int 468: _tme_3c400_bus_cycle(void *__3c400, struct tme_bus_cycle *cycle_init) 469: { 470: struct tme_3c400 *_3c400; 471: tme_uint16_t csr_old, csr_new, csr_diff; 472: int new_callouts; 473: 474: /* recover our data structure: */ 475: _3c400 = (struct tme_3c400 *) __3c400; 476: 477: /* assume we won't need any new callouts: */ 478: new_callouts = 0; 479: 480: /* lock the mutex: */ 481: tme_mutex_lock(&_3c400->tme_3c400_mutex); 482: 483: /* get the changed CSR value - there are bits that software can only 484: set, and not clear: */ 485: csr_old = TME_3C400_CSR_GET(_3c400); 486: 487: /* unless this address falls within the address ROM, run the cycle: */ 488: if ((cycle_init->tme_bus_cycle_address 489: < TME_3C400_REG_AROM) 490: || (cycle_init->tme_bus_cycle_address 491: >= TME_3C400_REG_ARAM)) { 492: tme_bus_cycle_xfer_memory(cycle_init, 493: _3c400->tme_3c400_card, 494: _3c400->tme_3c400_device.tme_bus_device_address_last); 495: } 496: 497: /* get the new CSR value, and put back any bits that software 498: cannot clear: */ 499: csr_new = TME_3C400_CSR_GET(_3c400); 500: csr_new |= (csr_old & ~TME_3C400_CSR_INTPA); 501: 502: /* get the set of bits that has changed: */ 503: csr_diff = (csr_old ^ csr_new); 504: 505: /* if this is a reset: */ 506: if (csr_diff & TME_3C400_CSR_RESET) { 507: _tme_3c400_reset(_3c400); 508: } 509: 510: /* otherwise: */ 511: else { 512: 513: /* if the transmit buffer now belongs to the card, call out 514: that we are now readable: */ 515: if (csr_diff & TME_3C400_CSR_TBSW) { 516: new_callouts |= TME_3C400_CALLOUT_CTRL; 517: } 518: 519: /* if the address RAM now belongs to the card, or if the address 520: filter configuration has changed, call out the config change: */ 521: if ((csr_diff & TME_3C400_CSR_AMSW) 522: || (csr_diff & TME_3C400_CSR_PAMASK) != 0) { 523: new_callouts |= TME_3C400_CALLOUT_CONFIG; 524: } 525: 526: /* if any interrupt enable status bits have changed, 527: call out the interrupt signal change: */ 528: if (csr_diff & (TME_3C400_CSR_BINT 529: | TME_3C400_CSR_AINT 530: | TME_3C400_CSR_TINT)) { 531: new_callouts |= TME_3C400_CALLOUT_INT; 532: } 533: 534: /* set the current CSR value: */ 535: TME_3C400_CSR_PUT(_3c400, csr_new); 536: 537: #ifndef TME_NO_LOG 538: if (csr_new != _3c400->tme_3c400_last_log_csr) { 539: _3c400->tme_3c400_last_log_csr = csr_new; 540: tme_log(&_3c400->tme_3c400_element->tme_element_log_handle, 541: 1000, TME_OK, 542: (&_3c400->tme_3c400_element->tme_element_log_handle, 543: "csr now 0x%04x", 544: csr_new)); 545: } 546: #endif /* !TME_NO_LOG */ 547: } 548: 549: /* make any new callouts: */ 550: _tme_3c400_callout(_3c400, new_callouts); 551: 552: /* unlock the mutex: */ 553: tme_mutex_unlock(&_3c400->tme_3c400_mutex); 554: 555: /* no faults: */ 556: return (TME_OK); 557: } 558: 559: /* this is called when a device changes its configuration: */ 560: static int 561: _tme_3c400_config(struct tme_ethernet_connection *conn_eth, 562: struct tme_ethernet_config *config) 563: { 564: /* we don't care when other devices on the Ethernet 565: reconfigure themselves: */ 566: return (TME_OK); 567: } 568: 569: /* this is called when control lines change: */ 570: static int 571: _tme_3c400_ctrl(struct tme_ethernet_connection *conn_eth, 572: unsigned int ctrl) 573: { 574: struct tme_3c400 *_3c400; 575: int new_callouts; 576: 577: /* recover our data structures: */ 578: _3c400 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; 579: 580: /* assume that we won't need any new callouts: */ 581: new_callouts = 0; 582: 583: /* lock the mutex: */ 584: tme_mutex_lock(&_3c400->tme_3c400_mutex); 585: 586: /* if this connection is readable, call out a read: */ 587: if (ctrl & TME_ETHERNET_CTRL_OK_READ) { 588: new_callouts |= TME_3C400_CALLOUT_READ; 589: } 590: 591: /* make any new callouts: */ 592: _tme_3c400_callout(_3c400, new_callouts); 593: 594: /* unlock the mutex: */ 595: tme_mutex_unlock(&_3c400->tme_3c400_mutex); 596: 597: return (TME_OK); 598: } 599: 600: /* this is called to read frames (from the 3c400 perspective, to transmit them): */ 601: static int 602: _tme_3c400_read(struct tme_ethernet_connection *conn_eth, 603: tme_ethernet_fid_t *_frame_id, 604: struct tme_ethernet_frame_chunk *frame_chunks, 605: unsigned int flags) 606: { 607: struct tme_3c400 *_3c400; 608: struct tme_ethernet_frame_chunk frame_chunk_buffer; 609: tme_uint16_t csr, count; 610: int new_callouts; 611: int rc; 612: 613: /* recover our data structures: */ 614: _3c400 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private; 615: 616: /* assume that we won't need any new callouts: */ 617: new_callouts = 0; 618: 619: /* lock our mutex: */ 620: tme_mutex_lock(&_3c400->tme_3c400_mutex); 621: 622: /* get the current CSR value: */ 623: csr = TME_3C400_CSR_GET(_3c400); 624: 625: /* if the transmit buffer is full: */ 626: if (csr & TME_3C400_CSR_TBSW) { 627: 628: /* get the count of bytes in the frame: */ 629: count = (TME_3C400_SIZ_BUF 630: - (tme_betoh_u16(*((tme_uint16_t *) 631: &_3c400->tme_3c400_card[TME_3C400_REG_TBUF])) 632: & TME_3C400_RBUF_DOFF_MASK)); 633: 634: /* form the single frame chunk: */ 635: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL; 636: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes 637: = (&_3c400->tme_3c400_card[TME_3C400_REG_TBUF] 638: + TME_3C400_SIZ_BUF 639: - count); 640: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count 641: = count; 642: 643: /* copy out the frame: */ 644: count = tme_ethernet_chunks_copy(frame_chunks, &frame_chunk_buffer); 645: 646: /* if this isn't a peek: */ 647: if (!(flags & TME_ETHERNET_READ_PEEK)) { 648: 649: /* mark the transmit buffer as empty: */ 650: csr &= ~TME_3C400_CSR_TBSW; 651: TME_3C400_CSR_PUT(_3c400, csr); 652: 653: /* if transmit buffer interrupts are enabled, call out 654: an interrupt: */ 655: if (csr & TME_3C400_CSR_TINT) { 656: new_callouts |= TME_3C400_CALLOUT_INT; 657: } 658: } 659: 660: /* success: */ 661: rc = count; 662: } 663: 664: /* if the transmit buffer is empty, return an error: */ 665: else { 666: rc = -ENOENT; 667: } 668: 669: /* make any new callouts: */ 670: _tme_3c400_callout(_3c400, new_callouts); 671: 672: /* unlock our mutex: */ 673: tme_mutex_unlock(&_3c400->tme_3c400_mutex); 674: 675: /* done: */ 676: return (rc); 677: } 678: 679: /* the _3c400 TLB filler: */ 680: static int 681: _tme_3c400_tlb_fill(void *__3c400, struct tme_bus_tlb *tlb, 682: tme_bus_addr_t address, unsigned int cycles) 683: { 684: struct tme_3c400 *_3c400; 685: 686: /* recover our data structure: */ 687: _3c400 = (struct tme_3c400 *) __3c400; 688: 689: /* the address must be within range: */ 690: assert(address < TME_3C400_SIZ_CARD); 691: 692: /* initialize the TLB entry: */ 693: tme_bus_tlb_initialize(tlb); 694: 695: /* if the address falls from the CSR to the address ROM: */ 696: if (TME_3C400_REG_CSR <= address 697: && address < TME_3C400_REG_AROM) { 698: 699: /* this TLB entry covers this range: */ 700: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_CSR); 701: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_REG_AROM - 1); 702: } 703: 704: /* if this address falls from the address ROM to the address RAM: */ 705: else if (TME_3C400_REG_AROM <= address 706: && address < TME_3C400_REG_ARAM) { 707: 708: /* this TLB entry covers this range: */ 709: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_AROM); 710: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_REG_ARAM - 1); 711: } 712: 713: /* anything else covers the remainder of the device: */ 714: else { 715: 716: /* this TLB entry can cover from the address RAM to the end of the card: */ 717: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_ARAM); 718: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_SIZ_CARD - 1); 719: 720: /* this TLB entry allows fast writing: */ 721: tlb->tme_bus_tlb_emulator_off_write = &_3c400->tme_3c400_card[0]; 722: } 723: 724: /* all address ranges allow fast reading: */ 725: tlb->tme_bus_tlb_emulator_off_read = &_3c400->tme_3c400_card[0]; 726: tlb->tme_bus_tlb_rwlock = &_3c400->tme_3c400_rwlock; 727: 728: /* allow reading and writing: */ 729: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 730: 731: /* our bus cycle handler: */ 732: tlb->tme_bus_tlb_cycle_private = _3c400; 733: tlb->tme_bus_tlb_cycle = _tme_3c400_bus_cycle; 734: 735: return (TME_OK); 736: } 737: 738: /* this makes a new Ethernet connection: */ 739: static int 740: _tme_3c400_connection_make(struct tme_connection *conn, unsigned int state) 741: { 742: struct tme_3c400 *_3c400; 743: struct tme_ethernet_connection *conn_eth; 744: struct tme_ethernet_connection *conn_eth_other; 745: 746: /* recover our data structures: */ 747: _3c400 = conn->tme_connection_element->tme_element_private; 748: conn_eth = (struct tme_ethernet_connection *) conn; 749: conn_eth_other = (struct tme_ethernet_connection *) conn->tme_connection_other; 750: 751: /* both sides must be Ethernet connections: */ 752: assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET); 753: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET); 754: 755: /* we're always set up to answer calls across the connection, so we 756: only have to do work when the connection has gone full, namely 757: taking the other side of the connection: */ 758: if (state == TME_CONNECTION_FULL) { 759: 760: /* lock our mutex: */ 761: tme_mutex_lock(&_3c400->tme_3c400_mutex); 762: 763: /* save our connection: */ 764: _3c400->tme_3c400_eth_connection = conn_eth_other; 765: 766: /* unlock our mutex: */ 767: tme_mutex_unlock(&_3c400->tme_3c400_mutex); 768: } 769: 770: return (TME_OK); 771: } 772: 773: /* this breaks a connection: */ 774: static int 775: _tme_3c400_connection_break(struct tme_connection *conn, unsigned int state) 776: { 777: abort(); 778: } 779: 780: /* this makes a new connection side for a 3c400: */ 781: static int 782: _tme_3c400_connections_new(struct tme_element *element, 783: const char * const *args, 784: struct tme_connection **_conns, 785: char **_output) 786: { 787: struct tme_3c400 *_3c400; 788: struct tme_ethernet_connection *conn_eth; 789: struct tme_connection *conn; 790: int rc; 791: 792: /* recover our data structure: */ 793: _3c400 = (struct tme_3c400 *) element->tme_element_private; 794: 795: /* make the generic bus device connection side: */ 796: rc = tme_bus_device_connections_new(element, args, _conns, _output); 797: if (rc != TME_OK) { 798: return (rc); 799: } 800: 801: /* if we don't have an Ethernet connection, make one: */ 802: if (_3c400->tme_3c400_eth_connection == NULL) { 803: 804: /* allocate the new Ethernet connection: */ 805: conn_eth = tme_new0(struct tme_ethernet_connection, 1); 806: conn = &conn_eth->tme_ethernet_connection; 807: 808: /* fill in the generic connection: */ 809: conn->tme_connection_next = *_conns; 810: conn->tme_connection_type = TME_CONNECTION_ETHERNET; 811: conn->tme_connection_score = tme_ethernet_connection_score; 812: conn->tme_connection_make = _tme_3c400_connection_make; 813: conn->tme_connection_break = _tme_3c400_connection_break; 814: 815: /* fill in the Ethernet connection: */ 816: conn_eth->tme_ethernet_connection_config = _tme_3c400_config; 817: conn_eth->tme_ethernet_connection_ctrl = _tme_3c400_ctrl; 818: conn_eth->tme_ethernet_connection_read = _tme_3c400_read; 819: 820: /* return the connection side possibility: */ 821: *_conns = conn; 822: } 823: 824: /* done: */ 825: return (TME_OK); 826: } 827: 828: /* the new _3c400 function: */ 829: TME_ELEMENT_SUB_NEW_DECL(tme_bus_multibus,3c400) { 830: struct tme_3c400 *_3c400; 831: tme_uint8_t arom[TME_ETHERNET_ADDR_SIZE]; 832: int arom_ok; 833: int arg_i; 834: int usage; 835: 836: /* check our arguments: */ 837: usage = 0; 838: arom_ok = FALSE; 839: arg_i = 1; 840: for (;;) { 841: 842: /* our Ethernet address ROM: */ 843: if (TME_ARG_IS(args[arg_i], "ether") 844: && tme_ethernet_addr_parse(args[arg_i + 1], arom) == TME_OK) { 845: arom_ok = TRUE; 846: arg_i += 2; 847: } 848: 849: /* if we ran out of arguments: */ 850: else if (args[arg_i] == NULL) { 851: 852: /* we must have been given our Ethernet address ROM: */ 853: if (!arom_ok) { 854: usage = TRUE; 855: } 856: break; 857: } 858: 859: /* otherwise this is a bad argument: */ 860: else { 861: tme_output_append_error(_output, 862: "%s %s, ", 863: args[arg_i], 864: _("unexpected")); 865: usage = TRUE; 866: break; 867: } 868: } 869: 870: if (usage) { 871: tme_output_append_error(_output, 872: "%s %s ether %s", 873: _("usage:"), 874: args[0], 875: _("ETHERNET-ADDRESS")); 876: return (EINVAL); 877: } 878: 879: /* start the _3c400 structure: */ 880: _3c400 = tme_new0(struct tme_3c400, 1); 881: _3c400->tme_3c400_element = element; 882: tme_mutex_init(&_3c400->tme_3c400_mutex); 883: tme_rwlock_init(&_3c400->tme_3c400_rwlock); 884: memcpy(_3c400->tme_3c400_card + TME_3C400_REG_AROM, 885: arom, 886: sizeof(arom)); 887: 888: /* initialize our simple bus device descriptor: */ 889: assert((TME_3C400_SIZ_CARD & (TME_3C400_SIZ_CARD - 1)) == 0); 890: _3c400->tme_3c400_device.tme_bus_device_element = element; 891: _3c400->tme_3c400_device.tme_bus_device_tlb_fill = _tme_3c400_tlb_fill; 892: _3c400->tme_3c400_device.tme_bus_device_address_last = TME_3C400_SIZ_CARD - 1; 893: 894: /* fill the element: */ 895: element->tme_element_private = _3c400; 896: element->tme_element_connections_new = _tme_3c400_connections_new; 897: 898: return (TME_OK); 899: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.