lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:   Wed, 27 Feb 2019 15:18:09 +0800
From:   Morris Ku <saumah@...il.com>
To:     gregkh@...uxfoundation.org
Cc:     morris_ku@...ix.com, linux-kernel@...r.kernel.org,
        Morris Ku <saumah@...il.com>
Subject: [PATCH 3/5] Add SUNIX Multi-I/O board driver

Add driver, Kconfig and Makefile entry.
---
 char/snx/Kconfig        |    7 +
 char/snx/Makefile       |    9 +
 char/snx/snx_devtable.c |  669 +++++++++++++++++
 char/snx/snx_main.c     | 1583 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 2268 insertions(+)
 create mode 100644 char/snx/Kconfig
 create mode 100644 char/snx/Makefile
 create mode 100644 char/snx/snx_devtable.c
 create mode 100644 char/snx/snx_main.c

diff --git a/char/snx/Kconfig b/char/snx/Kconfig
new file mode 100644
index 00000000..d203c850
--- /dev/null
+++ b/char/snx/Kconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Character device configuration
+#
+
+config SNX
+	tristate "SUNIX Multi-IO Board Drvier"
diff --git a/char/snx/Makefile b/char/snx/Makefile
new file mode 100644
index 00000000..47348926
--- /dev/null
+++ b/char/snx/Makefile
@@ -0,0 +1,9 @@
+#
+# drivers/char/snx/Makefile
+#
+# Makefile for the sunix multi-io device drivers.
+#
+
+obj-$(CONFIG_SNX) += snx.o
+
+snx-y := snx_main.o snx_devtable.o snx_serial.o snx_parallel.o snx_share.o snx_ieee1284.o snx_ieee1284_ops.o snx_ppdev.o snx_lp.o
diff --git a/char/snx/snx_devtable.c b/char/snx/snx_devtable.c
new file mode 100644
index 00000000..9084f006
--- /dev/null
+++ b/char/snx/snx_devtable.c
@@ -0,0 +1,669 @@
+#include "snx_common.h"
+
+
+PCI_BOARD snx_pci_board_conf[] = {
+	// mode none
+	{
+		// VenID		DevID			SubVenID			SubSysID			SerPort	ParPort	IntrBar	IntrOffset	Name		BoardFlag   part_number
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_TEST,		0,		0,		0,		0x00,		"none",		BOARDFLAG_NONE,	PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	'n',	-1,		0,		0,			-1,		0,		0,		0x0000,		SUNNONE_HWID	},
+		},
+	},
+
+	// mode 4027A
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4027A,		1,		0,		0,		0x1C,		"4027",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+		},
+	},
+
+	// mode 4027D
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4027D,		1,		0,		0,		0x00,		"4027",		BOARDFLAG_REMAP, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	2,		0,		8,			-1,		0,		0,		0x0000,		SUN1699_HWID	},
+		},
+	},
+
+	// mode 4037A, 4037AL
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4037A,		2,		0,		0,		0x1C,		"4037",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+		},
+	},
+
+	// mode 4037D
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4037D,		2,		0,		0,		0x00,		"4037",		BOARDFLAG_REMAP, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	2,		0,		8,			-1,		0,		0,		0x0000,		SUN1699_HWID	},
+			{	's',	3,		0,		8,			-1,		0,		0,		0x0000,		SUN1699_HWID	},
+		},
+	},
+
+	// mode 4036A3V
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4036A3V,	2,		0,		0,		0x1C,		"4036",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+		},
+	},
+
+
+	// mode 4056A, 4056P
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4056A,		4,		0,		0,		0x1C,		"4056",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+		},
+	},
+
+
+	// mode 4056D
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4056D,		4,		0,		0,		0x00,		"4056",		BOARDFLAG_REMAP, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	2,		0,		8,			-1,		0,		0,		0x0000,		SUN1699_HWID	},
+			{	's',	3,		0,		8,			-1,		0,		0,		0x0000,		SUN1699_HWID	},
+			{	's',	4,		0,		8,			-1,		0,		0,		0x0000,		SUN1699_HWID	},
+			{	's',	5,		0,		8,			-1,		0,		0,		0x0000,		SUN1699_HWID	},
+		},
+	},
+
+	// mode 4055WN, 4056WN, 4056DW
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4056DW,	4,		0,		0,		0x1C,		"4056",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+		},
+	},
+
+	// mode 4066A
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4066A,		8,		0,		0,		0x1C,		"4066",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+			{	's',	2,		0,		8,			-1,		0,		0,		0x0010,		SUN1699_HWID	},
+			{	's',	3,		0,		8,			-1,		0,		0,		0x0020,		SUN1699_HWID	},
+			{	's',	4,		0,		8,			-1,		0,		0,		0x0040,		SUN1699_HWID	},
+			{	's',	5,		0,		8,			-1,		0,		0,		0x0080,		SUN1699_HWID	},
+		},
+	},
+
+	// mode 4066R
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4066R,		8,		0,		0,		0x1C,		"4066",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+			{	's',	2,		0,		8,			-1,		0,		0,		0x0010,		SUN1699_HWID	},
+			{	's',	3,		0,		8,			-1,		0,		0,		0x0020,		SUN1699_HWID	},
+			{	's',	4,		0,		8,			-1,		0,		0,		0x0040,		SUN1699_HWID	},
+			{	's',	5,		0,		8,			-1,		0,		0,		0x0080,		SUN1699_HWID	},
+		},
+	},
+
+	// mode 8139
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_8139,		2,		0,		0,		0x1C,		"8139",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+		},
+	},
+
+	// mode 8139S, 8139SI
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_8139S,		2,		0,		0,		0x1C,		"8139",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+		},
+	},
+
+	// mode 8159
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_8159,		4,		0,		0,		0x1C,		"8159",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+		},
+	},
+
+// mode 8159S, 8159SI
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_8159S,		4,		0,		0,		0x1C,		"8159",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+		},
+	},
+
+	// mode 8169
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_8169,		8,		0,		0,		0x1C,		"8169",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+			{	's',	2,		0,		8,			-1,		0,		0,		0x0010,		SUN1699_HWID	},
+			{	's',	3,		0,		8,			-1,		0,		0,		0x0020,		SUN1699_HWID	},
+			{	's',	4,		0,		8,			-1,		0,		0,		0x0040,		SUN1699_HWID	},
+			{	's',	5,		0,		8,			-1,		0,		0,		0x0080,		SUN1699_HWID	},
+		},
+	},
+
+	// mode 8169S, 8169SI
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_8169S,		8,		0,		0,		0x1C,		"8169",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+			{	's',	2,		0,		8,			-1,		0,		0,		0x0010,		SUN1699_HWID	},
+			{	's',	3,		0,		8,			-1,		0,		0,		0x0020,		SUN1699_HWID	},
+			{	's',	4,		0,		8,			-1,		0,		0,		0x0040,		SUN1699_HWID	},
+			{	's',	5,		0,		8,			-1,		0,		0,		0x0080,		SUN1699_HWID	},
+		},
+	},
+
+
+	/* support by system parport_pc driver
+	// mode 4008A
+	{
+		VENID_GOLDEN,	DEVID_G_PARALL,	SUBVENID_GOLDEN,	SUBDEVID_4008A,		0,		1,		0,		0x00,		"4008",		BOARDFLAG_NONE, PART_NUMBER_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	'p',	0,		0,		8,			 1,		0,		8,		0x0000,		SUN1888_HWID	},
+		},
+	},
+
+	// mode 4018A
+	{
+		VENID_GOLDEN,	DEVID_G_PARALL,	SUBVENID_GOLDEN,	SUBDEVID_4018A,		0,		2,		0,		0x00,		"4018",		BOARDFLAG_NONE, PART_NUMBER_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	'p',	0,		0,		8,			 1,		0,		8,		0x0000,		SUN1888_HWID	},
+			{	'p',	2,		0,		8,			 3,		0,		8,		0x0000,		SUN1888_HWID	},
+		},
+	},
+	*/
+
+	// mode 4079A
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4079A,		2,		1,		0,		0x1C,		"4079",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	'p',	2,		0,		8,			 3,		0,		8,		0x0000,		SUN1689_HWID	},
+		},
+	},
+
+	// mode 4089A
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4089A,		2,		2,		0,		0x1C,		"4089",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	'p',	2,		0,		8,			 3,		0,		8,		0x0000,		SUN1689_HWID	},
+			{	'p',	4,		0,		8,			 5,		0,		8,		0x0000,		SUN1689_HWID	},
+		},
+	},
+
+	// mode 4096A
+	{
+		VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4096A,		4,		2,		0,		0x1C,		"4096",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1889_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1889_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0004,		SUN1699_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0008,		SUN1699_HWID	},
+			{	'p',	2,		0,		8,			 3,		0,		8,		0x0000,		SUN1689_HWID	},
+			{	'p',	4,		0,		8,			 5,		0,		8,		0x0000,		SUN1689_HWID	},
+		},
+	},
+
+	// mode P1002
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1002,		2,		0,		1,		0x00,		"1002",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P1004
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1004,		4,		0,		1,		0x00,		"1004",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUNMATX_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P1008
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1008,		8,		0,		1,		0x00,		"1008",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUNMATX_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUNMATX_HWID	},
+			{	's',	0,		32,		8,			-1,		0,		0,		0x0010,		SUNMATX_HWID	},
+			{	's',	0,		40,		8,			-1,		0,		0,		0x0020,		SUNMATX_HWID	},
+			{	's',	0,		48,		8,			-1,		0,		0,		0x0040,		SUNMATX_HWID	},
+			{	's',	0,		56,		8,			-1,		0,		0,		0x0080,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P1016
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1016,		16,		0,		1,		0x00,		"1016",		BOARDFLAG_NONE | BOARDFLAG_16PORTS, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUNMATX_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUNMATX_HWID	},
+			{	's',	0,		32,		8,			-1,		0,		0,		0x0010,		SUNMATX_HWID	},
+			{	's',	0,		40,		8,			-1,		0,		0,		0x0020,		SUNMATX_HWID	},
+			{	's',	0,		48,		8,			-1,		0,		0,		0x0040,		SUNMATX_HWID	},
+			{	's',	0,		56,		8,			-1,		0,		0,		0x0080,		SUNMATX_HWID	},
+			{	's',	0,		64,		8,			-1,		0,		0,		0x0100,		SUNMATX_HWID	},
+			{	's',	0,		72,		8,			-1,		0,		0,		0x0200,		SUNMATX_HWID	},
+			{	's',	0,		80,		8,			-1,		0,		0,		0x0400,		SUNMATX_HWID	},
+			{	's',	0,		88,		8,			-1,		0,		0,		0x0800,		SUNMATX_HWID	},
+			{	's',	0,		96,		8,			-1,		0,		0,		0x1000,		SUNMATX_HWID	},
+			{	's',	0,		104,	8,			-1,		0,		0,		0x2000,		SUNMATX_HWID	},
+			{	's',	0,		112,	8,			-1,		0,		0,		0x4000,		SUNMATX_HWID	},
+			{	's',	0,		120,	8,			-1,		0,		0,		0x8000,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P2002
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2002,		2,		0,		1,		0x00,		"2002",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P2004
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2004,		4,		0,		1,		0x00,		"2004",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUNMATX_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P2008
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2008,		8,		0,		1,		0x00,		"2008",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUNMATX_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUNMATX_HWID	},
+			{	's',	0,		32,		8,			-1,		0,		0,		0x0010,		SUNMATX_HWID	},
+			{	's',	0,		40,		8,			-1,		0,		0,		0x0020,		SUNMATX_HWID	},
+			{	's',	0,		48,		8,			-1,		0,		0,		0x0040,		SUNMATX_HWID	},
+			{	's',	0,		56,		8,			-1,		0,		0,		0x0080,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P3002
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3002,		2,		0,		1,		0x00,		"3002",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P3004
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3004,		4,		0,		1,		0x00,		"3004",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUNMATX_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUNMATX_HWID	},
+		},
+	},
+
+	// mode P3008
+	{
+		VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3008,		8,		0,		1,		0x00,		"3008",		BOARDFLAG_NONE, PART_NUMBER_NONE, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUNMATX_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUNMATX_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUNMATX_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUNMATX_HWID	},
+			{	's',	0,		32,		8,			-1,		0,		0,		0x0010,		SUNMATX_HWID	},
+			{	's',	0,		40,		8,			-1,		0,		0,		0x0020,		SUNMATX_HWID	},
+			{	's',	0,		48,		8,			-1,		0,		0,		0x0040,		SUNMATX_HWID	},
+			{	's',	0,		56,		8,			-1,		0,		0,		0x0080,		SUNMATX_HWID	},
+		},
+	},
+
+
+	// mode 5027A
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5027A,		1,		0,		3,		0x00,		"5027",		BOARDFLAG_NONE, 0x01, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+		},
+	},
+
+	// mode 5037A
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5037A,		2,		0,		3,		0x00,		"5037",		BOARDFLAG_NONE, 0x02, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+		},
+	},
+
+	// mode 5056A
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5056A,		4,		0,		3,		0x00,		"5056",		BOARDFLAG_NONE, 0x04, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+
+	// mode 5066A
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5066A,		8,		0,		3,		0x00,		"5066",		BOARDFLAG_NONE, 0x08, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	1,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	1,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+
+	// mode 5016
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5016A,		16,		0,		3,		0x00,		"5016",		BOARDFLAG_NONE | BOARDFLAG_16PORTS, 0x10, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	1,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	1,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+			{	's',	1,		64,		8,			-1,		0,		0,		0x0010,		SUN1999_HWID	},
+			{	's',	1,		72,		8,			-1,		0,		0,		0x0020,		SUN1999_HWID	},
+			{	's',	1,		80,		8,			-1,		0,		0,		0x0040,		SUN1999_HWID	},
+			{	's',	1,		88,		8,			-1,		0,		0,		0x0080,		SUN1999_HWID	},
+			{	's',	1,		128,		8,			-1,		0,		0,		0x0100,		SUN1999_HWID	},
+			{	's',	1,		136,		8,			-1,		0,		0,		0x0200,		SUN1999_HWID	},
+			{	's',	1,		144,		8,			-1,		0,		0,		0x0400,		SUN1999_HWID	},
+			{	's',	1,		152,		8,			-1,		0,		0,		0x0800,		SUN1999_HWID	},
+		},
+	},
+
+	// mode 5069A 5069H
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5069A,		1,		1,		3,		0x00,		"5069",		BOARDFLAG_NONE, 0x01, 0x00, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	'p',	1,		0,		8,			 2,		0,		0,		0x0000,		SUN1999_HWID	},
+		},
+	},
+
+
+	// mode 5079A
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5079A,		2,		1,		3,		0x00,		"5079",		BOARDFLAG_NONE, 0x02, 0x00, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	'p',	1,		0,		8,			 2,		0,		0,		0x0000,		SUN1999_HWID	},
+		},
+	},
+
+	// mode 5099A
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5099A,		4,		1,		3,		0x00,		"5099",		BOARDFLAG_NONE, 0x04, 0x00, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+			{	'p',	1,		0,		8,			 2,		0,		0,		0x0000,		SUN1999_HWID	},
+		},
+	},
+
+	// mode 5008A
+	{
+		VENID_SUN1999,	DEVID_S_PARALL,	SUBVENID_SUN1999,	SUBDEVID_5008A,		0,		1,		0,		0x00,		"5008",		BOARDFLAG_NONE, 0x00, 0x00, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+
+			{	'p',	1,		0,		8,			 2,		0,		0,		0x0000,		SUN1999_HWID	},
+		},
+	},
+
+	// mode P2102
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2102,		2,		0,		3,		0x00,		"P2102",		BOARDFLAG_NONE, 0x42, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+		},
+	},
+
+	// mode P2104
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2104,		4,		0,		3,		0x00,		"P2104",		BOARDFLAG_NONE, 0x44, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+
+	// mode P2108
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2108,		8,		0,		3,		0x00,		"P2108",		BOARDFLAG_NONE, 0x48, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	1,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	1,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+
+	// mode P2116
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2116,		16,		0,		3,		0x00,		"P2116",		BOARDFLAG_NONE | BOARDFLAG_16PORTS, 0x50, CARD_TYPE_UART_ONLY, GPIO_NONE,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	1,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	1,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+			{	's',	1,		64,		8,			-1,		0,		0,		0x0010,		SUN1999_HWID	},
+			{	's',	1,		72,		8,			-1,		0,		0,		0x0020,		SUN1999_HWID	},
+			{	's',	1,		80,		8,			-1,		0,		0,		0x0040,		SUN1999_HWID	},
+			{	's',	1,		88,		8,			-1,		0,		0,		0x0080,		SUN1999_HWID	},
+			{	's',	1,		128,		8,			-1,		0,		0,		0x0100,		SUN1999_HWID	},
+			{	's',	1,		136,		8,			-1,		0,		0,		0x0200,		SUN1999_HWID	},
+			{	's',	1,		144,		8,			-1,		0,		0,		0x0400,		SUN1999_HWID	},
+			{	's',	1,		152,		8,			-1,		0,		0,		0x0800,		SUN1999_HWID	},
+		},
+	},
+
+	// mode IPC-P3104
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P3104,		4,		0,		3,		0x00,		"P3104",		BOARDFLAG_NONE, 0x84, 0x00, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+
+	// mode IPC-P3108
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P3108,		8,		0,		3,		0x00,		"P3108",		BOARDFLAG_NONE, 0x88, 0x00, GPIO_NONE,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+			{	's',	1,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	1,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	1,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	1,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+
+	// CDK1037
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_CASH_2S,		2,		0,		3,		0x00,		"CDK1037",		BOARDFLAG_NONE, 0x02, CARD_TYPE_UART_GINTR, INTR_GPIO_6PORT,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+		},
+	},
+
+	// CDK1056
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_CASH_4S,		4,		0,		3,		0x00,		"CDK1056",		BOARDFLAG_NONE, 0x04, CARD_TYPE_UART_GINTR, INTR_GPIO_6PORT,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+
+	// mode DIO-0802
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO0802,		2,		0,		3,		0x00,		"DIO0802",		BOARDFLAG_NONE, 0x02, CARD_TYPE_UART_GEXTR, EXTR_GPIO_8PORT,
+		{
+			//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+		},
+	},
+
+// mode DIO-1604
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO1604,		4,		0,		3,		0x00,		"DIO1604",		BOARDFLAG_NONE, 0x04, CARD_TYPE_UART_GEXTR, EXTR_GPIO_16PORT,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+
+	// mode DIO-3204
+	{
+		VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO3204,		4,		0,		3,		0x00,		"DIO3204",		BOARDFLAG_NONE, 0x04, CARD_TYPE_UART_GEXTR, EXTR_GPIO_32PORT,
+		{
+		//	type	bar1	ofs1	len1		bar2	ofs2	len2	intmask		flags
+			{	's',	0,		0,		8,			-1,		0,		0,		0x0001,		SUN1999_HWID	},
+			{	's',	0,		8,		8,			-1,		0,		0,		0x0002,		SUN1999_HWID	},
+			{	's',	0,		16,		8,			-1,		0,		0,		0x0004,		SUN1999_HWID	},
+			{	's',	0,		24,		8,			-1,		0,		0,		0x0008,		SUN1999_HWID	},
+		},
+	},
+};
+
diff --git a/char/snx/snx_main.c b/char/snx/snx_main.c
new file mode 100644
index 00000000..5a29be14
--- /dev/null
+++ b/char/snx/snx_main.c
@@ -0,0 +1,1583 @@
+/*
+ *
+ *                SUNIX Multi-I/O Board Device Driver
+ *
+ *
+ *
+ *	Driver for SUNIX Multi-I/O Board device driver
+ *	Based on drivers/char/serial.c, parport_pc.c, ppdev.c and lp.c
+ *	by Linus Torvalds, Theodore Ts'o.
+ *
+ * 	This program is free software; you can redistribute it and/or modify
+ * 	it under the terms of the GNU General Public License as published by
+ * 	the Free Software Foundation; either version 2 of the License, or
+ * 	(at your option) any later version.
+ *
+ * 	This program is distributed in the hope that it will be useful,
+ * 	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 	GNU General Public License for more details.
+ *
+ * 	You should have received a copy of the GNU General Public License
+ * 	along with this program; if not, write to the Free Software
+ * 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ *                                                    		Version: 2.0.4.5
+ *                                                          Date: 2018/11/20
+ */
+#include "snx_common.h"
+#include "driver_extd.h"
+
+
+MODULE_AUTHOR(SNX_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(SNX_DRIVER_DESC);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 18))
+MODULE_LICENSE("GPL");
+#endif
+
+extern struct sunix_board			sunix_board_table[SNX_BOARDS_MAX];
+extern struct sunix_ser_port	    sunix_ser_table[SNX_SER_TOTAL_MAX + 1];
+extern struct sunix_par_port	    sunix_par_table[SNX_PAR_TOTAL_MAX];
+
+char snx_ser_ic_table[SNX_SER_PORT_MAX_UART][10] = {
+	{"UNKNOWN"},
+	{"SUN1889"},
+	{"SUN1699"},
+	{"SUNMATX"},
+	{"SUN1999"}
+};
+
+char snx_par_ic_table[SNX_PAR_PORT_MAX_UART][10] = {
+	{"UNKNOWN"},
+	{"SUN1888"},
+	{"SUN1689"},
+	{"SUNMATX"},
+	{"SUN1999"}
+};
+
+char snx_port_remap[2][10] = {
+	{"NON-REMAP"},
+	{"REMAP"}
+};
+
+enum{
+// golden-serial
+	GOLDEN_BOARD_TEST = 0,
+	GOLDEN_BOARD_4027A,
+	GOLDEN_BOARD_4027D,
+	GOLDEN_BOARD_4037A,
+	GOLDEN_BOARD_4037D,
+	GOLDEN_BOARD_4036A3V,
+	GOLDEN_BOARD_4056A,
+	GOLDEN_BOARD_4056D,
+	GOLDEN_BOARD_4056DW,
+	GOLDEN_BOARD_4066A,
+	GOLDEN_BOARD_4066R,
+	GOLDEN_BOARD_8139,
+	GOLDEN_BOARD_8139S,
+	GOLDEN_BOARD_8159,
+	GOLDEN_BOARD_8159S,
+	GOLDEN_BOARD_8169,
+	GOLDEN_BOARD_8169S,
+
+// golden-parallel, support by system parport_pc driver
+/*
+	GOLDEN_BOARD_4008A,
+	GOLDEN_BOARD_4018A,
+*/
+
+// golden-multi I/O
+	GOLDEN_BOARD_4079A,
+	GOLDEN_BOARD_4089A,
+	GOLDEN_BOARD_4096A,
+
+// matrix-serial
+	MATRIX_BOARD_P1002,
+	MATRIX_BOARD_P1004,
+	MATRIX_BOARD_P1008,
+	MATRIX_BOARD_P1016,
+	MATRIX_BOARD_P2002,
+	MATRIX_BOARD_P2004,
+	MATRIX_BOARD_P2008,
+	MATRIX_BOARD_P3002,
+	MATRIX_BOARD_P3004,
+	MATRIX_BOARD_P3008,
+
+// sun1999-serial RS232
+	SUN1999_BOARD_5027A,
+	SUN1999_BOARD_5037A,
+	SUN1999_BOARD_5056A,
+	SUN1999_BOARD_5066A,
+	SUN1999_BOARD_5016A,
+
+	//sun1999-multi I/O
+	SUN1999_BOARD_5069A,
+	SUN1999_BOARD_5079A,
+	SUN1999_BOARD_5099A,
+
+	//sun1999-parallel
+
+	SUN1999_BOARD_5008A,
+
+	//sun1999-serial RS422/485
+	SUN1999_BOARD_P2102,
+	SUN1999_BOARD_P2104,
+	SUN1999_BOARD_P2108,
+	SUN1999_BOARD_P2116,
+
+	//sun1999 3_in_1
+	SUN1999_BOARD_P3104,
+	SUN1999_BOARD_P3108,
+
+	//cash drawer card
+	SUN1999_BOARD_CASH_2S,
+	SUN1999_BOARD_CASH_4S,
+
+	//DIO
+	SUN1999_BOARD_DIO0802,
+	SUN1999_BOARD_DIO1604,
+	SUN1999_BOARD_DIO3204,
+
+};
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+static  struct pci_device_id	sunix_pci_board_id[] = {
+// golden-serial
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_TEST, 		0,	0,	GOLDEN_BOARD_TEST},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4027A, 	0,	0,	GOLDEN_BOARD_4027A},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4027D, 	0,	0,	GOLDEN_BOARD_4027D},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4037A, 	0,	0,	GOLDEN_BOARD_4037A},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4037D, 	0,	0,	GOLDEN_BOARD_4037D},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4036A3V,	0, 	0,	GOLDEN_BOARD_4036A3V},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4056A,  	0, 	0,	GOLDEN_BOARD_4056A},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4056D,  	0, 	0,	GOLDEN_BOARD_4056D},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4056DW, 	0, 	0,	GOLDEN_BOARD_4056DW},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4066A,  	0, 	0,	GOLDEN_BOARD_4066A},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4066R,  	0, 	0,	GOLDEN_BOARD_4066R},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8139,   	0, 	0,	GOLDEN_BOARD_8139},
+	{VENID_GOLDEN,	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8139S,  	0, 	0,	GOLDEN_BOARD_8139S},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8159,   	0, 	0,	GOLDEN_BOARD_8159},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8159S,  	0, 	0,	GOLDEN_BOARD_8159S},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8169,   	0, 	0,	GOLDEN_BOARD_8169},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8169S,  	0, 	0,	GOLDEN_BOARD_8169S},
+
+// golden-parallel, support by system parport_pc driver
+/*
+	{VENID_GOLDEN,	DEVID_G_PARALL,	SUBVENID_GOLDEN,	SUBDEVID_4008A, 	0,	0,	GOLDEN_BOARD_4008A},
+	{VENID_GOLDEN,	DEVID_G_PARALL,	SUBVENID_GOLDEN,	SUBDEVID_4018A, 	0,	0,	GOLDEN_BOARD_4018A},
+*/
+
+// golden-multi I/O
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4079A, 	0,	0,	GOLDEN_BOARD_4079A},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4089A, 	0,	0,	GOLDEN_BOARD_4089A},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4096A, 	0,	0,	GOLDEN_BOARD_4096A},
+
+// matrix-serial
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1002, 	0,	0,	MATRIX_BOARD_P1002},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1004, 	0,	0,	MATRIX_BOARD_P1004},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1008, 	0,	0,	MATRIX_BOARD_P1008},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1016, 	0,	0,	MATRIX_BOARD_P1016},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2002, 	0,	0,	MATRIX_BOARD_P2002},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2004, 	0,	0,	MATRIX_BOARD_P2004},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2008, 	0,	0,	MATRIX_BOARD_P2008},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3002, 	0,	0,	MATRIX_BOARD_P3002},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3004, 	0,	0,	MATRIX_BOARD_P3004},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3008, 	0,	0,	MATRIX_BOARD_P3008},
+
+	// sun1999-serial RS232
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5027A, 	0,	0,	SUN1999_BOARD_5027A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5037A, 	0,	0,	SUN1999_BOARD_5037A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5056A, 	0,	0,	SUN1999_BOARD_5056A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5066A, 	0,	0,	SUN1999_BOARD_5066A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5016A, 	0,	0,	SUN1999_BOARD_5016A},
+
+	// sun1999-multi I/O
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5069A, 	0,	0,	SUN1999_BOARD_5069A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5079A, 	0,	0,	SUN1999_BOARD_5079A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5099A, 	0,	0,	SUN1999_BOARD_5099A},
+
+	// sun1999-parallel
+	{VENID_SUN1999,	DEVID_S_PARALL,	SUBVENID_SUN1999,	SUBDEVID_5008A, 	0,	0,	SUN1999_BOARD_5008A},
+
+	// sun1999-serial RS422/485
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2102, 	0,	0,	SUN1999_BOARD_P2102},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2104, 	0,	0,	SUN1999_BOARD_P2104},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2108, 	0,	0,	SUN1999_BOARD_P2108},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2116, 	0,	0,	SUN1999_BOARD_P2116},
+
+	// sun1999 3_in_1
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P3104, 	0,	0,	SUN1999_BOARD_P3104},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P3108, 	0,	0,	SUN1999_BOARD_P3108},
+
+	//cash drawer card  2S
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_CASH_2S, 0,	0,	SUN1999_BOARD_CASH_2S},
+
+	//cash drawer card  4S
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_CASH_4S, 0,	0,	SUN1999_BOARD_CASH_4S},
+
+	//DIO
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO0802, 0,	0,	SUN1999_BOARD_DIO0802},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO1604, 0,	0,	SUN1999_BOARD_DIO1604},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO3204, 0,	0,	SUN1999_BOARD_DIO3204},
+
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, sunix_pci_board_id);
+#else
+typedef struct{
+	unsigned short vendor;
+	unsigned short device;
+	unsigned short subvendor;
+	unsigned short subdevice;
+	unsigned short driver_data;
+	unsigned short part_number;
+} sunix_pciInfo;
+
+static sunix_pciInfo sunix_pci_board_id[] = {
+// golden-serial
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_TEST,		GOLDEN_BOARD_TEST},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4027A,		GOLDEN_BOARD_4027A},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4027D,		GOLDEN_BOARD_4027D},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4037A,		GOLDEN_BOARD_4037A},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4037D,		GOLDEN_BOARD_4037D},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4036A3V, GOLDEN_BOARD_4036A3V},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4056A,  	GOLDEN_BOARD_4056A},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4056D,  	GOLDEN_BOARD_4056D},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4056DW, 	GOLDEN_BOARD_4056DW},
+	{VENID_GOLDEN,	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4066A,  	GOLDEN_BOARD_4066A},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_4066R,  	GOLDEN_BOARD_4066R},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8139,   	GOLDEN_BOARD_8139},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8139S,  	GOLDEN_BOARD_8139S},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8159,   	GOLDEN_BOARD_8159},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8159S,  	GOLDEN_BOARD_8159S},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8169,   	GOLDEN_BOARD_8169},
+	{VENID_GOLDEN, 	DEVID_G_SERIAL, SUBVENID_GOLDEN, 	SUBDEVID_8169S,  	GOLDEN_BOARD_8169S},
+
+// golden-parallel, support by system parport_pc driver
+/*
+	{VENID_GOLDEN,	DEVID_G_PARALL,	SUBVENID_GOLDEN,	SUBDEVID_4008A,		GOLDEN_BOARD_4008A},
+	{VENID_GOLDEN,	DEVID_G_PARALL,	SUBVENID_GOLDEN,	SUBDEVID_4018A,		GOLDEN_BOARD_4018A},
+*/
+
+// golden-multi I/O
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4079A,		GOLDEN_BOARD_4079A},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4089A,		GOLDEN_BOARD_4089A},
+	{VENID_GOLDEN,	DEVID_G_SERIAL,	SUBVENID_GOLDEN,	SUBDEVID_4096A,		GOLDEN_BOARD_4096A},
+
+// matrix-serial
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1002, 	MATRIX_BOARD_P1002},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1004, 	MATRIX_BOARD_P1004},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1008, 	MATRIX_BOARD_P1008},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P1016, 	MATRIX_BOARD_P1016},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2002, 	MATRIX_BOARD_P2002},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2004, 	MATRIX_BOARD_P2004},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P2008, 	MATRIX_BOARD_P2008},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3002, 	MATRIX_BOARD_P3002},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3004, 	MATRIX_BOARD_P3004},
+	{VENID_MATRIX,	DEVID_M_SERIAL,	SUBVENID_MATRIX,	SUBDEVID_P3008, 	MATRIX_BOARD_P3008},
+
+	// sun1999-serial
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5027A, 	SUN1999_BOARD_5027A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5037A, 	SUN1999_BOARD_5037A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5056A, 	SUN1999_BOARD_5056A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5066A, 	SUN1999_BOARD_5066A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5016A, 	SUN1999_BOARD_5016A},
+
+	// sun1999-multi I/O
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5069A, 	SUN1999_BOARD_5069A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5079A, 	SUN1999_BOARD_5079A},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_5099A, 	SUN1999_BOARD_5099A},
+
+	// sun1999-parallel
+	{VENID_SUN1999,	DEVID_S_PARALL,	SUBVENID_SUN1999,	SUBDEVID_5008A, 	SUN1999_BOARD_5008A},
+
+	// sun1999-serial RS422/485
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2102, 	SUN1999_BOARD_P2102},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2104, 	SUN1999_BOARD_P2104},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2108, 	SUN1999_BOARD_P2108},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P2116, 	SUN1999_BOARD_P2116},
+
+	// sun1999 3_in_1
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P3104, 	SUN1999_BOARD_P3104},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_P3108, 	SUN1999_BOARD_P3108},
+
+	//cash drawer card
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_CASH_2S, SUN1999_BOARD_CASH_2S},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_CASH_4S, SUN1999_BOARD_CASH_4S},
+
+	//DIO
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO0802, SUN1999_BOARD_DIO0802},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO1604, SUN1999_BOARD_DIO1604},
+	{VENID_SUN1999,	DEVID_S_SERIAL,	SUBVENID_SUN1999,	SUBDEVID_DIO3204, SUN1999_BOARD_DIO3204},
+
+	{0}
+};
+#endif
+
+
+struct sunix_board			sunix_board_table[SNX_BOARDS_MAX];
+struct sunix_ser_port	    sunix_ser_table[SNX_SER_TOTAL_MAX + 1];
+struct sunix_par_port	    sunix_par_table[SNX_PAR_TOTAL_MAX];
+
+static int snx_ser_port_total_cnt;
+static int snx_par_port_total_cnt;
+
+int snx_board_count;
+
+static struct snx_ser_driver	sunix_ser_reg = {
+	.dev_name = "ttySNX",
+	.major = 0,
+	.minor = 0,
+	.nr = (SNX_SER_TOTAL_MAX + 1),
+};
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+static irqreturn_t sunix_interrupt(int irq, void *dev_id)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+static irqreturn_t sunix_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+static void sunix_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#endif
+{
+	struct sunix_ser_port *sp = NULL;
+	struct sunix_par_port *pp = NULL;
+	struct sunix_board *sb = NULL;
+	int i;
+	int status = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+	int handled = IRQ_NONE;
+#endif
+
+	for (i = 0; i < SNX_BOARDS_MAX; i++) {
+
+		if (dev_id == &(sunix_board_table[i])) {
+			sb = dev_id;
+			break;
+		}
+	}
+
+	if (i == SNX_BOARDS_MAX)
+		status = 1;
+
+	if (!sb)
+		status = 1;
+
+	if (sb->board_enum <= 0)
+		status = 1;
+
+	if (status != 0) {
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+		return handled;
+#else
+		return;
+#endif
+	}
+
+	if ((sb->ser_port > 0) && (sb->ser_isr != NULL)) {
+		sp = &sunix_ser_table[sb->ser_port_index];
+
+		if (!sp) {
+			status = 1;
+		}
+		status = sb->ser_isr(sb, sp);
+	}
+
+	if ((sb->par_port > 0) && (sb->par_isr != NULL)) {
+		pp = &sunix_par_table[sb->par_port_index];
+
+		if (!pp)
+			status = 1;
+
+		status = sb->par_isr(sb, pp);
+	}
+
+	if (status != 0) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+		return handled;
+#else
+		return;
+#endif
+	}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+	handled = IRQ_HANDLED;
+	return handled;
+#endif
+}
+
+static int snx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	return 0;
+}
+
+static int snx_suspend_one(struct pci_dev *pdev, pm_message_t state)
+{
+	return  0;
+}
+
+static int snx_set_port_termios(struct snx_ser_state *state)
+{
+	struct tty_struct *tty = state->info->tty;
+	struct SNXTERMIOS *termios;
+
+	int retval = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
+	termios = &tty->termios;
+#else
+	termios = tty->termios;
+#endif
+
+	retval = snx_ser_startup(state, 0);
+
+	if (retval == 0)
+		snx_ser_update_termios(state);
+
+	return 0;
+}
+
+static int snx_resume_port_termios(struct snx_ser_info *info)
+{
+	struct snx_ser_state *state = NULL;
+	struct tty_struct *tty = info->tty ;
+
+	state = tty->driver_data;
+	snx_set_port_termios(state);
+
+	return 0;
+}
+
+
+static int snx_resume_port(struct sunix_ser_port *sp)
+{
+	struct snx_ser_port *port = &sp->port;
+	struct snx_ser_info *info = port->info;
+
+	if (info)
+		snx_resume_port_termios(info);
+
+	return 0;
+}
+
+static int snx_resume_one(struct pci_dev *pdev)
+{
+	struct sunix_board *sb = pci_get_drvdata(pdev);
+	struct sunix_ser_port *sp = NULL;
+	int j;
+
+	if (sb == NULL)
+		return 0;
+
+	for (j = 0; j < sb->ser_port; j++) {
+		sp = &sunix_ser_table[j];
+
+		if (sp == NULL)
+			return 0;
+
+		if (sp->port.suspended == 1)
+			snx_resume_port(sp);
+	}
+
+	return 0;
+}
+
+
+static int sunix_pci_board_probe(void)
+{
+	struct sunix_board *sb;
+	struct pci_dev *pdev = NULL;
+	struct pci_dev *pdev_array[4] = {NULL, NULL, NULL, NULL};
+
+	int sunix_pci_board_id_cnt;
+	int tablecnt;
+	int boardcnt;
+	int i;
+	unsigned short int sub_device_id;
+	unsigned short int device_part_number;
+	unsigned int bar3_base_add;
+
+	int status;
+	unsigned int bar3_Byte5;
+	unsigned int bar3_Byte6;
+	unsigned int bar3_Byte7;
+	unsigned int oem_id;
+	unsigned char uart_type;
+	unsigned char gpio_type;
+	unsigned char gpio_card_type;
+	int gpio_ch_cnt;
+
+	// clear and init some variable
+	memset(sunix_board_table, 0, SNX_BOARDS_MAX * sizeof(struct sunix_board));
+
+	for (i = 0; i < SNX_BOARDS_MAX; i++) {
+		sunix_board_table[i].board_enum = -1;
+		sunix_board_table[i].board_number = -1;
+	}
+
+	sunix_pci_board_id_cnt = (sizeof(sunix_pci_board_id) / sizeof(sunix_pci_board_id[0])) - 1;
+
+	// search golden serial and multi-I/O board
+	pdev = NULL;
+	tablecnt = 0;
+	boardcnt = 0;
+	sub_device_id = 0;
+	status = 0;
+
+	while (tablecnt < sunix_pci_board_id_cnt) {
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+		pdev = pci_get_device(VENID_GOLDEN, DEVID_G_SERIAL, pdev);
+#else
+		pdev = pci_find_device(VENID_GOLDEN, DEVID_G_SERIAL, pdev);
+#endif
+
+		if (pdev == NULL) {
+			tablecnt++;
+			continue;
+		}
+
+		if ((tablecnt > 0) && ((pdev == pdev_array[0]) ||
+		(pdev == pdev_array[1]) ||
+		(pdev == pdev_array[2]) ||
+		(pdev == pdev_array[3]))) {
+			continue;
+		}
+
+		pci_read_config_word(pdev, 0x2e, &sub_device_id);
+
+		if (sub_device_id == 0) {
+			printk("SNX Error: SUNIX Board (bus:%d device:%d), in configuration space,\n", pdev->bus->number, PCI_SLOT(pdev->devfn));
+			printk("           subdevice id isn't vaild.\n\n");
+			status = -EIO;
+			return status;
+		}
+
+		if (sub_device_id != sunix_pci_board_id[tablecnt].subdevice)
+			continue;
+
+		if (pdev == NULL) {
+			printk("SNX Error: PCI device object is an NULL pointer !\n\n");
+			status = -EIO;
+			return status;
+		} else {
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+		pci_disable_device(pdev);
+#endif
+			status = pci_enable_device(pdev);
+
+			if (status != 0) {
+				printk("SNX Error: SUNIX Board Enable Fail !\n\n");
+				status = -ENXIO;
+				return status;
+			}
+		}
+
+		if (snx_pci_board_conf[tablecnt].part_number != 0x00) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+			pci_disable_device(pdev);
+#endif
+			continue;
+		}
+
+		boardcnt++;
+		if (boardcnt > SNX_BOARDS_MAX) {
+			printk("\n");
+			printk("SNX Error: SUNIX Driver Module Support Four Boards In Maximum !\n\n");
+			status = -ENOSPC;
+			return status;
+		}
+
+		sb = &sunix_board_table[boardcnt-1];
+		pdev_array[boardcnt-1] = pdev;
+		sb->pdev = pdev;
+		sb->bus_number = pdev->bus->number;
+		sb->dev_number = PCI_SLOT(pdev->devfn);
+		sb->board_enum = (int)sunix_pci_board_id[tablecnt].driver_data;
+		sb->pb_info = snx_pci_board_conf[sb->board_enum];
+		sb->board_flag = sb->pb_info.board_flag;
+		sb->board_number  =  boardcnt - 1;
+	}
+
+	// search golden parallel board
+	pdev = NULL;
+	tablecnt = 0;
+	sub_device_id = 0;
+	status = 0;
+
+	while (tablecnt < sunix_pci_board_id_cnt) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+		pdev = pci_get_device(VENID_GOLDEN, DEVID_G_PARALL, pdev);
+#else
+		pdev = pci_find_device(VENID_GOLDEN, DEVID_G_PARALL, pdev);
+#endif
+		if (pdev == NULL) {
+			tablecnt++;
+			continue;
+		}
+
+		if ((tablecnt > 0) && ((pdev == pdev_array[0]) ||
+			(pdev == pdev_array[1]) ||
+			(pdev == pdev_array[2]) ||
+			(pdev == pdev_array[3]))) {
+			continue;
+		}
+
+		pci_read_config_word(pdev, 0x2e, &sub_device_id);
+
+		if (sub_device_id == 0) {
+			printk("SNX Error: SUNIX Board (bus:%d device:%d), in configuration space,\n", pdev->bus->number, PCI_SLOT(pdev->devfn));
+			printk("           subdevice id isn't vaild.\n\n");
+			status = -EIO;
+			return status;
+		}
+
+		if (sub_device_id != sunix_pci_board_id[tablecnt].subdevice) {
+			continue;
+		}
+
+		if (pdev == NULL) {
+			printk("SNX Error: PCI device object is an NULL pointer !\n\n");
+			status = -EIO;
+			return status;
+		} else {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+			pci_disable_device(pdev);
+#endif
+			status = pci_enable_device(pdev);
+
+			if (status != 0) {
+				printk("SNX Error: SUNIX Board Enable Fail !\n\n");
+				status = -ENXIO;
+				return status;
+			}
+		}
+
+		boardcnt++;
+		if (boardcnt > SNX_BOARDS_MAX) {
+			printk("\n");
+			printk("SNX Error: SUNIX Driver Module Support Four Boards In Maximum !\n\n");
+			status = -ENOSPC;
+			return status;
+		}
+
+		sb = &sunix_board_table[boardcnt-1];
+		pdev_array[boardcnt-1] = pdev;
+		sb->pdev = pdev;
+		sb->bus_number = pdev->bus->number;
+		sb->dev_number = PCI_SLOT(pdev->devfn);
+		sb->board_enum = (int)sunix_pci_board_id[tablecnt].driver_data;
+		sb->pb_info = snx_pci_board_conf[sb->board_enum];
+		sb->board_flag = sb->pb_info.board_flag;
+		sb->board_number = boardcnt - 1;
+	}
+
+	// search matrix serial board
+	pdev = NULL;
+	tablecnt = 0;
+	sub_device_id = 0;
+	status = 0;
+
+	while (tablecnt < sunix_pci_board_id_cnt) {
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+	pdev = pci_get_device(VENID_MATRIX, DEVID_M_SERIAL, pdev);
+#else
+	pdev = pci_find_device(VENID_MATRIX, DEVID_M_SERIAL, pdev);
+#endif
+
+		if (pdev == NULL) {
+			tablecnt++;
+			continue;
+		}
+
+		if ((tablecnt > 0) && ((pdev == pdev_array[0]) ||
+		(pdev == pdev_array[1]) ||
+		(pdev == pdev_array[2]) ||
+		(pdev == pdev_array[3]))) {
+			continue;
+		}
+
+		pci_read_config_word(pdev, 0x2e, &sub_device_id);
+
+		if (sub_device_id == 0) {
+			printk("SNX Error: SUNIX Board (bus:%d device:%d), in configuration space,\n", pdev->bus->number, PCI_SLOT(pdev->devfn));
+			printk("           subdevice id isn't vaild.\n\n");
+			status = -EIO;
+			return status;
+		}
+
+		if (sub_device_id != sunix_pci_board_id[tablecnt].subdevice)
+			continue;
+		if (pdev == NULL) {
+			printk("SNX Error: PCI device object is an NULL pointer !\n\n");
+			status = -EIO;
+			return status;
+		} else {
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+	pci_disable_device(pdev);
+#endif
+
+			status = pci_enable_device(pdev);
+
+			if (status != 0) {
+				printk("SNX Error: SUNIX Board Enable Fail !\n\n");
+				status = -ENXIO;
+				return status;
+			}
+		}
+
+		boardcnt++;
+		if (boardcnt > SNX_BOARDS_MAX) {
+			printk("\n");
+			printk("SNX Error: SUNIX Driver Module Support Four Boards In Maximum !\n\n");
+			status = -ENOSPC;
+			return status;
+		}
+
+		sb = &sunix_board_table[boardcnt-1];
+		pdev_array[boardcnt-1] = pdev;
+		sb->pdev = pdev;
+		sb->bus_number = pdev->bus->number;
+		sb->dev_number = PCI_SLOT(pdev->devfn);
+		sb->board_enum = (int)sunix_pci_board_id[tablecnt].driver_data;
+		sb->pb_info = snx_pci_board_conf[sb->board_enum];
+		sb->board_flag = sb->pb_info.board_flag;
+		sb->board_number = boardcnt - 1;
+    }
+
+	// search sun1999 muti I/O board
+	pdev = NULL;
+	tablecnt = 0;
+	sub_device_id = 0;
+	status = 0;
+	device_part_number = 0;
+	bar3_base_add = 0;
+	bar3_Byte5 = 0;
+	bar3_Byte6 = 0;
+	bar3_Byte7 = 0;
+	oem_id = 0;
+	uart_type = 0;
+	gpio_type = 0;
+	gpio_card_type = 0;
+	gpio_ch_cnt = 0;
+
+	while (tablecnt < sunix_pci_board_id_cnt) {
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+		pdev = pci_get_device(VENID_SUN1999, DEVID_S_SERIAL, pdev);
+#else
+		pdev = pci_find_device(VENID_SUN1999, DEVID_S_SERIAL, pdev);
+#endif
+
+		if (pdev == NULL) {
+			tablecnt++;
+			continue;
+		}
+
+		if ((tablecnt > 0) &&
+		((pdev == pdev_array[0]) ||
+		(pdev == pdev_array[1]) ||
+		(pdev == pdev_array[2]) ||
+		(pdev == pdev_array[3]))) {
+			continue;
+		}
+
+		pci_read_config_word(pdev, 0x2e, &sub_device_id);
+
+		if (sub_device_id == 0) {
+			printk("SNX Error: SUNIX Board (bus:%d device:%d), in configuration space,\n", pdev->bus->number, PCI_SLOT(pdev->devfn));
+			printk("           subdevice id isn't vaild.\n\n");
+			status = -EIO;
+			return status;
+		}
+
+		if (sub_device_id != sunix_pci_board_id[tablecnt].subdevice)
+		continue;
+
+		if (pdev == NULL) {
+			printk("SNX Error: PCI device object is an NULL pointer !\n\n");
+			status = -EIO;
+			return status;
+		} else {
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+		pci_disable_device(pdev);
+#endif
+			status = pci_enable_device(pdev);
+
+			if (status != 0) {
+				printk("SNX Error: SUNIX Board Enable Fail !\n\n");
+				status = -ENXIO;
+				return status;
+			}
+		}
+
+		bar3_base_add = pci_resource_start(pdev, 3);
+		device_part_number = inb(bar3_base_add + 5);
+		bar3_Byte5 = device_part_number;
+		bar3_Byte6 = inb(bar3_base_add + 0x06);
+		bar3_Byte7 = inb(bar3_base_add + 0x07);
+		gpio_card_type = ((bar3_Byte7 & 0x18)>>3);
+		oem_id = (bar3_Byte5 | (bar3_Byte6 << 8) | (bar3_Byte7 << 16));
+		uart_type = ((bar3_Byte5 & 0xc0)>>6);
+		gpio_ch_cnt = ((bar3_Byte7 & 0x60)>>5);
+		gpio_type = ((bar3_Byte7 & 0x80)>>7);
+
+		if ((gpio_ch_cnt == 0x00) && (gpio_card_type == 0x01)) {
+			gpio_ch_cnt = 6 ;
+		} else if ((gpio_ch_cnt == 0x00) && (gpio_card_type == 0x02)) {
+			gpio_ch_cnt = 8 ;
+		} else if (gpio_ch_cnt == 0x01) {
+			gpio_ch_cnt = 16 ;
+		} else if (gpio_ch_cnt == 0x02) {
+			gpio_ch_cnt = 32 ;
+		}
+
+		if (device_part_number != snx_pci_board_conf[tablecnt].part_number) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+			pci_disable_device(pdev);
+#endif
+			continue;
+		} else if (gpio_card_type != snx_pci_board_conf[tablecnt].card_type) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+			pci_disable_device(pdev);
+#endif
+			continue;
+		} else if (gpio_ch_cnt != snx_pci_board_conf[tablecnt].gpio_ch_cnt) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+			pci_disable_device(pdev);
+#endif
+			continue;
+		}
+
+		boardcnt++;
+		if (boardcnt > SNX_BOARDS_MAX) {
+			printk("\n");
+			printk("SNX Error: SUNIX Driver Module Support Four Boards In Maximum !\n\n");
+			status = -ENOSPC;
+			return status;
+		}
+
+		sb = &sunix_board_table[boardcnt-1];
+		pdev_array[boardcnt-1] = pdev;
+		sb->pdev = pdev;
+		sb->bus_number = pdev->bus->number;
+		sb->dev_number = PCI_SLOT(pdev->devfn);
+		sb->board_enum = (int)sunix_pci_board_id[tablecnt].driver_data;
+		sb->pb_info = snx_pci_board_conf[sb->board_enum];
+		sb->board_flag = sb->pb_info.board_flag;
+		sb->board_number = boardcnt - 1;
+		sb->oem_id = oem_id ;
+		sb->uart_cnt = sb->pb_info.num_serport ;
+		sb->gpio_chl_cnt = gpio_ch_cnt ;
+		sb->board_uart_type = uart_type ;
+		sb->board_gpio_card_type = gpio_card_type ;
+		sb->board_gpio_type = gpio_type ;
+	}
+
+	// search SUN1999 parallel board
+	pdev = NULL;
+	tablecnt = 0;
+	sub_device_id = 0;
+	status = 0;
+
+	while (tablecnt < sunix_pci_board_id_cnt) {
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+		pdev = pci_get_device(VENID_SUN1999, DEVID_S_PARALL, pdev);
+#else
+		pdev = pci_find_device(VENID_SUN1999, DEVID_S_PARALL, pdev);
+#endif
+
+		if (pdev == NULL) {
+			tablecnt++;
+			continue;
+		}
+
+		if ((tablecnt > 0) &&
+		((pdev == pdev_array[0]) ||
+		(pdev == pdev_array[1]) ||
+		(pdev == pdev_array[2]) ||
+		(pdev == pdev_array[3]))) {
+			continue;
+		}
+
+		pci_read_config_word(pdev, 0x2e, &sub_device_id);
+
+		if (sub_device_id == 0) {
+			printk("SNX Error: SUNIX Board (bus:%d device:%d), in configuration space,\n", pdev->bus->number, PCI_SLOT(pdev->devfn));
+			printk("           subdevice id isn't vaild.\n\n");
+			status = -EIO;
+			return status;
+		}
+
+		if (sub_device_id != sunix_pci_board_id[tablecnt].subdevice)
+			continue;
+
+		if (pdev == NULL) {
+			printk("SNX Error: PCI device object is an NULL pointer !\n\n");
+			status = -EIO;
+			return status;
+		} else {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 3))
+			pci_disable_device(pdev);
+#endif
+			status = pci_enable_device(pdev);
+
+			if (status != 0) {
+				printk("SNX Error: SUNIX Board Enable Fail !\n\n");
+				status = -ENXIO;
+				return status;
+			}
+		}
+
+		boardcnt++;
+		if (boardcnt > SNX_BOARDS_MAX) {
+			printk("\n");
+			printk("SNX Error: SUNIX Driver Module Support Four Boards In Maximum !\n\n");
+			status = -ENOSPC;
+			return status;
+		}
+
+		sb = &sunix_board_table[boardcnt-1];
+		pdev_array[boardcnt-1] = pdev;
+		sb->pdev = pdev;
+		sb->bus_number = pdev->bus->number;
+		sb->dev_number = PCI_SLOT(pdev->devfn);
+		sb->board_enum = (int)sunix_pci_board_id[tablecnt].driver_data;
+		sb->pb_info = snx_pci_board_conf[sb->board_enum];
+		sb->board_flag = sb->pb_info.board_flag;
+		sb->board_number = boardcnt - 1;
+	}
+
+	// print info
+	if (boardcnt == 0) {
+		printk("SNX Info : No SUNIX Multi-I/O Board Found !\n\n");
+		status = -ENXIO;
+		return status;
+	} else {
+
+		for (i = 0; i < SNX_BOARDS_MAX; i++) {
+			sb = &sunix_board_table[i];
+
+			if (sb->board_enum > 0) {
+				printk("\n");
+
+				if ((sb->pb_info.num_serport > 0) && (sb->pb_info.num_parport > 0)) {
+					printk("SNX Info : Found SUNIX %s Series Board (%dS%dP),\n", sb->pb_info.board_name, sb->pb_info.num_serport, sb->pb_info.num_parport);
+				} else if ((sb->pb_info.num_serport) > 0) {
+					printk("SNX Info : Found SUNIX %s Series Board (%dS),\n", sb->pb_info.board_name, sb->pb_info.num_serport);
+				} else {
+					printk("SNX Info : Found SUNIX %s Series Board (%dP),\n", sb->pb_info.board_name, sb->pb_info.num_parport);
+				}
+				printk("           bus number:%d, device number:%d\n\n", sb->bus_number, sb->dev_number);
+			}
+		}
+		snx_board_count  = boardcnt ;
+    }
+
+	return status;
+}
+
+
+static int sunix_get_pci_board_conf(void)
+{
+    struct sunix_board *sb = NULL;
+    struct pci_dev *pdev = NULL;
+    int status = 0;
+    int i;
+    int j;
+
+	for (i = 0; i < SNX_BOARDS_MAX; i++) {
+		sb = &sunix_board_table[i];
+
+		if (sb->board_enum > 0) {
+			pdev = sb->pdev;
+			sb->ports = sb->pb_info.num_serport + sb->pb_info.num_parport;
+			sb->ser_port = sb->pb_info.num_serport;
+			sb->par_port = sb->pb_info.num_parport;
+			snx_ser_port_total_cnt = snx_ser_port_total_cnt + sb->ser_port;
+			snx_par_port_total_cnt = snx_par_port_total_cnt + sb->par_port;
+
+			if (snx_ser_port_total_cnt > SNX_SER_TOTAL_MAX) {
+				printk("SNX Error: Too much serial port, maximum %d ports can be supported !\n\n", SNX_SER_TOTAL_MAX);
+				status = -EIO;
+				return status;
+			}
+
+			if (snx_par_port_total_cnt > SNX_PAR_SUPPORT_MAX) {
+				printk("SNX Error: Too much parallel port, maximum %d ports can be supported !\n\n", SNX_PAR_SUPPORT_MAX);
+				status = -EIO;
+				return status;
+			}
+
+			for (j = 0; j < SNX_PCICFG_BAR_TOTAL; j++) {
+				sb->bar_addr[j] = pci_resource_start(pdev, j);
+			}
+
+			sb->irq = sb->pdev->irq;
+
+			if (sb->irq <= 0) {
+				printk("SNX Error: SUNIX Board %s Series (bus:%d device:%d), in configuartion space, irq isn't valid !\n\n",
+				sb->pb_info.board_name,
+				sb->bus_number,
+				sb->dev_number);
+
+				status = -EIO;
+				return status;
+			}
+		}
+	}
+
+	return status;
+}
+
+
+static int sunix_assign_resource(void)
+{
+	struct sunix_board *sb = NULL;
+	struct sunix_ser_port *sp = NULL;
+	struct sunix_par_port *pp = NULL;
+
+	int status = 0;
+	int i;
+	int j;
+	int k;
+	int ser_n;
+	int ser_port_index = 0;
+
+	memset(sunix_ser_table, 0, (SNX_SER_TOTAL_MAX + 1) * sizeof(struct sunix_ser_port));
+	memset(sunix_par_table, 0, (SNX_PAR_TOTAL_MAX) * sizeof(struct sunix_par_port));
+
+	for (i = 0; i < SNX_BOARDS_MAX; i++) {
+		sb = &sunix_board_table[i];
+
+		if (sb->board_enum > 0) {
+			if (sb->ser_port > 0) {
+				sb->vector_mask = 0;
+
+				// assign serial port resource
+				ser_n = sb->ser_port_index = ser_port_index;
+
+				sp = &sunix_ser_table[ser_n];
+
+				if (sp == NULL) {
+					status = -ENXIO;
+					printk("SNX Error: Serial port table address error !\n");
+					return status;
+				}
+
+				for (j = 0; j < sb->ser_port; j++, ser_n++, sp++) {
+					sp->port.chip_flag = sb->pb_info.port[j].chip_flag;
+					sp->port.iobase = sb->bar_addr[sb->pb_info.port[j].bar1] + sb->pb_info.port[j].offset1;
+
+					if ((sb->board_flag & BOARDFLAG_REMAP) == BOARDFLAG_REMAP) {
+						sp->port.vector = 0;
+						sb->vector_mask = 0x00;
+					} else {
+
+						sp->port.vector = sb->bar_addr[sb->pb_info.intr_vector_bar] + sb->pb_info.intr_vector_offset;
+						sb->vector_mask |= (1 << j);
+					}
+				}
+
+				ser_port_index = ser_port_index + sb->ser_port;
+			}
+
+
+			// assign parallel port resource
+			if (sb->par_port > 0) {
+				k = 0;
+
+				for (j = 0; j < SNX_PAR_TOTAL_MAX; j++) {
+					if ((k + 1) > sb->par_port)
+						break;
+
+					if (j >= SNX_PAR_TOTAL_MAX) {
+						status = -EACCES;
+						printk("SNX Error: Too much parallel port, maximum %d ports can be supported !\n\n", SNX_PAR_TOTAL_MAX);
+						return status;
+					}
+
+					pp = &sunix_par_table[j];
+
+					if (pp == NULL) {
+						status = -ENXIO;
+						printk("SNX Error: Parallel port table address error !\n");
+						return status;
+					}
+
+					if (pp->chip_flag != SUNNONE_HWID) {
+						continue;
+					} else {
+						pp->chip_flag = sb->pb_info.port[k + sb->ser_port].chip_flag;
+
+						pp->base = sb->bar_addr[sb->pb_info.port[k + sb->ser_port].bar1] + sb->pb_info.port[k + sb->ser_port].offset1;
+						pp->base_hi = sb->bar_addr[sb->pb_info.port[k + sb->ser_port].bar2] + sb->pb_info.port[k + sb->ser_port].offset2;
+
+						pp->bus_number = sb->bus_number;
+						pp->dev_number = sb->dev_number;
+						pp->board_enum = sb->board_enum;
+						k++;
+					}
+				}
+			}
+		}
+	}
+
+	return status;
+}
+
+
+static int sunix_ser_port_table_init(void)
+{
+	struct sunix_board *sb = NULL;
+	struct sunix_ser_port *sp = NULL;
+	int status = 0;
+	int i;
+	int j;
+	int n;
+	int AHDC_State = 0;
+	int RS422_State = 0;
+
+	for (i = 0; i < SNX_BOARDS_MAX; i++) {
+
+		sb = &sunix_board_table[i];
+
+		if (sb == NULL) {
+			status = -ENXIO;
+			printk("SNX Error: Board table pointer error !\n");
+			return status;
+		}
+
+		if ((sb->board_enum > 0) && (sb->ser_port > 0)) {
+			n = sb->ser_port_index;
+			sp = &sunix_ser_table[n];
+
+			if (sp == NULL) {
+				status = -ENXIO;
+				printk("SNX Error: Serial port table pointer error !\n");
+				return status;
+			}
+
+			for (j = 0; j < sb->ser_port; j++, n++, sp++) {
+				if (j < 4) {
+					AHDC_State = inb(sb->bar_addr[3]+2) & 0x0F & (0x01 << (((j+1)-1) % 4));
+					RS422_State = inb(sb->bar_addr[3]+3) & 0xF0 & (0x10 << (((j+1)-1) % 4));
+				} else if (j < 8) {
+					AHDC_State = inb(sb->bar_addr[1] + 0x32) & 0x0F & (0x01 << (((j+1)-1) % 4)) ;
+					RS422_State = inb(sb->bar_addr[1] + 0x33) & 0xF0 & (0x10 << (((j+1)-1) % 4)) ;
+				}
+
+				RS422_State = ((RS422_State & 0xF0) >> 4);
+				sp->port.AHDC_State = AHDC_State >> (((j+1)-1)%4);
+				sp->port.RS422_State = RS422_State >> (((j+1)-1)%4);
+
+				sp->port.board_enum	= sb->board_enum;
+				sp->port.bus_number	= sb->bus_number;
+				sp->port.dev_number	= sb->dev_number;
+				sp->port.baud_base = 921600;
+				sp->port.pb_info = sb->pb_info;
+				sp->port.irq = sb->irq;
+				sp->port.line = n;
+				sp->port.uartclk = sp->port.baud_base * 16;
+				sp->port.iotype = SNX_UPIO_PORT;
+				sp->port.flags = ASYNC_SHARE_IRQ;
+				sp->port.ldisc_stop_rx = 0;
+				spin_lock_init(&sp->port.lock);
+
+				if (sp->port.chip_flag == SUN1889_HWID) {
+					sp->port.snx_type = SNX_SER_PORT_SUN1889;
+					sp->port.type = PORT_SER_16650V2;
+					sp->port.fifosize = SUN1889_FIFOSIZE_SET;
+					sp->port.rx_trigger = SUN1889_TRIGGER_LEVEL_SET;
+				} else if (sp->port.chip_flag == SUN1699_HWID) {
+					sp->port.snx_type = SNX_SER_PORT_SUN1699;
+					sp->port.type = PORT_SER_16650V2;
+					sp->port.fifosize = SUN1699_FIFOSIZE_SET;
+					sp->port.rx_trigger = SUN1699_TRIGGER_LEVEL_SET;
+				} else if (sp->port.chip_flag == SUNMATX_HWID) {
+					sp->port.snx_type = SNX_SER_PORT_SUNMATX;
+					sp->port.type = PORT_SER_16750;
+					sp->port.fifosize = SUNMATX_FIFOSIZE_SET;
+					sp->port.rx_trigger = SUNMATX_TRIGGER_LEVEL_SET;
+				} else if (sp->port.chip_flag == SUN1999_HWID) {
+					sp->port.snx_type = SNX_SER_PORT_SUN1999;
+					sp->port.type = PORT_SER_16750;
+					sp->port.fifosize = SUN1999_FIFOSIZE_SET;
+					sp->port.rx_trigger = SUN1999_TRIGGER_LEVEL_SET;
+				} else {
+					sp->port.snx_type = SNX_SER_PORT_UNKNOWN;
+					sp->port.type = PORT_SER_16450;
+					sp->port.fifosize = DEFAULT_FIFOSIZE;
+					sp->port.rx_trigger = DEFAULT_TRIGGER_LEVEL;
+				}
+
+
+				if ((sb->pb_info.board_flag & BOARDFLAG_REMAP) == BOARDFLAG_REMAP) {
+					sp->port.vector_mask = 0;
+					sp->port.port_flag = PORTFLAG_REMAP;
+				} else {
+					sp->port.vector_mask = sb->vector_mask;
+					sp->port.port_flag = PORTFLAG_NONE;
+				}
+
+				if ((sb->pb_info.board_flag & BOARDFLAG_16PORTS) == BOARDFLAG_16PORTS) {
+						sp->port.port_flag |= PORTFLAG_16PORTS;
+				}
+
+				sp->port.setserial_flag = SNX_SER_BAUD_NOTSETSER;
+			}
+
+			sb->ser_isr = sunix_ser_interrupt;
+		} else {
+			sb->ser_isr = NULL;
+		}
+	}
+
+
+	// release io resource
+	for (i = 0; i < SNX_SER_TOTAL_MAX; i++) {
+		sp = &sunix_ser_table[i];
+
+		if (sp->port.iobase > 0) {
+			release_region(sp->port.iobase, SNX_SER_ADDRESS_LENGTH);
+		}
+	}
+    return status;
+}
+
+
+static int sunix_par_port_table_init(void)
+{
+	struct sunix_board *sb = NULL;
+	struct sunix_par_port *pp = NULL;
+    int status = 0;
+	int i;
+	int j;
+	int k;
+
+	for (i = 0; i < SNX_BOARDS_MAX; i++) {
+		sb = &sunix_board_table[i];
+
+		if (sb == NULL) {
+			status = -ENXIO;
+			printk("SNX Error: Board table pointer error !\n");
+			return status;
+		}
+
+		if ((sb->board_enum > 0) && (sb->par_port > 0)) {
+			k = 0;
+			for (j = 0; j < SNX_PAR_TOTAL_MAX; j++) {
+				pp = &sunix_par_table[j];
+
+				if (pp == NULL) {
+					status = -ENXIO;
+					printk("SNX Error: Parallel port table pointer error !\n");
+					return status;
+				}
+
+				if ((k + 1) > sb->par_port) {
+					break;
+				}
+
+
+				if ((pp->bus_number == sb->bus_number) &&
+					(pp->dev_number == sb->dev_number) &&
+					(pp->board_enum	== sb->board_enum)) {
+
+					pp->pb_info = sb->pb_info;
+					//pp->irq 				= sb->irq;
+					pp->irq	= PARPORT_IRQ_NONE;
+					pp->portnum = j;
+
+					if (pp->chip_flag == SUN1888_HWID) {
+						pp->snx_type =
+						SNX_PAR_PORT_SUN1888;
+					} else if (pp->chip_flag ==
+						SUN1689_HWID) {
+						pp->snx_type =
+						SNX_PAR_PORT_SUN1689;
+					} else if (pp->chip_flag ==
+						SUNMATX_HWID) {
+						pp->snx_type =
+						SNX_PAR_PORT_SUNMATX;
+					} else if (pp->chip_flag ==
+						SUN1999_HWID) {
+						pp->snx_type =
+						SNX_PAR_PORT_SUN1999;
+					} else {
+						pp->snx_type =
+						SNX_PAR_PORT_UNKNOWN;
+					}
+
+					if ((sb->pb_info.board_flag &
+						BOARDFLAG_REMAP) ==
+						BOARDFLAG_REMAP) {
+						pp->port_flag = PORTFLAG_REMAP;
+					} else {
+						pp->port_flag = PORTFLAG_NONE;
+					}
+					sb->par_isr = NULL;
+					k++;
+				}
+			}
+		}
+	}
+
+
+	// release io resource
+	for (i = 0; i < SNX_PAR_TOTAL_MAX; i++) {
+		pp = &sunix_par_table[i];
+
+		if (pp->base > 0) {
+			release_region(pp->base, SNX_PAR_ADDRESS_LENGTH);
+
+
+			release_region(pp->base, SNX_PAR_STD_ADDR_LENGTH);
+
+			release_region(pp->base +
+			SNX_PAR_STD_ADDR_LENGTH,
+			SNX_PAR_ETD_ADDR_LENGTH);
+
+			if (pp->base_hi > 0) {
+				release_region(pp->base_hi,
+				SNX_PAR_ADDRESS_LENGTH);
+
+				release_region(pp->base_hi,
+				SNX_PAR_STD_ADDR_LENGTH);
+
+				release_region(pp->base_hi +
+				SNX_PAR_STD_ADDR_LENGTH,
+				SNX_PAR_ETD_ADDR_LENGTH);
+			}
+		}
+	}
+
+	return status;
+}
+
+int sunix_register_irq(void)
+{
+	struct sunix_board *sb = NULL;
+	int status = 0;
+	int i;
+
+	for (i = 0; i < SNX_BOARDS_MAX; i++) {
+		sb = &sunix_board_table[i];
+
+		if (sb == NULL) {
+			status = -ENXIO;
+			pr_err("SNX Error: Board table pointer error !\n");
+			return status;
+		}
+
+			if (sb->board_enum > 0) {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+				status = request_irq(sb->irq,
+				sunix_interrupt,
+				IRQF_SHARED,
+				"snx", sb);
+#else
+					status = request_irq(sb->irq,
+					sunix_interrupt,
+					SA_SHIRQ,
+					"snx", sb);
+#endif
+
+			if (status) {
+				pr_err("SNX Error: SUNIX Multi-I/O %s Board(bus:%d device:%d), request\n",
+				sb->pb_info.board_name,
+				sb->bus_number,
+				sb->dev_number);
+				pr_err("           IRQ %d fail, IRQ %d may be conflit with another device.\n",
+				sb->irq, sb->irq);
+				return status;
+			}
+		}
+	}
+
+	return status;
+}
+
+
+void sunix_release_irq(void)
+{
+
+	struct sunix_board *sb = NULL;
+	int i;
+
+	for (i = 0; i < SNX_BOARDS_MAX; i++) {
+		sb = &sunix_board_table[i];
+
+		if (sb->board_enum > 0)
+			free_irq(sb->irq, sb);
+	}
+}
+
+static struct pci_driver snx_pci_driver = {
+	.name			= "snx",
+	.probe			= snx_pci_probe,
+	.suspend		= snx_suspend_one,
+	.resume			= snx_resume_one,
+	.id_table		= sunix_pci_board_id,
+};
+
+static int __init snx_init(void)
+{
+	int status = 0;
+
+	pr_err("\n\n");
+	pr_err("=====================  SUNIX Device Driver Module Install  =====================\n");
+	pr_err("\n");
+	pr_err("SNX Info : Loading SUNIX Multi-I/O Board Driver Module\n");
+	pr_err("                                                       -- Date :    %s\n",
+	SNX_DRIVER_DATE);
+	pr_err("                                                       -- Version : %s\n\n",
+	SNX_DRIVER_VERSION);
+
+	snx_ser_port_total_cnt = snx_par_port_total_cnt = 0;
+
+	status = sunix_pci_board_probe();
+	if (status != 0)
+		goto step1_fail;
+
+	status = sunix_get_pci_board_conf();
+	if (status != 0)
+		goto step1_fail;
+
+	status = sunix_assign_resource();
+	if (status != 0)
+		goto step1_fail;
+
+	status = sunix_ser_port_table_init();
+	if (status != 0)
+		goto step1_fail;
+
+	status = sunix_par_port_table_init();
+	if (status != 0)
+		goto step1_fail;
+
+	status = sunix_register_irq();
+	if (status != 0)
+		goto step1_fail;
+
+	status = sunix_ser_register_driver(&sunix_ser_reg);
+	if (status != 0)
+		goto step2_fail;
+
+	status = sunix_ser_register_ports(&sunix_ser_reg);
+	if (status != 0)
+		goto step3_fail;
+
+	status = pci_register_driver(&snx_pci_driver);
+	if (status != 0)
+		goto step7_fail;
+
+	if (snx_par_port_total_cnt > 0) {
+		status = sunix_par_parport_init();
+		if (status != 0)
+			goto step4_fail;
+
+		status = sunix_par_ppdev_init();
+		if (status != 0)
+			goto step5_fail;
+
+		status = sunix_par_lp_init();
+		if (status != 0)
+			goto step6_fail;
+	}
+
+#if SNX_DBG
+	sunix_debug();
+#endif
+
+
+	pr_err("================================================================================\n");
+	return status;
+
+
+	if (snx_par_port_total_cnt > 0) {
+step7_fail:
+
+		pci_unregister_driver(&snx_pci_driver);
+step6_fail:
+
+		sunix_par_ppdev_exit();
+
+
+step5_fail:
+
+		sunix_par_parport_exit();
+
+
+step4_fail:
+
+		sunix_ser_unregister_ports(&sunix_ser_reg);
+	}
+
+step3_fail:
+
+	sunix_ser_unregister_driver(&sunix_ser_reg);
+
+
+step2_fail:
+
+	sunix_release_irq();
+
+
+step1_fail:
+
+	pr_err("SNX Error: Couldn't Loading SUNIX Multi-I/O Board Driver Module correctly,\n");
+	pr_err("           please reboot system and try again. If still can't loading driver,\n");
+	pr_err("           contact support.\n\n");
+	pr_err("================================================================================\n");
+	return status;
+
+}
+
+
+static void __exit snx_exit(void)
+{
+	pr_err("\n\n");
+	pr_err("====================  SUNIX Device Driver Module Uninstall  ====================\n");
+	pr_err("\n");
+
+	if (snx_par_port_total_cnt > 0) {
+		sunix_par_lp_exit();
+
+		sunix_par_ppdev_exit();
+
+		sunix_par_parport_exit();
+	}
+
+	sunix_ser_unregister_ports(&sunix_ser_reg);
+
+	sunix_ser_unregister_driver(&sunix_ser_reg);
+
+	sunix_release_irq();
+	pci_unregister_driver(&snx_pci_driver);
+	pr_err("SNX Info : Unload SUNIX Multi-I/O Board Driver Module Done.\n");
+	pr_err("================================================================================\n");
+}
+
+module_init(snx_init);
+module_exit(snx_exit);
+
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ