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