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