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