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