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