1 /* 2 * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved. 3 * Author: Denis I.Timofeev <timofeev@granch.ru> 4 * 5 * Redistributon and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 /* 31 * Device driver for Granch SBNI12 leased line adapters 32 * 33 * Revision 2.0.0 1997/08/06 34 * Initial revision by Alexey Zverev 35 * 36 * Revision 2.0.1 1997/08/11 37 * Additional internal statistics support (tx statistics) 38 * 39 * Revision 2.0.2 1997/11/05 40 * if_bpf bug has been fixed 41 * 42 * Revision 2.0.3 1998/12/20 43 * Memory leakage has been eliminated in 44 * the sbni_st and sbni_timeout routines. 45 * 46 * Revision 3.0 2000/08/10 by Yaroslav Polyakov 47 * Support for PCI cards. 4.1 modification. 48 * 49 * Revision 3.1 2000/09/12 50 * Removed extra #defines around bpf functions 51 * 52 * Revision 4.0 2000/11/23 by Denis Timofeev 53 * Completely redesigned the buffer management 54 * 55 * Revision 4.1 2001/01/21 56 * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards 57 * 58 * Written with reference to NE2000 driver developed by David Greenman. 59 */ 60 61 62 #include <sys/param.h> 63 #include <sys/systm.h> 64 #include <sys/socket.h> 65 #include <sys/sockio.h> 66 #include <sys/mbuf.h> 67 #include <sys/kernel.h> 68 #include <sys/proc.h> 69 #include <sys/callout.h> 70 #include <sys/syslog.h> 71 72 #include <net/if.h> 73 #include <net/ethernet.h> 74 #include <net/if_arp.h> 75 #include <net/bpf.h> 76 77 #include <dev/sbni/if_sbnireg.h> 78 #include <dev/sbni/if_sbnivar.h> 79 80 #define ASM_CRC 1 81 82 static void sbni_init(void *); 83 static void sbni_start(struct ifnet *); 84 static int sbni_ioctl(struct ifnet *, u_long, caddr_t); 85 static void sbni_watchdog(struct ifnet *); 86 static void sbni_stop(struct sbni_softc *); 87 static void handle_channel(struct sbni_softc *); 88 89 static void card_start(struct sbni_softc *); 90 static int recv_frame(struct sbni_softc *); 91 static void send_frame(struct sbni_softc *); 92 static int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 93 static int skip_tail(struct sbni_softc *, u_int, u_int32_t); 94 static void interpret_ack(struct sbni_softc *, u_int); 95 static void download_data(struct sbni_softc *, u_int32_t *); 96 static void prepare_to_send(struct sbni_softc *); 97 static void drop_xmit_queue(struct sbni_softc *); 98 static int get_rx_buf(struct sbni_softc *); 99 static void indicate_pkt(struct sbni_softc *); 100 static void change_level(struct sbni_softc *); 101 static int check_fhdr(struct sbni_softc *, u_int *, u_int *, 102 u_int *, u_int *, u_int32_t *); 103 static int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 104 static void timeout_change_level(struct sbni_softc *); 105 static void send_frame_header(struct sbni_softc *, u_int32_t *); 106 static void set_initial_values(struct sbni_softc *, struct sbni_flags); 107 108 static u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 109 static timeout_t sbni_timeout; 110 111 static __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 112 static __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 113 static __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 114 static __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 115 116 static u_int32_t crc32tab[]; 117 118 #ifdef SBNI_DUAL_COMPOUND 119 struct sbni_softc *headlist; 120 #endif 121 122 u_int32_t next_sbni_unit; 123 124 /* -------------------------------------------------------------------------- */ 125 126 static __inline u_char 127 sbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 128 { 129 return (inb(sc->base_addr + reg)); 130 } 131 132 static __inline void 133 sbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 134 { 135 outb(sc->base_addr + reg, value); 136 } 137 138 static __inline void 139 sbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 140 { 141 insb(sc->base_addr + DAT, to, len); 142 } 143 144 static __inline void 145 sbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 146 { 147 outsb(sc->base_addr + DAT, from, len); 148 } 149 150 151 /* 152 Valid combinations in CSR0 (for probing): 153 154 VALID_DECODER 0000,0011,1011,1010 155 156 ; 0 ; - 157 TR_REQ ; 1 ; + 158 TR_RDY ; 2 ; - 159 TR_RDY TR_REQ ; 3 ; + 160 BU_EMP ; 4 ; + 161 BU_EMP TR_REQ ; 5 ; + 162 BU_EMP TR_RDY ; 6 ; - 163 BU_EMP TR_RDY TR_REQ ; 7 ; + 164 RC_RDY ; 8 ; + 165 RC_RDY TR_REQ ; 9 ; + 166 RC_RDY TR_RDY ; 10 ; - 167 RC_RDY TR_RDY TR_REQ ; 11 ; - 168 RC_RDY BU_EMP ; 12 ; - 169 RC_RDY BU_EMP TR_REQ ; 13 ; - 170 RC_RDY BU_EMP TR_RDY ; 14 ; - 171 RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 172 */ 173 174 #define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 175 176 177 int 178 sbni_probe(struct sbni_softc *sc) 179 { 180 u_char csr0; 181 182 csr0 = sbni_inb(sc, CSR0); 183 if (csr0 != 0xff && csr0 != 0x00) { 184 csr0 &= ~EN_INT; 185 if (csr0 & BU_EMP) 186 csr0 |= EN_INT; 187 188 if (VALID_DECODER & (1 << (csr0 >> 4))) 189 return (0); 190 } 191 192 return (ENXIO); 193 } 194 195 196 /* 197 * Install interface into kernel networking data structures 198 */ 199 void 200 sbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 201 { 202 struct ifnet *ifp; 203 u_char csr0; 204 205 ifp = &sc->arpcom.ac_if; 206 sbni_outb(sc, CSR0, 0); 207 set_initial_values(sc, flags); 208 209 callout_handle_init(&sc->wch); 210 if (!ifp->if_name) { 211 /* Initialize ifnet structure */ 212 ifp->if_softc = sc; 213 ifp->if_unit = unit; 214 ifp->if_name = "sbni"; 215 ifp->if_init = sbni_init; 216 ifp->if_start = sbni_start; 217 ifp->if_output = ether_output; 218 ifp->if_ioctl = sbni_ioctl; 219 ifp->if_watchdog = sbni_watchdog; 220 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 221 222 /* report real baud rate */ 223 csr0 = sbni_inb(sc, CSR0); 224 ifp->if_baudrate = 225 (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 226 227 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 228 ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 229 } 230 /* device attach does transition from UNCONFIGURED to IDLE state */ 231 232 printf("%s%d: speed %ld, address %6D, rxl ", ifp->if_name, 233 ifp->if_unit, ifp->if_baudrate, sc->arpcom.ac_enaddr, ":"); 234 if (sc->delta_rxl) 235 printf("auto\n"); 236 else 237 printf("%d (fixed)\n", sc->cur_rxl_index); 238 } 239 240 /* -------------------------------------------------------------------------- */ 241 242 static void 243 sbni_init(void *xsc) 244 { 245 struct sbni_softc *sc; 246 struct ifnet *ifp; 247 int s; 248 249 sc = (struct sbni_softc *)xsc; 250 ifp = &sc->arpcom.ac_if; 251 252 /* address not known */ 253 if (TAILQ_EMPTY(&ifp->if_addrhead)) 254 return; 255 256 /* 257 * kludge to avoid multiple initialization when more than once 258 * protocols configured 259 */ 260 if (ifp->if_flags & IFF_RUNNING) 261 return; 262 263 s = splimp(); 264 ifp->if_timer = 0; 265 card_start(sc); 266 sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 267 268 ifp->if_flags |= IFF_RUNNING; 269 ifp->if_flags &= ~IFF_OACTIVE; 270 271 /* attempt to start output */ 272 sbni_start(ifp); 273 splx(s); 274 } 275 276 277 static void 278 sbni_start(struct ifnet *ifp) 279 { 280 struct sbni_softc *sc = ifp->if_softc; 281 if (sc->tx_frameno == 0) 282 prepare_to_send(sc); 283 } 284 285 286 static void 287 sbni_stop(struct sbni_softc *sc) 288 { 289 sbni_outb(sc, CSR0, 0); 290 drop_xmit_queue(sc); 291 292 if (sc->rx_buf_p) { 293 m_freem(sc->rx_buf_p); 294 sc->rx_buf_p = NULL; 295 } 296 297 untimeout(sbni_timeout, sc, sc->wch); 298 sc->wch.callout = NULL; 299 } 300 301 /* -------------------------------------------------------------------------- */ 302 303 /* interrupt handler */ 304 305 /* 306 * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 307 * be looked as two independent single-channel devices. Every channel seems 308 * as Ethernet interface but interrupt handler must be common. Really, first 309 * channel ("master") driver only registers the handler. In it's struct softc 310 * it has got pointer to "slave" channel's struct softc and handles that's 311 * interrupts too. 312 * softc of successfully attached ISA SBNI boards is linked to list. 313 * While next board driver is initialized, it scans this list. If one 314 * has found softc with same irq and ioaddr different by 4 then it assumes 315 * this board to be "master". 316 */ 317 318 void 319 sbni_intr(void *arg) 320 { 321 struct sbni_softc *sc; 322 int repeat; 323 324 sc = (struct sbni_softc *)arg; 325 326 do { 327 repeat = 0; 328 if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 329 handle_channel(sc); 330 repeat = 1; 331 } 332 if (sc->slave_sc /* second channel present */ 333 && (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) { 334 handle_channel(sc->slave_sc); 335 repeat = 1; 336 } 337 } while (repeat); 338 } 339 340 341 static void 342 handle_channel(struct sbni_softc *sc) 343 { 344 int req_ans; 345 u_char csr0; 346 347 sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 348 349 sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 350 for (;;) { 351 csr0 = sbni_inb(sc, CSR0); 352 if ((csr0 & (RC_RDY | TR_RDY)) == 0) 353 break; 354 355 req_ans = !(sc->state & FL_PREV_OK); 356 357 if (csr0 & RC_RDY) 358 req_ans = recv_frame(sc); 359 360 /* 361 * TR_RDY always equals 1 here because we have owned the marker, 362 * and we set TR_REQ when disabled interrupts 363 */ 364 csr0 = sbni_inb(sc, CSR0); 365 if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 366 printf("sbni: internal error!\n"); 367 368 /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 369 if (req_ans || sc->tx_frameno != 0) 370 send_frame(sc); 371 else 372 /* send the marker without any data */ 373 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 374 } 375 376 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 377 } 378 379 380 /* 381 * Routine returns 1 if it need to acknoweledge received frame. 382 * Empty frame received without errors won't be acknoweledged. 383 */ 384 385 static int 386 recv_frame(struct sbni_softc *sc) 387 { 388 u_int32_t crc; 389 u_int framelen, frameno, ack; 390 u_int is_first, frame_ok; 391 392 crc = CRC32_INITIAL; 393 if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 394 frame_ok = framelen > 4 395 ? upload_data(sc, framelen, frameno, is_first, crc) 396 : skip_tail(sc, framelen, crc); 397 if (frame_ok) 398 interpret_ack(sc, ack); 399 } else 400 frame_ok = 0; 401 402 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 403 if (frame_ok) { 404 sc->state |= FL_PREV_OK; 405 if (framelen > 4) 406 sc->in_stats.all_rx_number++; 407 } else { 408 sc->state &= ~FL_PREV_OK; 409 change_level(sc); 410 sc->in_stats.all_rx_number++; 411 sc->in_stats.bad_rx_number++; 412 } 413 414 return (!frame_ok || framelen > 4); 415 } 416 417 418 static void 419 send_frame(struct sbni_softc *sc) 420 { 421 u_int32_t crc; 422 u_char csr0; 423 424 crc = CRC32_INITIAL; 425 if (sc->state & FL_NEED_RESEND) { 426 427 /* if frame was sended but not ACK'ed - resend it */ 428 if (sc->trans_errors) { 429 sc->trans_errors--; 430 if (sc->framelen != 0) 431 sc->in_stats.resend_tx_number++; 432 } else { 433 /* cannot xmit with many attempts */ 434 drop_xmit_queue(sc); 435 goto do_send; 436 } 437 } else 438 sc->trans_errors = TR_ERROR_COUNT; 439 440 send_frame_header(sc, &crc); 441 sc->state |= FL_NEED_RESEND; 442 /* 443 * FL_NEED_RESEND will be cleared after ACK, but if empty 444 * frame sended then in prepare_to_send next frame 445 */ 446 447 448 if (sc->framelen) { 449 download_data(sc, &crc); 450 sc->in_stats.all_tx_number++; 451 sc->state |= FL_WAIT_ACK; 452 } 453 454 sbni_outsb(sc, (u_char *)&crc, sizeof crc); 455 456 do_send: 457 csr0 = sbni_inb(sc, CSR0); 458 sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 459 460 if (sc->tx_frameno) { 461 /* next frame exists - request to send */ 462 sbni_outb(sc, CSR0, csr0 | TR_REQ); 463 } 464 } 465 466 467 static void 468 download_data(struct sbni_softc *sc, u_int32_t *crc_p) 469 { 470 struct mbuf *m; 471 caddr_t data_p; 472 u_int data_len, pos, slice; 473 474 data_p = NULL; /* initialized to avoid warn */ 475 pos = 0; 476 477 for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 478 if (pos + m->m_len > sc->outpos) { 479 data_len = m->m_len - (sc->outpos - pos); 480 data_p = mtod(m, caddr_t) + (sc->outpos - pos); 481 482 goto do_copy; 483 } else 484 pos += m->m_len; 485 } 486 487 data_len = 0; 488 489 do_copy: 490 pos = 0; 491 do { 492 if (data_len) { 493 slice = min(data_len, sc->framelen - pos); 494 sbni_outsb(sc, data_p, slice); 495 *crc_p = calc_crc32(*crc_p, data_p, slice); 496 497 pos += slice; 498 if (data_len -= slice) 499 data_p += slice; 500 else { 501 do m = m->m_next; 502 while (m != NULL && m->m_len == 0); 503 504 if (m) { 505 data_len = m->m_len; 506 data_p = mtod(m, caddr_t); 507 } 508 } 509 } else { 510 /* frame too short - zero padding */ 511 512 pos = sc->framelen - pos; 513 while (pos--) { 514 sbni_outb(sc, DAT, 0); 515 *crc_p = CRC32(0, *crc_p); 516 } 517 return; 518 } 519 } while (pos < sc->framelen); 520 } 521 522 523 static int 524 upload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 525 u_int is_first, u_int32_t crc) 526 { 527 int frame_ok; 528 529 if (is_first) { 530 sc->wait_frameno = frameno; 531 sc->inppos = 0; 532 } 533 534 if (sc->wait_frameno == frameno) { 535 536 if (sc->inppos + framelen <= ETHER_MAX_LEN) { 537 frame_ok = append_frame_to_pkt(sc, framelen, crc); 538 539 /* 540 * if CRC is right but framelen incorrect then transmitter 541 * error was occured... drop entire packet 542 */ 543 } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 544 sc->wait_frameno = 0; 545 sc->inppos = 0; 546 sc->arpcom.ac_if.if_ierrors++; 547 /* now skip all frames until is_first != 0 */ 548 } 549 } else 550 frame_ok = skip_tail(sc, framelen, crc); 551 552 if (is_first && !frame_ok) { 553 /* 554 * Frame has been violated, but we have stored 555 * is_first already... Drop entire packet. 556 */ 557 sc->wait_frameno = 0; 558 sc->arpcom.ac_if.if_ierrors++; 559 } 560 561 return (frame_ok); 562 } 563 564 565 static __inline void send_complete(struct sbni_softc *); 566 567 static __inline void 568 send_complete(struct sbni_softc *sc) 569 { 570 m_freem(sc->tx_buf_p); 571 sc->tx_buf_p = NULL; 572 sc->arpcom.ac_if.if_opackets++; 573 } 574 575 576 static void 577 interpret_ack(struct sbni_softc *sc, u_int ack) 578 { 579 if (ack == FRAME_SENT_OK) { 580 sc->state &= ~FL_NEED_RESEND; 581 582 if (sc->state & FL_WAIT_ACK) { 583 sc->outpos += sc->framelen; 584 585 if (--sc->tx_frameno) 586 sc->framelen = min(sc->maxframe, 587 sc->pktlen - sc->outpos); 588 else { 589 send_complete(sc); 590 prepare_to_send(sc); 591 } 592 } 593 } 594 595 sc->state &= ~FL_WAIT_ACK; 596 } 597 598 599 /* 600 * Glue received frame with previous fragments of packet. 601 * Indicate packet when last frame would be accepted. 602 */ 603 604 static int 605 append_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 606 { 607 caddr_t p; 608 609 if (sc->inppos + framelen > ETHER_MAX_LEN) 610 return (0); 611 612 if (!sc->rx_buf_p && !get_rx_buf(sc)) 613 return (0); 614 615 p = sc->rx_buf_p->m_data + sc->inppos; 616 sbni_insb(sc, p, framelen); 617 if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 618 return (0); 619 620 sc->inppos += framelen - 4; 621 if (--sc->wait_frameno == 0) { /* last frame received */ 622 indicate_pkt(sc); 623 sc->arpcom.ac_if.if_ipackets++; 624 } 625 626 return (1); 627 } 628 629 630 /* 631 * Prepare to start output on adapter. Current priority must be set to splimp 632 * before this routine is called. 633 * Transmitter will be actually activated when marker has been accepted. 634 */ 635 636 static void 637 prepare_to_send(struct sbni_softc *sc) 638 { 639 struct mbuf *m; 640 u_int len; 641 642 /* sc->tx_buf_p == NULL here! */ 643 if (sc->tx_buf_p) 644 printf("sbni: memory leak!\n"); 645 646 sc->outpos = 0; 647 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 648 649 for (;;) { 650 IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, sc->tx_buf_p); 651 if (!sc->tx_buf_p) { 652 /* nothing to transmit... */ 653 sc->pktlen = 0; 654 sc->tx_frameno = 0; 655 sc->framelen = 0; 656 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 657 return; 658 } 659 660 for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 661 len += m->m_len; 662 663 if (len != 0) 664 break; 665 m_freem(sc->tx_buf_p); 666 } 667 668 if (len < SBNI_MIN_LEN) 669 len = SBNI_MIN_LEN; 670 671 sc->pktlen = len; 672 sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe; 673 sc->framelen = min(len, sc->maxframe); 674 675 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 676 sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; 677 if (sc->arpcom.ac_if.if_bpf) 678 bpf_mtap(&sc->arpcom.ac_if, sc->tx_buf_p); 679 } 680 681 682 static void 683 drop_xmit_queue(struct sbni_softc *sc) 684 { 685 struct mbuf *m; 686 687 if (sc->tx_buf_p) { 688 m_freem(sc->tx_buf_p); 689 sc->tx_buf_p = NULL; 690 sc->arpcom.ac_if.if_oerrors++; 691 } 692 693 for (;;) { 694 IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 695 if (m == NULL) 696 break; 697 m_freem(m); 698 sc->arpcom.ac_if.if_oerrors++; 699 } 700 701 sc->tx_frameno = 0; 702 sc->framelen = 0; 703 sc->outpos = 0; 704 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 705 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 706 } 707 708 709 static void 710 send_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 711 { 712 u_int32_t crc; 713 u_int len_field; 714 u_char value; 715 716 crc = *crc_p; 717 len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 718 719 if (sc->state & FL_NEED_RESEND) 720 len_field |= FRAME_RETRY; /* non-first attempt... */ 721 722 if (sc->outpos == 0) 723 len_field |= FRAME_FIRST; 724 725 len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 726 sbni_outb(sc, DAT, SBNI_SIG); 727 728 value = (u_char)len_field; 729 sbni_outb(sc, DAT, value); 730 crc = CRC32(value, crc); 731 value = (u_char)(len_field >> 8); 732 sbni_outb(sc, DAT, value); 733 crc = CRC32(value, crc); 734 735 sbni_outb(sc, DAT, sc->tx_frameno); 736 crc = CRC32(sc->tx_frameno, crc); 737 sbni_outb(sc, DAT, 0); 738 crc = CRC32(0, crc); 739 *crc_p = crc; 740 } 741 742 743 /* 744 * if frame tail not needed (incorrect number or received twice), 745 * it won't store, but CRC will be calculated 746 */ 747 748 static int 749 skip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 750 { 751 while (tail_len--) 752 crc = CRC32(sbni_inb(sc, DAT), crc); 753 754 return (crc == CRC32_REMAINDER); 755 } 756 757 758 static int 759 check_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 760 u_int *ack, u_int *is_first, u_int32_t *crc_p) 761 { 762 u_int32_t crc; 763 u_char value; 764 765 crc = *crc_p; 766 if (sbni_inb(sc, DAT) != SBNI_SIG) 767 return (0); 768 769 value = sbni_inb(sc, DAT); 770 *framelen = (u_int)value; 771 crc = CRC32(value, crc); 772 value = sbni_inb(sc, DAT); 773 *framelen |= ((u_int)value) << 8; 774 crc = CRC32(value, crc); 775 776 *ack = *framelen & FRAME_ACK_MASK; 777 *is_first = (*framelen & FRAME_FIRST) != 0; 778 779 if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 780 return (0); 781 782 value = sbni_inb(sc, DAT); 783 *frameno = (u_int)value; 784 crc = CRC32(value, crc); 785 786 crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 787 *framelen -= 2; 788 789 *crc_p = crc; 790 return (1); 791 } 792 793 794 static int 795 get_rx_buf(struct sbni_softc *sc) 796 { 797 struct mbuf *m; 798 799 MGETHDR(m, M_DONTWAIT, MT_DATA); 800 if (m == NULL) { 801 printf("sbni%d: cannot allocate header mbuf\n", 802 sc->arpcom.ac_if.if_unit); 803 return (0); 804 } 805 806 /* 807 * We always put the received packet in a single buffer - 808 * either with just an mbuf header or in a cluster attached 809 * to the header. The +2 is to compensate for the alignment 810 * fixup below. 811 */ 812 if (ETHER_MAX_LEN + 2 > MHLEN) { 813 /* Attach an mbuf cluster */ 814 MCLGET(m, M_DONTWAIT); 815 if ((m->m_flags & M_EXT) == 0) { 816 m_freem(m); 817 return (0); 818 } 819 } 820 m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 821 822 /* 823 * The +2 is to longword align the start of the real packet. 824 * (sizeof ether_header == 14) 825 * This is important for NFS. 826 */ 827 m_adj(m, 2); 828 sc->rx_buf_p = m; 829 return (1); 830 } 831 832 833 static void 834 indicate_pkt(struct sbni_softc *sc) 835 { 836 struct mbuf *m; 837 struct ether_header *eh; 838 839 m = sc->rx_buf_p; 840 m->m_pkthdr.rcvif = &sc->arpcom.ac_if; 841 m->m_pkthdr.len = m->m_len = sc->inppos; 842 eh = mtod(m, struct ether_header *); 843 844 /* Remove link layer address and indicate packet */ 845 m_adj(m, sizeof(struct ether_header)); 846 ether_input(&sc->arpcom.ac_if, eh, m); 847 sc->rx_buf_p = NULL; 848 } 849 850 /* -------------------------------------------------------------------------- */ 851 852 /* 853 * Routine checks periodically wire activity and regenerates marker if 854 * connect was inactive for a long time. 855 */ 856 857 static void 858 sbni_timeout(void *xsc) 859 { 860 struct sbni_softc *sc; 861 int s; 862 u_char csr0; 863 864 sc = (struct sbni_softc *)xsc; 865 s = splimp(); 866 867 csr0 = sbni_inb(sc, CSR0); 868 if (csr0 & RC_CHK) { 869 870 if (sc->timer_ticks) { 871 if (csr0 & (RC_RDY | BU_EMP)) 872 /* receiving not active */ 873 sc->timer_ticks--; 874 } else { 875 sc->in_stats.timeout_number++; 876 if (sc->delta_rxl) 877 timeout_change_level(sc); 878 879 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 880 csr0 = sbni_inb(sc, CSR0); 881 } 882 } 883 884 sbni_outb(sc, CSR0, csr0 | RC_CHK); 885 sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 886 splx(s); 887 } 888 889 /* -------------------------------------------------------------------------- */ 890 891 static void 892 card_start(struct sbni_softc *sc) 893 { 894 sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 895 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 896 sc->state |= FL_PREV_OK; 897 898 sc->inppos = 0; 899 sc->wait_frameno = 0; 900 901 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 902 sbni_outb(sc, CSR0, EN_INT); 903 } 904 905 /* -------------------------------------------------------------------------- */ 906 907 /* 908 * Device timeout/watchdog routine. Entered if the device neglects to 909 * generate an interrupt after a transmit has been started on it. 910 */ 911 912 static void 913 sbni_watchdog(struct ifnet *ifp) 914 { 915 log(LOG_ERR, "sbni%d: device timeout\n", ifp->if_unit); 916 ifp->if_oerrors++; 917 } 918 919 920 static u_char rxl_tab[] = { 921 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 922 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 923 }; 924 925 #define SIZE_OF_TIMEOUT_RXL_TAB 4 926 static u_char timeout_rxl_tab[] = { 927 0x03, 0x05, 0x08, 0x0b 928 }; 929 930 static void 931 set_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 932 { 933 if (flags.fixed_rxl) { 934 sc->delta_rxl = 0; /* disable receive level autodetection */ 935 sc->cur_rxl_index = flags.rxl; 936 } else { 937 sc->delta_rxl = DEF_RXL_DELTA; 938 sc->cur_rxl_index = DEF_RXL; 939 } 940 941 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 942 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 943 sc->maxframe = DEFAULT_FRAME_LEN; 944 945 /* 946 * generate Ethernet address (0x00ff01xxxxxx) 947 */ 948 *(u_int16_t*)sc->arpcom.ac_enaddr = htons(0x00ff); 949 if (flags.mac_addr) 950 *(u_int32_t*)(sc->arpcom.ac_enaddr+2) = 951 htonl(flags.mac_addr | 0x01000000); 952 else { 953 /* reading timer value */ 954 outb(0x43, 0); 955 insb(0x40, sc->arpcom.ac_enaddr + 3, 4); 956 *(u_char*)(sc->arpcom.ac_enaddr + 2) = 0x01; 957 } 958 } 959 960 961 #ifdef SBNI_DUAL_COMPOUND 962 963 #ifndef offsetof 964 #define offsetof(type, member) ((u_int32_t)(&((type *)0)->member)) 965 #endif 966 967 968 struct sbni_softc * 969 connect_to_master(struct sbni_softc *sc) 970 { 971 struct sbni_softc *p; 972 973 p = (struct sbni_softc *)(((char *)&headlist) 974 - offsetof(struct sbni_softc, link)); 975 976 for (; p->link; p = p->link) { 977 if (p->link->irq == sc->irq 978 && (p->link->base_addr == sc->base_addr + 4 979 || p->link->base_addr == sc->base_addr - 4)) { 980 981 struct sbni_softc *t = p->link; 982 t->slave_sc = sc; 983 p->link = p->link->link; 984 return (t); 985 } 986 } 987 988 return (NULL); 989 } 990 991 #endif /* SBNI_DUAL_COMPOUND */ 992 993 994 /* Receive level auto-selection */ 995 996 static void 997 change_level(struct sbni_softc *sc) 998 { 999 if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 1000 return; 1001 1002 if (sc->cur_rxl_index == 0) 1003 sc->delta_rxl = 1; 1004 else if (sc->cur_rxl_index == 15) 1005 sc->delta_rxl = -1; 1006 else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 1007 sc->delta_rxl = -sc->delta_rxl; 1008 1009 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 1010 sbni_inb(sc, CSR0); /* it needed for PCI cards */ 1011 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1012 1013 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1014 sc->cur_rxl_rcvd = 0; 1015 } 1016 1017 1018 static void 1019 timeout_change_level(struct sbni_softc *sc) 1020 { 1021 sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 1022 if (++sc->timeout_rxl >= 4) 1023 sc->timeout_rxl = 0; 1024 1025 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1026 sbni_inb(sc, CSR0); 1027 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1028 1029 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1030 sc->cur_rxl_rcvd = 0; 1031 } 1032 1033 /* -------------------------------------------------------------------------- */ 1034 1035 /* 1036 * Process an ioctl request. This code needs some work - it looks 1037 * pretty ugly. 1038 */ 1039 1040 static int 1041 sbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1042 { 1043 struct sbni_softc *sc; 1044 struct ifreq *ifr; 1045 struct proc *p; 1046 struct sbni_in_stats *in_stats; 1047 struct sbni_flags flags; 1048 int error, s; 1049 1050 sc = ifp->if_softc; 1051 ifr = (struct ifreq *)data; 1052 p = curproc; 1053 error = 0; 1054 1055 s = splimp(); 1056 1057 switch (command) { 1058 case SIOCSIFADDR: 1059 case SIOCGIFADDR: 1060 ether_ioctl(ifp, command, data); 1061 break; 1062 1063 case SIOCSIFFLAGS: 1064 /* 1065 * If the interface is marked up and stopped, then start it. 1066 * If it is marked down and running, then stop it. 1067 */ 1068 if (ifp->if_flags & IFF_UP) { 1069 if (!(ifp->if_flags & IFF_RUNNING)) 1070 sbni_init(sc); 1071 } else { 1072 if (ifp->if_flags & IFF_RUNNING) { 1073 sbni_stop(sc); 1074 ifp->if_flags &= ~IFF_RUNNING; 1075 } 1076 } 1077 break; 1078 1079 case SIOCADDMULTI: 1080 case SIOCDELMULTI: 1081 /* 1082 * Multicast list has changed; set the hardware filter 1083 * accordingly. 1084 */ 1085 error = 0; 1086 /* if (ifr == NULL) 1087 error = EAFNOSUPPORT; */ 1088 break; 1089 1090 case SIOCSIFMTU: 1091 if (ifr->ifr_mtu > ETHERMTU) 1092 error = EINVAL; 1093 else 1094 ifp->if_mtu = ifr->ifr_mtu; 1095 break; 1096 1097 /* 1098 * SBNI specific ioctl 1099 */ 1100 case SIOCGHWFLAGS: /* get flags */ 1101 bcopy((caddr_t) sc->arpcom.ac_enaddr+3, (caddr_t) &flags, 3); 1102 flags.rxl = sc->cur_rxl_index; 1103 flags.rate = sc->csr1.rate; 1104 flags.fixed_rxl = (sc->delta_rxl == 0); 1105 flags.fixed_rate = 1; 1106 ifr->ifr_data = *(caddr_t*) &flags; 1107 break; 1108 1109 case SIOCGINSTATS: 1110 in_stats = (struct sbni_in_stats *)ifr->ifr_data; 1111 bcopy((void *)(&(sc->in_stats)), (void *)in_stats, 1112 sizeof(struct sbni_in_stats)); 1113 break; 1114 1115 case SIOCSHWFLAGS: /* set flags */ 1116 /* root only */ 1117 error = suser(p); 1118 if (error) 1119 break; 1120 flags = *(struct sbni_flags*)&ifr->ifr_data; 1121 if (flags.fixed_rxl) { 1122 sc->delta_rxl = 0; 1123 sc->cur_rxl_index = flags.rxl; 1124 } else { 1125 sc->delta_rxl = DEF_RXL_DELTA; 1126 sc->cur_rxl_index = DEF_RXL; 1127 } 1128 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1129 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 1130 if (flags.mac_addr) 1131 bcopy((caddr_t) &flags, 1132 (caddr_t) sc->arpcom.ac_enaddr+3, 3); 1133 1134 /* Don't be afraid... */ 1135 sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 1136 break; 1137 1138 case SIOCRINSTATS: 1139 if (!(error = suser(p))) /* root only */ 1140 bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 1141 break; 1142 1143 default: 1144 error = EINVAL; 1145 } 1146 1147 splx(s); 1148 return (error); 1149 } 1150 1151 /* -------------------------------------------------------------------------- */ 1152 1153 #ifdef ASM_CRC 1154 1155 static u_int32_t 1156 calc_crc32(u_int32_t crc, caddr_t p, u_int len) 1157 { 1158 register u_int32_t _crc __asm ("ax"); 1159 _crc = crc; 1160 1161 __asm __volatile ( 1162 "xorl %%ebx, %%ebx\n" 1163 "movl %1, %%esi\n" 1164 "movl %2, %%ecx\n" 1165 "movl $crc32tab, %%edi\n" 1166 "shrl $2, %%ecx\n" 1167 "jz 1f\n" 1168 1169 ".align 4\n" 1170 "0:\n" 1171 "movb %%al, %%bl\n" 1172 "movl (%%esi), %%edx\n" 1173 "shrl $8, %%eax\n" 1174 "xorb %%dl, %%bl\n" 1175 "shrl $8, %%edx\n" 1176 "xorl (%%edi,%%ebx,4), %%eax\n" 1177 1178 "movb %%al, %%bl\n" 1179 "shrl $8, %%eax\n" 1180 "xorb %%dl, %%bl\n" 1181 "shrl $8, %%edx\n" 1182 "xorl (%%edi,%%ebx,4), %%eax\n" 1183 1184 "movb %%al, %%bl\n" 1185 "shrl $8, %%eax\n" 1186 "xorb %%dl, %%bl\n" 1187 "movb %%dh, %%dl\n" 1188 "xorl (%%edi,%%ebx,4), %%eax\n" 1189 1190 "movb %%al, %%bl\n" 1191 "shrl $8, %%eax\n" 1192 "xorb %%dl, %%bl\n" 1193 "addl $4, %%esi\n" 1194 "xorl (%%edi,%%ebx,4), %%eax\n" 1195 1196 "decl %%ecx\n" 1197 "jnz 0b\n" 1198 1199 "1:\n" 1200 "movl %2, %%ecx\n" 1201 "andl $3, %%ecx\n" 1202 "jz 2f\n" 1203 1204 "movb %%al, %%bl\n" 1205 "shrl $8, %%eax\n" 1206 "xorb (%%esi), %%bl\n" 1207 "xorl (%%edi,%%ebx,4), %%eax\n" 1208 1209 "decl %%ecx\n" 1210 "jz 2f\n" 1211 1212 "movb %%al, %%bl\n" 1213 "shrl $8, %%eax\n" 1214 "xorb 1(%%esi), %%bl\n" 1215 "xorl (%%edi,%%ebx,4), %%eax\n" 1216 1217 "decl %%ecx\n" 1218 "jz 2f\n" 1219 1220 "movb %%al, %%bl\n" 1221 "shrl $8, %%eax\n" 1222 "xorb 2(%%esi), %%bl\n" 1223 "xorl (%%edi,%%ebx,4), %%eax\n" 1224 "2:\n" 1225 : 1226 : "a" (_crc), "g" (p), "g" (len) 1227 : "ax", "bx", "cx", "dx", "si", "di" 1228 ); 1229 1230 return (_crc); 1231 } 1232 1233 #else /* ASM_CRC */ 1234 1235 static u_int32_t 1236 calc_crc32(u_int32_t crc, caddr_t p, u_int len) 1237 { 1238 while (len--) 1239 crc = CRC32(*p++, crc); 1240 1241 return (crc); 1242 } 1243 1244 #endif /* ASM_CRC */ 1245 1246 1247 static u_int32_t crc32tab[] __attribute__ ((aligned(8))) = { 1248 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 1249 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 1250 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 1251 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 1252 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 1253 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 1254 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 1255 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 1256 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 1257 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 1258 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 1259 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 1260 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 1261 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 1262 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 1263 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 1264 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 1265 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 1266 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 1267 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 1268 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 1269 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 1270 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 1271 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 1272 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 1273 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 1274 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 1275 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 1276 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 1277 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 1278 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 1279 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 1280 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 1281 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 1282 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 1283 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 1284 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 1285 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 1286 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 1287 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 1288 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 1289 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 1290 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 1291 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 1292 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 1293 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 1294 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 1295 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 1296 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 1297 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 1298 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 1299 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 1300 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 1301 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 1302 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 1303 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 1304 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 1305 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 1306 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 1307 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 1308 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 1309 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 1310 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 1311 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 1312 }; 1313