File-copy from v4.4.100

This is the result of 'cp' from a linux-stable tree with the 'v4.4.100'
tag checked out (commit 26d6298789e695c9f627ce49a7bbd2286405798a) on
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git

Please refer to that tree for all history prior to this point.

Change-Id: I8a9ee2aea93cd29c52c847d0ce33091a73ae6afe
diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig
new file mode 100644
index 0000000..36bc28c
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/Kconfig
@@ -0,0 +1,47 @@
+
+config USB_SISUSBVGA
+	tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
+	depends on (USB_MUSB_HDRC || USB_EHCI_HCD)
+	select FONT_SUPPORT if USB_SISUSBVGA_CON
+        ---help---
+	  Say Y here if you intend to attach a USB2VGA dongle based on a
+	  Net2280 and a SiS315 chip.
+
+	  Note that this device requires a USB 2.0 host controller. It will not
+	  work with USB 1.x controllers.
+
+	  To compile this driver as a module, choose M here; the module will be
+	  called sisusbvga. If unsure, say N.
+
+config USB_SISUSBVGA_CON
+	bool "Text console and mode switching support" if USB_SISUSBVGA
+	depends on VT
+	select FONT_8x16
+	---help---
+	  Say Y here if you want a VGA text console via the USB dongle or
+	  want to support userland applications that utilize the driver's
+	  display mode switching capabilities.
+
+	  Note that this console supports VGA/EGA text mode only.
+
+	  By default, the console part of the driver will not kick in when
+	  the driver is initialized. If you want the driver to take over
+	  one or more of the consoles, you need to specify the number of
+	  the first and last consoles (starting at 1) as driver parameters.
+
+	  For example, if the driver is compiled as a module:
+
+	     modprobe sisusbvga first=1 last=5
+
+	  If you use hotplug, add this to your modutils config files with
+	  the "options" keyword, such as eg.
+
+	     options sisusbvga first=1 last=5
+
+	  If the driver is compiled into the kernel image, the parameters
+	  must be given in the kernel command like, such as
+
+	     sisusbvga.first=1 sisusbvga.last=5
+
+
+
diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile
new file mode 100644
index 0000000..3142476
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the sisusb driver (if driver is inside kernel tree).
+#
+
+obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o
+
+sisusbvga-y := sisusb.o sisusb_init.o sisusb_con.o
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
new file mode 100644
index 0000000..306d685
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -0,0 +1,3301 @@
+/*
+ * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
+ *
+ * Main part
+ *
+ * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific psisusbr written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+
+#include "sisusb.h"
+#include "sisusb_init.h"
+
+#ifdef INCL_SISUSB_CON
+#include <linux/font.h>
+#endif
+
+#define SISUSB_DONTSYNC
+
+/* Forward declarations / clean-up routines */
+
+#ifdef INCL_SISUSB_CON
+static int sisusb_first_vc = 0;
+static int sisusb_last_vc = 0;
+module_param_named(first, sisusb_first_vc, int, 0);
+module_param_named(last, sisusb_last_vc, int, 0);
+MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
+MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
+#endif
+
+static struct usb_driver sisusb_driver;
+
+static void
+sisusb_free_buffers(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	for (i = 0; i < NUMOBUFS; i++) {
+		if (sisusb->obuf[i]) {
+			kfree(sisusb->obuf[i]);
+			sisusb->obuf[i] = NULL;
+		}
+	}
+	if (sisusb->ibuf) {
+		kfree(sisusb->ibuf);
+		sisusb->ibuf = NULL;
+	}
+}
+
+static void
+sisusb_free_urbs(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	for (i = 0; i < NUMOBUFS; i++) {
+		usb_free_urb(sisusb->sisurbout[i]);
+		sisusb->sisurbout[i] = NULL;
+	}
+	usb_free_urb(sisusb->sisurbin);
+	sisusb->sisurbin = NULL;
+}
+
+/* Level 0: USB transport layer */
+
+/* 1. out-bulks */
+
+/* out-urb management */
+
+/* Return 1 if all free, 0 otherwise */
+static int
+sisusb_all_free(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	for (i = 0; i < sisusb->numobufs; i++) {
+
+		if (sisusb->urbstatus[i] & SU_URB_BUSY)
+			return 0;
+
+	}
+
+	return 1;
+}
+
+/* Kill all busy URBs */
+static void
+sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	if (sisusb_all_free(sisusb))
+		return;
+
+	for (i = 0; i < sisusb->numobufs; i++) {
+
+		if (sisusb->urbstatus[i] & SU_URB_BUSY)
+			usb_kill_urb(sisusb->sisurbout[i]);
+
+	}
+}
+
+/* Return 1 if ok, 0 if error (not all complete within timeout) */
+static int
+sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
+{
+	int timeout = 5 * HZ, i = 1;
+
+	wait_event_timeout(sisusb->wait_q,
+				(i = sisusb_all_free(sisusb)),
+				 timeout);
+
+	return i;
+}
+
+static int
+sisusb_outurb_available(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	for (i = 0; i < sisusb->numobufs; i++) {
+
+		if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
+			return i;
+
+	}
+
+	return -1;
+}
+
+static int
+sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
+{
+	int i, timeout = 5 * HZ;
+
+	wait_event_timeout(sisusb->wait_q,
+				((i = sisusb_outurb_available(sisusb)) >= 0),
+				timeout);
+
+	return i;
+}
+
+static int
+sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	i = sisusb_outurb_available(sisusb);
+
+	if (i >= 0)
+		sisusb->urbstatus[i] |= SU_URB_ALLOC;
+
+	return i;
+}
+
+static void
+sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
+{
+	if ((index >= 0) && (index < sisusb->numobufs))
+		sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
+}
+
+/* completion callback */
+
+static void
+sisusb_bulk_completeout(struct urb *urb)
+{
+	struct sisusb_urb_context *context = urb->context;
+	struct sisusb_usb_data *sisusb;
+
+	if (!context)
+		return;
+
+	sisusb = context->sisusb;
+
+	if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
+		return;
+
+#ifndef SISUSB_DONTSYNC
+	if (context->actual_length)
+		*(context->actual_length) += urb->actual_length;
+#endif
+
+	sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
+	wake_up(&sisusb->wait_q);
+}
+
+static int
+sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
+		int len, int *actual_length, int timeout, unsigned int tflags)
+{
+	struct urb *urb = sisusb->sisurbout[index];
+	int retval, byteswritten = 0;
+
+	/* Set up URB */
+	urb->transfer_flags = 0;
+
+	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
+		sisusb_bulk_completeout, &sisusb->urbout_context[index]);
+
+	urb->transfer_flags |= tflags;
+	urb->actual_length = 0;
+
+	/* Set up context */
+	sisusb->urbout_context[index].actual_length = (timeout) ?
+						NULL : actual_length;
+
+	/* Declare this urb/buffer in use */
+	sisusb->urbstatus[index] |= SU_URB_BUSY;
+
+	/* Submit URB */
+	retval = usb_submit_urb(urb, GFP_KERNEL);
+
+	/* If OK, and if timeout > 0, wait for completion */
+	if ((retval == 0) && timeout) {
+		wait_event_timeout(sisusb->wait_q,
+				   (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
+				   timeout);
+		if (sisusb->urbstatus[index] & SU_URB_BUSY) {
+			/* URB timed out... kill it and report error */
+			usb_kill_urb(urb);
+			retval = -ETIMEDOUT;
+		} else {
+			/* Otherwise, report urb status */
+			retval = urb->status;
+			byteswritten = urb->actual_length;
+		}
+	}
+
+	if (actual_length)
+		*actual_length = byteswritten;
+
+	return retval;
+}
+
+/* 2. in-bulks */
+
+/* completion callback */
+
+static void
+sisusb_bulk_completein(struct urb *urb)
+{
+	struct sisusb_usb_data *sisusb = urb->context;
+
+	if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
+		return;
+
+	sisusb->completein = 1;
+	wake_up(&sisusb->wait_q);
+}
+
+static int
+sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
+	int len, int *actual_length, int timeout, unsigned int tflags)
+{
+	struct urb *urb = sisusb->sisurbin;
+	int retval, readbytes = 0;
+
+	urb->transfer_flags = 0;
+
+	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
+			sisusb_bulk_completein, sisusb);
+
+	urb->transfer_flags |= tflags;
+	urb->actual_length = 0;
+
+	sisusb->completein = 0;
+	retval = usb_submit_urb(urb, GFP_KERNEL);
+	if (retval == 0) {
+		wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
+		if (!sisusb->completein) {
+			/* URB timed out... kill it and report error */
+			usb_kill_urb(urb);
+			retval = -ETIMEDOUT;
+		} else {
+			/* URB completed within timeout */
+			retval = urb->status;
+			readbytes = urb->actual_length;
+		}
+	}
+
+	if (actual_length)
+		*actual_length = readbytes;
+
+	return retval;
+}
+
+
+/* Level 1:  */
+
+/* Send a bulk message of variable size
+ *
+ * To copy the data from userspace, give pointer to "userbuffer",
+ * to copy from (non-DMA) kernel memory, give "kernbuffer". If
+ * both of these are NULL, it is assumed, that the transfer
+ * buffer "sisusb->obuf[index]" is set up with the data to send.
+ * Index is ignored if either kernbuffer or userbuffer is set.
+ * If async is nonzero, URBs will be sent without waiting for
+ * completion of the previous URB.
+ *
+ * (return 0 on success)
+ */
+
+static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
+		char *kernbuffer, const char __user *userbuffer, int index,
+		ssize_t *bytes_written, unsigned int tflags, int async)
+{
+	int result = 0, retry, count = len;
+	int passsize, thispass, transferred_len = 0;
+	int fromuser = (userbuffer != NULL) ? 1 : 0;
+	int fromkern = (kernbuffer != NULL) ? 1 : 0;
+	unsigned int pipe;
+	char *buffer;
+
+	(*bytes_written) = 0;
+
+	/* Sanity check */
+	if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
+		return -ENODEV;
+
+	/* If we copy data from kernel or userspace, force the
+	 * allocation of a buffer/urb. If we have the data in
+	 * the transfer buffer[index] already, reuse the buffer/URB
+	 * if the length is > buffer size. (So, transmitting
+	 * large data amounts directly from the transfer buffer
+	 * treats the buffer as a ring buffer. However, we need
+	 * to sync in this case.)
+	 */
+	if (fromuser || fromkern)
+		index = -1;
+	else if (len > sisusb->obufsize)
+		async = 0;
+
+	pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
+
+	do {
+		passsize = thispass = (sisusb->obufsize < count) ?
+						sisusb->obufsize : count;
+
+		if (index < 0)
+			index = sisusb_get_free_outbuf(sisusb);
+
+		if (index < 0)
+			return -EIO;
+
+		buffer = sisusb->obuf[index];
+
+		if (fromuser) {
+
+			if (copy_from_user(buffer, userbuffer, passsize))
+				return -EFAULT;
+
+			userbuffer += passsize;
+
+		} else if (fromkern) {
+
+			memcpy(buffer, kernbuffer, passsize);
+			kernbuffer += passsize;
+
+		}
+
+		retry = 5;
+		while (thispass) {
+
+			if (!sisusb->sisusb_dev)
+				return -ENODEV;
+
+			result = sisusb_bulkout_msg(sisusb,
+						index,
+						pipe,
+						buffer,
+						thispass,
+						&transferred_len,
+						async ? 0 : 5 * HZ,
+						tflags);
+
+			if (result == -ETIMEDOUT) {
+
+				/* Will not happen if async */
+				if (!retry--)
+					return -ETIME;
+
+				continue;
+			}
+
+			if ((result == 0) && !async && transferred_len) {
+
+				thispass -= transferred_len;
+				buffer += transferred_len;
+
+			} else
+				break;
+		}
+
+		if (result)
+			return result;
+
+		(*bytes_written) += passsize;
+		count            -= passsize;
+
+		/* Force new allocation in next iteration */
+		if (fromuser || fromkern)
+			index = -1;
+
+	} while (count > 0);
+
+	if (async) {
+#ifdef SISUSB_DONTSYNC
+		(*bytes_written) = len;
+		/* Some URBs/buffers might be busy */
+#else
+		sisusb_wait_all_out_complete(sisusb);
+		(*bytes_written) = transferred_len;
+		/* All URBs and all buffers are available */
+#endif
+	}
+
+	return ((*bytes_written) == len) ? 0 : -EIO;
+}
+
+/* Receive a bulk message of variable size
+ *
+ * To copy the data to userspace, give pointer to "userbuffer",
+ * to copy to kernel memory, give "kernbuffer". One of them
+ * MUST be set. (There is no technique for letting the caller
+ * read directly from the ibuf.)
+ *
+ */
+
+static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
+		void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
+		unsigned int tflags)
+{
+	int result = 0, retry, count = len;
+	int bufsize, thispass, transferred_len;
+	unsigned int pipe;
+	char *buffer;
+
+	(*bytes_read) = 0;
+
+	/* Sanity check */
+	if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
+		return -ENODEV;
+
+	pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
+	buffer = sisusb->ibuf;
+	bufsize = sisusb->ibufsize;
+
+	retry = 5;
+
+#ifdef SISUSB_DONTSYNC
+	if (!(sisusb_wait_all_out_complete(sisusb)))
+		return -EIO;
+#endif
+
+	while (count > 0) {
+
+		if (!sisusb->sisusb_dev)
+			return -ENODEV;
+
+		thispass = (bufsize < count) ? bufsize : count;
+
+		result = sisusb_bulkin_msg(sisusb,
+					   pipe,
+					   buffer,
+					   thispass,
+					   &transferred_len,
+					   5 * HZ,
+					   tflags);
+
+		if (transferred_len)
+			thispass = transferred_len;
+
+		else if (result == -ETIMEDOUT) {
+
+			if (!retry--)
+				return -ETIME;
+
+			continue;
+
+		} else
+			return -EIO;
+
+
+		if (thispass) {
+
+			(*bytes_read) += thispass;
+			count         -= thispass;
+
+			if (userbuffer) {
+
+				if (copy_to_user(userbuffer, buffer, thispass))
+					return -EFAULT;
+
+				userbuffer += thispass;
+
+			} else {
+
+				memcpy(kernbuffer, buffer, thispass);
+				kernbuffer += thispass;
+
+			}
+
+		}
+
+	}
+
+	return ((*bytes_read) == len) ? 0 : -EIO;
+}
+
+static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
+						struct sisusb_packet *packet)
+{
+	int ret;
+	ssize_t bytes_transferred = 0;
+	__le32 tmp;
+
+	if (len == 6)
+		packet->data = 0;
+
+#ifdef SISUSB_DONTSYNC
+	if (!(sisusb_wait_all_out_complete(sisusb)))
+		return 1;
+#endif
+
+	/* Eventually correct endianness */
+	SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
+
+	/* 1. send the packet */
+	ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
+			(char *)packet, NULL, 0, &bytes_transferred, 0, 0);
+
+	if ((ret == 0) && (len == 6)) {
+
+		/* 2. if packet len == 6, it means we read, so wait for 32bit
+		 *    return value and write it to packet->data
+		 */
+		ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
+				(char *)&tmp, NULL, &bytes_transferred, 0);
+
+		packet->data = le32_to_cpu(tmp);
+	}
+
+	return ret;
+}
+
+static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
+					struct sisusb_packet *packet,
+					unsigned int tflags)
+{
+	int ret;
+	ssize_t bytes_transferred = 0;
+	__le32 tmp;
+
+	if (len == 6)
+		packet->data = 0;
+
+#ifdef SISUSB_DONTSYNC
+	if (!(sisusb_wait_all_out_complete(sisusb)))
+		return 1;
+#endif
+
+	/* Eventually correct endianness */
+	SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
+
+	/* 1. send the packet */
+	ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
+			(char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
+
+	if ((ret == 0) && (len == 6)) {
+
+		/* 2. if packet len == 6, it means we read, so wait for 32bit
+		 *    return value and write it to packet->data
+		 */
+		ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
+				(char *)&tmp, NULL, &bytes_transferred, 0);
+
+		packet->data = le32_to_cpu(tmp);
+	}
+
+	return ret;
+}
+
+/* access video memory and mmio (return 0 on success) */
+
+/* Low level */
+
+/* The following routines assume being used to transfer byte, word,
+ * long etc.
+ * This means that
+ *   - the write routines expect "data" in machine endianness format.
+ *     The data will be converted to leXX in sisusb_xxx_packet.
+ *   - the read routines can expect read data in machine-endianess.
+ */
+
+static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u8 data)
+{
+	struct sisusb_packet packet;
+	int ret;
+
+	packet.header  = (1 << (addr & 3)) | (type << 6);
+	packet.address = addr & ~3;
+	packet.data    = data << ((addr & 3) << 3);
+	ret = sisusb_send_packet(sisusb, 10, &packet);
+	return ret;
+}
+
+static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u16 data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header = (type << 6) | 0x0003;
+			packet.data   = (u32)data;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 1:
+			packet.header = (type << 6) | 0x0006;
+			packet.data   = (u32)data << 8;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 2:
+			packet.header = (type << 6) | 0x000c;
+			packet.data   = (u32)data << 16;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 3:
+			packet.header = (type << 6) | 0x0008;
+			packet.data   = (u32)data << 24;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			packet.data   = (u32)data >> 8;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+	}
+
+	return ret;
+}
+
+static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u32 data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header  = (type << 6) | 0x0007;
+			packet.data    = data & 0x00ffffff;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 1:
+			packet.header  = (type << 6) | 0x000e;
+			packet.data    = data << 8;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 2:
+			packet.header  = (type << 6) | 0x000c;
+			packet.data    = data << 16;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = (data >> 16) & 0x00ff;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 3:
+			packet.header  = (type << 6) | 0x0008;
+			packet.data    = data << 24;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0003;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = (data >> 8) & 0xffff;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+	}
+
+	return ret;
+}
+
+static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u32 data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header  = (type << 6) | 0x000f;
+			packet.data    = data;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 1:
+			packet.header  = (type << 6) | 0x000e;
+			packet.data    = data << 8;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = data >> 24;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 2:
+			packet.header  = (type << 6) | 0x000c;
+			packet.data    = data << 16;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0003;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = data >> 16;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+			break;
+		case 3:
+			packet.header  = (type << 6) | 0x0008;
+			packet.data    = data << 24;
+			ret = sisusb_send_packet(sisusb, 10, &packet);
+			packet.header  = (type << 6) | 0x0007;
+			packet.address = (addr & ~3) + 4;
+			packet.data    = data >> 8;
+			ret |= sisusb_send_packet(sisusb, 10, &packet);
+	}
+
+	return ret;
+}
+
+/* The xxx_bulk routines copy a buffer of variable size. They treat the
+ * buffer as chars, therefore lsb/msb has to be corrected if using the
+ * byte/word/long/etc routines for speed-up
+ *
+ * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
+ * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
+ * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
+ * that the data already is in the transfer buffer "sisusb->obuf[index]".
+ */
+
+static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
+				char *kernbuffer, int length,
+				const char __user *userbuffer, int index,
+				ssize_t *bytes_written)
+{
+	struct sisusb_packet packet;
+	int  ret = 0;
+	static int msgcount = 0;
+	u8   swap8, fromkern = kernbuffer ? 1 : 0;
+	u16  swap16;
+	u32  swap32, flag = (length >> 28) & 1;
+	char buf[4];
+
+	/* if neither kernbuffer not userbuffer are given, assume
+	 * data in obuf
+	 */
+	if (!fromkern && !userbuffer)
+		kernbuffer = sisusb->obuf[index];
+
+	(*bytes_written = 0);
+
+	length &= 0x00ffffff;
+
+	while (length) {
+
+	    switch (length) {
+
+		case 1:
+			if (userbuffer) {
+				if (get_user(swap8, (u8 __user *)userbuffer))
+					return -EFAULT;
+			} else
+				swap8 = kernbuffer[0];
+
+			ret = sisusb_write_memio_byte(sisusb,
+							SISUSB_TYPE_MEM,
+							addr, swap8);
+
+			if (!ret)
+				(*bytes_written)++;
+
+			return ret;
+
+		case 2:
+			if (userbuffer) {
+				if (get_user(swap16, (u16 __user *)userbuffer))
+					return -EFAULT;
+			} else
+				swap16 = *((u16 *)kernbuffer);
+
+			ret = sisusb_write_memio_word(sisusb,
+							SISUSB_TYPE_MEM,
+							addr,
+							swap16);
+
+			if (!ret)
+				(*bytes_written) += 2;
+
+			return ret;
+
+		case 3:
+			if (userbuffer) {
+				if (copy_from_user(&buf, userbuffer, 3))
+					return -EFAULT;
+#ifdef __BIG_ENDIAN
+				swap32 = (buf[0] << 16) |
+					 (buf[1] <<  8) |
+					 buf[2];
+#else
+				swap32 = (buf[2] << 16) |
+					 (buf[1] <<  8) |
+					 buf[0];
+#endif
+			} else
+#ifdef __BIG_ENDIAN
+				swap32 = (kernbuffer[0] << 16) |
+					 (kernbuffer[1] <<  8) |
+					 kernbuffer[2];
+#else
+				swap32 = (kernbuffer[2] << 16) |
+					 (kernbuffer[1] <<  8) |
+					 kernbuffer[0];
+#endif
+
+			ret = sisusb_write_memio_24bit(sisusb,
+							SISUSB_TYPE_MEM,
+							addr,
+							swap32);
+
+			if (!ret)
+				(*bytes_written) += 3;
+
+			return ret;
+
+		case 4:
+			if (userbuffer) {
+				if (get_user(swap32, (u32 __user *)userbuffer))
+					return -EFAULT;
+			} else
+				swap32 = *((u32 *)kernbuffer);
+
+			ret = sisusb_write_memio_long(sisusb,
+							SISUSB_TYPE_MEM,
+							addr,
+							swap32);
+			if (!ret)
+				(*bytes_written) += 4;
+
+			return ret;
+
+		default:
+			if ((length & ~3) > 0x10000) {
+
+			   packet.header  = 0x001f;
+			   packet.address = 0x000001d4;
+			   packet.data    = addr;
+			   ret = sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			   packet.header  = 0x001f;
+			   packet.address = 0x000001d0;
+			   packet.data    = (length & ~3);
+			   ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			   packet.header  = 0x001f;
+			   packet.address = 0x000001c0;
+			   packet.data    = flag | 0x16;
+			   ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			   if (userbuffer) {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_LBULK_OUT,
+							(length & ~3),
+							NULL, userbuffer, 0,
+							bytes_written, 0, 1);
+				userbuffer += (*bytes_written);
+			   } else if (fromkern) {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_LBULK_OUT,
+							(length & ~3),
+							kernbuffer, NULL, 0,
+							bytes_written, 0, 1);
+				kernbuffer += (*bytes_written);
+			   } else {
+			ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_LBULK_OUT,
+							(length & ~3),
+							NULL, NULL, index,
+							bytes_written, 0, 1);
+				kernbuffer += ((*bytes_written) &
+						(sisusb->obufsize-1));
+			   }
+
+			} else {
+
+			   packet.header  = 0x001f;
+			   packet.address = 0x00000194;
+			   packet.data    = addr;
+			   ret = sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			   packet.header  = 0x001f;
+			   packet.address = 0x00000190;
+			   packet.data    = (length & ~3);
+			   ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+			   if (sisusb->flagb0 != 0x16) {
+				packet.header  = 0x001f;
+				packet.address = 0x00000180;
+				packet.data    = flag | 0x16;
+				ret |= sisusb_send_bridge_packet(sisusb, 10,
+								&packet, 0);
+				sisusb->flagb0 = 0x16;
+			   }
+			   if (userbuffer) {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_BULK_OUT,
+							(length & ~3),
+							NULL, userbuffer, 0,
+							bytes_written, 0, 1);
+				userbuffer += (*bytes_written);
+			   } else if (fromkern) {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_BULK_OUT,
+							(length & ~3),
+							kernbuffer, NULL, 0,
+							bytes_written, 0, 1);
+				kernbuffer += (*bytes_written);
+			   } else {
+				ret |= sisusb_send_bulk_msg(sisusb,
+							SISUSB_EP_GFX_BULK_OUT,
+							(length & ~3),
+							NULL, NULL, index,
+							bytes_written, 0, 1);
+				kernbuffer += ((*bytes_written) &
+						(sisusb->obufsize-1));
+			   }
+			}
+			if (ret) {
+				msgcount++;
+				if (msgcount < 500)
+					dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+						*bytes_written, length, ret);
+				else if (msgcount == 500)
+					dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
+			}
+			addr += (*bytes_written);
+			length -= (*bytes_written);
+	    }
+
+	    if (ret)
+		break;
+
+	}
+
+	return ret ? -EIO : 0;
+}
+
+/* Remember: Read data in packet is in machine-endianess! So for
+ * byte, word, 24bit, long no endian correction is necessary.
+ */
+
+static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u8 *data)
+{
+	struct sisusb_packet packet;
+	int ret;
+
+	CLEARPACKET(&packet);
+	packet.header  = (1 << (addr & 3)) | (type << 6);
+	packet.address = addr & ~3;
+	ret = sisusb_send_packet(sisusb, 6, &packet);
+	*data = (u8)(packet.data >> ((addr & 3) << 3));
+	return ret;
+}
+
+static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u16 *data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	CLEARPACKET(&packet);
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header = (type << 6) | 0x0003;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = (u16)(packet.data);
+			break;
+		case 1:
+			packet.header = (type << 6) | 0x0006;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = (u16)(packet.data >> 8);
+			break;
+		case 2:
+			packet.header = (type << 6) | 0x000c;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = (u16)(packet.data >> 16);
+			break;
+		case 3:
+			packet.header = (type << 6) | 0x0008;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = (u16)(packet.data >> 24);
+			packet.header = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= (u16)(packet.data << 8);
+	}
+
+	return ret;
+}
+
+static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u32 *data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header  = (type << 6) | 0x0007;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data & 0x00ffffff;
+			break;
+		case 1:
+			packet.header  = (type << 6) | 0x000e;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 8;
+			break;
+		case 2:
+			packet.header  = (type << 6) | 0x000c;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 16;
+			packet.header  = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= ((packet.data & 0xff) << 16);
+			break;
+		case 3:
+			packet.header  = (type << 6) | 0x0008;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 24;
+			packet.header  = (type << 6) | 0x0003;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= ((packet.data & 0xffff) << 8);
+	}
+
+	return ret;
+}
+
+static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
+							u32 addr, u32 *data)
+{
+	struct sisusb_packet packet;
+	int ret = 0;
+
+	packet.address = addr & ~3;
+
+	switch (addr & 3) {
+		case 0:
+			packet.header  = (type << 6) | 0x000f;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data;
+			break;
+		case 1:
+			packet.header  = (type << 6) | 0x000e;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 8;
+			packet.header  = (type << 6) | 0x0001;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= (packet.data << 24);
+			break;
+		case 2:
+			packet.header  = (type << 6) | 0x000c;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 16;
+			packet.header  = (type << 6) | 0x0003;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= (packet.data << 16);
+			break;
+		case 3:
+			packet.header  = (type << 6) | 0x0008;
+			ret = sisusb_send_packet(sisusb, 6, &packet);
+			*data = packet.data >> 24;
+			packet.header  = (type << 6) | 0x0007;
+			packet.address = (addr & ~3) + 4;
+			ret |= sisusb_send_packet(sisusb, 6, &packet);
+			*data |= (packet.data << 8);
+	}
+
+	return ret;
+}
+
+static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
+				char *kernbuffer, int length,
+				char __user *userbuffer, ssize_t *bytes_read)
+{
+	int ret = 0;
+	char buf[4];
+	u16 swap16;
+	u32 swap32;
+
+	(*bytes_read = 0);
+
+	length &= 0x00ffffff;
+
+	while (length) {
+
+	    switch (length) {
+
+		case 1:
+
+			ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
+								addr, &buf[0]);
+			if (!ret) {
+				(*bytes_read)++;
+				if (userbuffer) {
+					if (put_user(buf[0],
+						(u8 __user *)userbuffer)) {
+						return -EFAULT;
+					}
+				} else {
+					kernbuffer[0] = buf[0];
+				}
+			}
+			return ret;
+
+		case 2:
+			ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
+								addr, &swap16);
+			if (!ret) {
+				(*bytes_read) += 2;
+				if (userbuffer) {
+					if (put_user(swap16,
+						(u16 __user *)userbuffer))
+						return -EFAULT;
+				} else {
+					*((u16 *)kernbuffer) = swap16;
+				}
+			}
+			return ret;
+
+		case 3:
+			ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
+								addr, &swap32);
+			if (!ret) {
+				(*bytes_read) += 3;
+#ifdef __BIG_ENDIAN
+				buf[0] = (swap32 >> 16) & 0xff;
+				buf[1] = (swap32 >> 8) & 0xff;
+				buf[2] = swap32 & 0xff;
+#else
+				buf[2] = (swap32 >> 16) & 0xff;
+				buf[1] = (swap32 >> 8) & 0xff;
+				buf[0] = swap32 & 0xff;
+#endif
+				if (userbuffer) {
+					if (copy_to_user(userbuffer, &buf[0], 3))
+						return -EFAULT;
+				} else {
+					kernbuffer[0] = buf[0];
+					kernbuffer[1] = buf[1];
+					kernbuffer[2] = buf[2];
+				}
+			}
+			return ret;
+
+		default:
+			ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
+								addr, &swap32);
+			if (!ret) {
+				(*bytes_read) += 4;
+				if (userbuffer) {
+					if (put_user(swap32,
+						(u32 __user *)userbuffer))
+						return -EFAULT;
+
+					userbuffer += 4;
+				} else {
+					*((u32 *)kernbuffer) = swap32;
+					kernbuffer += 4;
+				}
+				addr += 4;
+				length -= 4;
+			}
+	    }
+
+	    if (ret)
+		break;
+	}
+
+	return ret;
+}
+
+/* High level: Gfx (indexed) register access */
+
+#ifdef INCL_SISUSB_CON
+int
+sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
+{
+	return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
+}
+
+int
+sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
+{
+	return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
+}
+#endif
+
+int
+sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
+{
+	int ret;
+	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
+	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
+	return ret;
+}
+
+int
+sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
+{
+	int ret;
+	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
+	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
+	return ret;
+}
+
+int
+sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
+							u8 myand, u8 myor)
+{
+	int ret;
+	u8 tmp;
+
+	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
+	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
+	tmp &= myand;
+	tmp |= myor;
+	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
+	return ret;
+}
+
+static int
+sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
+							u8 data, u8 mask)
+{
+	int ret;
+	u8 tmp;
+	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
+	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
+	tmp &= ~(mask);
+	tmp |= (data & mask);
+	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
+	return ret;
+}
+
+int
+sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
+{
+	return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
+}
+
+int
+sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
+{
+	return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
+}
+
+/* Write/read video ram */
+
+#ifdef INCL_SISUSB_CON
+int
+sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
+{
+	return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
+}
+
+int
+sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
+{
+	return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
+}
+
+int
+sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
+			u32 dest, int length, size_t *bytes_written)
+{
+	return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
+}
+
+#ifdef SISUSBENDIANTEST
+int
+sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
+			u32 src, int length, size_t *bytes_written)
+{
+	return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
+}
+#endif
+#endif
+
+#ifdef SISUSBENDIANTEST
+static void
+sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
+{
+    static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
+    char destbuffer[10];
+    size_t dummy;
+    int i,j;
+
+    sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
+
+    for(i = 1; i <= 7; i++) {
+        dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
+	sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
+	for(j = 0; j < i; j++) {
+	     dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
+	}
+    }
+}
+#endif
+
+/* access pci config registers (reg numbers 0, 4, 8, etc) */
+
+static int
+sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
+{
+	struct sisusb_packet packet;
+	int ret;
+
+	packet.header = 0x008f;
+	packet.address = regnum | 0x10000;
+	packet.data = data;
+	ret = sisusb_send_packet(sisusb, 10, &packet);
+	return ret;
+}
+
+static int
+sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
+{
+	struct sisusb_packet packet;
+	int ret;
+
+	packet.header = 0x008f;
+	packet.address = (u32)regnum | 0x10000;
+	ret = sisusb_send_packet(sisusb, 6, &packet);
+	*data = packet.data;
+	return ret;
+}
+
+/* Clear video RAM */
+
+static int
+sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
+{
+	int ret, i;
+	ssize_t j;
+
+	if (address < sisusb->vrambase)
+		return 1;
+
+	if (address >= sisusb->vrambase + sisusb->vramsize)
+		return 1;
+
+	if (address + length > sisusb->vrambase + sisusb->vramsize)
+		length = sisusb->vrambase + sisusb->vramsize - address;
+
+	if (length <= 0)
+		return 0;
+
+	/* allocate free buffer/urb and clear the buffer */
+	if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
+		return -EBUSY;
+
+	memset(sisusb->obuf[i], 0, sisusb->obufsize);
+
+	/* We can write a length > buffer size here. The buffer
+	 * data will simply be re-used (like a ring-buffer).
+	 */
+	ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
+
+	/* Free the buffer/urb */
+	sisusb_free_outbuf(sisusb, i);
+
+	return ret;
+}
+
+/* Initialize the graphics core (return 0 on success)
+ * This resets the graphics hardware and puts it into
+ * a defined mode (640x480@60Hz)
+ */
+
+#define GETREG(r,d)     sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
+#define SETREG(r,d)	sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
+#define SETIREG(r,i,d)	sisusb_setidxreg(sisusb, r, i, d)
+#define GETIREG(r,i,d)  sisusb_getidxreg(sisusb, r, i, d)
+#define SETIREGOR(r,i,o)	sisusb_setidxregor(sisusb, r, i, o)
+#define SETIREGAND(r,i,a)	sisusb_setidxregand(sisusb, r, i, a)
+#define SETIREGANDOR(r,i,a,o)	sisusb_setidxregandor(sisusb, r, i, a, o)
+#define READL(a,d)	sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d)	sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define READB(a,d)	sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d)	sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+
+static int
+sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
+{
+	int ret;
+	u8 tmp8;
+
+	ret = GETIREG(SISSR, 0x16, &tmp8);
+	if (ramtype <= 1) {
+		tmp8 &= 0x3f;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 |= 0x80;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+	} else {
+		tmp8 |= 0xc0;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 &= 0x0f;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 |= 0x80;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 &= 0x0f;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 |= 0xd0;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 &= 0x0f;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+		tmp8 |= 0xa0;
+		ret |= SETIREG(SISSR, 0x16, tmp8);
+	}
+	return ret;
+}
+
+static int
+sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
+{
+	int ret;
+	u8  ramtype, done = 0;
+	u32 t0, t1, t2, t3;
+	u32 ramptr = SISUSB_PCI_MEMBASE;
+
+	ret = GETIREG(SISSR, 0x3a, &ramtype);
+	ramtype &= 3;
+
+	ret |= SETIREG(SISSR, 0x13, 0x00);
+
+	if (ramtype <= 1) {
+		ret |= SETIREG(SISSR, 0x14, 0x12);
+		ret |= SETIREGAND(SISSR, 0x15, 0xef);
+	} else {
+		ret |= SETIREG(SISSR, 0x14, 0x02);
+	}
+
+	ret |= sisusb_triggersr16(sisusb, ramtype);
+	ret |= WRITEL(ramptr +  0, 0x01234567);
+	ret |= WRITEL(ramptr +  4, 0x456789ab);
+	ret |= WRITEL(ramptr +  8, 0x89abcdef);
+	ret |= WRITEL(ramptr + 12, 0xcdef0123);
+	ret |= WRITEL(ramptr + 16, 0x55555555);
+	ret |= WRITEL(ramptr + 20, 0x55555555);
+	ret |= WRITEL(ramptr + 24, 0xffffffff);
+	ret |= WRITEL(ramptr + 28, 0xffffffff);
+	ret |= READL(ramptr +  0, &t0);
+	ret |= READL(ramptr +  4, &t1);
+	ret |= READL(ramptr +  8, &t2);
+	ret |= READL(ramptr + 12, &t3);
+
+	if (ramtype <= 1) {
+
+		*chab = 0; *bw = 64;
+
+		if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
+			if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
+				*chab = 0; *bw = 64;
+				ret |= SETIREGAND(SISSR, 0x14, 0xfd);
+			}
+		}
+		if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
+			*chab = 1; *bw = 64;
+			ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
+
+			ret |= sisusb_triggersr16(sisusb, ramtype);
+			ret |= WRITEL(ramptr +  0, 0x89abcdef);
+			ret |= WRITEL(ramptr +  4, 0xcdef0123);
+			ret |= WRITEL(ramptr +  8, 0x55555555);
+			ret |= WRITEL(ramptr + 12, 0x55555555);
+			ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
+			ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
+			ret |= READL(ramptr +  4, &t1);
+
+			if (t1 != 0xcdef0123) {
+				*bw = 32;
+				ret |= SETIREGOR(SISSR, 0x15, 0x10);
+			}
+		}
+
+	} else {
+
+		*chab = 0; *bw = 64;	/* default: cha, bw = 64 */
+
+		done = 0;
+
+		if (t1 == 0x456789ab) {
+			if (t0 == 0x01234567) {
+				*chab = 0; *bw = 64;
+				done = 1;
+			}
+		} else {
+			if (t0 == 0x01234567) {
+				*chab = 0; *bw = 32;
+				ret |= SETIREG(SISSR, 0x14, 0x00);
+				done = 1;
+			}
+		}
+
+		if (!done) {
+			ret |= SETIREG(SISSR, 0x14, 0x03);
+			ret |= sisusb_triggersr16(sisusb, ramtype);
+
+			ret |= WRITEL(ramptr +  0, 0x01234567);
+			ret |= WRITEL(ramptr +  4, 0x456789ab);
+			ret |= WRITEL(ramptr +  8, 0x89abcdef);
+			ret |= WRITEL(ramptr + 12, 0xcdef0123);
+			ret |= WRITEL(ramptr + 16, 0x55555555);
+			ret |= WRITEL(ramptr + 20, 0x55555555);
+			ret |= WRITEL(ramptr + 24, 0xffffffff);
+			ret |= WRITEL(ramptr + 28, 0xffffffff);
+			ret |= READL(ramptr +  0, &t0);
+			ret |= READL(ramptr +  4, &t1);
+
+			if (t1 == 0x456789ab) {
+				if (t0 == 0x01234567) {
+					*chab = 1; *bw = 64;
+					return ret;
+				} /* else error */
+			} else {
+				if (t0 == 0x01234567) {
+					*chab = 1; *bw = 32;
+					ret |= SETIREG(SISSR, 0x14, 0x01);
+				} /* else error */
+			}
+		}
+	}
+	return ret;
+}
+
+static int
+sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
+{
+	int ret = 0;
+	u32 ramptr = SISUSB_PCI_MEMBASE;
+	u8 tmp1, tmp2, i, j;
+
+	ret |= WRITEB(ramptr, 0xaa);
+	ret |= WRITEB(ramptr + 16, 0x55);
+	ret |= READB(ramptr, &tmp1);
+	ret |= READB(ramptr + 16, &tmp2);
+	if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
+		for (i = 0, j = 16; i < 2; i++, j += 16) {
+			ret |= GETIREG(SISSR, 0x21, &tmp1);
+			ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
+			ret |= SETIREGOR(SISSR, 0x3c, 0x01);  /* not on 330 */
+			ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
+			ret |= SETIREG(SISSR, 0x21, tmp1);
+			ret |= WRITEB(ramptr + 16 + j, j);
+			ret |= READB(ramptr + 16 + j, &tmp1);
+			if (tmp1 == j) {
+				ret |= WRITEB(ramptr + j, j);
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+static int
+sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
+			u8 rankno, u8 chab, const u8 dramtype[][5],
+			int bw)
+{
+	int ret = 0, ranksize;
+	u8 tmp;
+
+	*iret = 0;
+
+	if ((rankno == 2) && (dramtype[index][0] == 2))
+		return ret;
+
+	ranksize = dramtype[index][3] / 2 * bw / 32;
+
+	if ((ranksize * rankno) > 128)
+		return ret;
+
+	tmp = 0;
+	while ((ranksize >>= 1) > 0) tmp += 0x10;
+	tmp |= ((rankno - 1) << 2);
+	tmp |= ((bw / 64) & 0x02);
+	tmp |= (chab & 0x01);
+
+	ret = SETIREG(SISSR, 0x14, tmp);
+	ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
+
+	*iret = 1;
+
+	return ret;
+}
+
+static int
+sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
+{
+	int ret = 0, i;
+	u32 j, tmp;
+
+	*iret = 0;
+
+	for (i = 0, j = 0; i < testn; i++) {
+		ret |= WRITEL(sisusb->vrambase + j, j);
+		j += inc;
+	}
+
+	for (i = 0, j = 0; i < testn; i++) {
+		ret |= READL(sisusb->vrambase + j, &tmp);
+		if (tmp != j) return ret;
+		j += inc;
+	}
+
+	*iret = 1;
+	return ret;
+}
+
+static int
+sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
+					int idx, int bw, const u8 rtype[][5])
+{
+	int ret = 0, i, i2ret;
+	u32 inc;
+
+	*iret = 0;
+
+	for (i = rankno; i >= 1; i--) {
+		inc = 1 << (rtype[idx][2] +
+			    rtype[idx][1] +
+			    rtype[idx][0] +
+			    bw / 64 + i);
+		ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
+		if (!i2ret)
+			return ret;
+	}
+
+	inc = 1 << (rtype[idx][2] + bw / 64 + 2);
+	ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
+	if (!i2ret)
+		return ret;
+
+	inc = 1 << (10 + bw / 64);
+	ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
+	if (!i2ret)
+		return ret;
+
+	*iret = 1;
+	return ret;
+}
+
+static int
+sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
+								int chab)
+{
+	int ret = 0, i2ret = 0, i, j;
+	static const u8 sdramtype[13][5] = {
+		{ 2, 12, 9, 64, 0x35 },
+		{ 1, 13, 9, 64, 0x44 },
+		{ 2, 12, 8, 32, 0x31 },
+		{ 2, 11, 9, 32, 0x25 },
+		{ 1, 12, 9, 32, 0x34 },
+		{ 1, 13, 8, 32, 0x40 },
+		{ 2, 11, 8, 16, 0x21 },
+		{ 1, 12, 8, 16, 0x30 },
+		{ 1, 11, 9, 16, 0x24 },
+		{ 1, 11, 8,  8, 0x20 },
+		{ 2,  9, 8,  4, 0x01 },
+		{ 1, 10, 8,  4, 0x10 },
+		{ 1,  9, 8,  2, 0x00 }
+	};
+
+	*iret = 1; /* error */
+
+	for (i = 0; i < 13; i++) {
+		ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
+		for (j = 2; j > 0; j--) {
+			ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
+						chab, sdramtype, bw);
+			if (!i2ret)
+				continue;
+
+			ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
+						bw, sdramtype);
+			if (i2ret) {
+				*iret = 0;	/* ram size found */
+				return ret;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int
+sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
+{
+	int ret = 0;
+	u32 address;
+	int i, length, modex, modey, bpp;
+
+	modex = 640; modey = 480; bpp = 2;
+
+	address = sisusb->vrambase;	/* Clear video ram */
+
+	if (clrall)
+		length = sisusb->vramsize;
+	else
+		length = modex * bpp * modey;
+
+	ret = sisusb_clear_vram(sisusb, address, length);
+
+	if (!ret && drwfr) {
+		for (i = 0; i < modex; i++) {
+			address = sisusb->vrambase + (i * bpp);
+			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+							address, 0xf100);
+			address += (modex * (modey-1) * bpp);
+			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+							address, 0xf100);
+		}
+		for (i = 0; i < modey; i++) {
+			address = sisusb->vrambase + ((i * modex) * bpp);
+			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+							address, 0xf100);
+			address += ((modex - 1) * bpp);
+			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
+							address, 0xf100);
+		}
+	}
+
+	return ret;
+}
+
+static int
+sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
+{
+	int ret = 0, i, j, modex, modey, bpp, du;
+	u8 sr31, cr63, tmp8;
+	static const char attrdata[] = {
+		0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+		0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+		0x01,0x00,0x00,0x00
+	};
+	static const char crtcrdata[] = {
+		0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+		0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+		0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+		0xff
+	};
+	static const char grcdata[] = {
+		0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+		0xff
+	};
+	static const char crtcdata[] = {
+		0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
+		0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
+		0x00
+	};
+
+	modex = 640; modey = 480; bpp = 2;
+
+	GETIREG(SISSR, 0x31, &sr31);
+	GETIREG(SISCR, 0x63, &cr63);
+	SETIREGOR(SISSR, 0x01, 0x20);
+	SETIREG(SISCR, 0x63, cr63 & 0xbf);
+	SETIREGOR(SISCR, 0x17, 0x80);
+	SETIREGOR(SISSR, 0x1f, 0x04);
+	SETIREGAND(SISSR, 0x07, 0xfb);
+	SETIREG(SISSR, 0x00, 0x03);	/* seq */
+	SETIREG(SISSR, 0x01, 0x21);
+	SETIREG(SISSR, 0x02, 0x0f);
+	SETIREG(SISSR, 0x03, 0x00);
+	SETIREG(SISSR, 0x04, 0x0e);
+	SETREG(SISMISCW, 0x23);		/* misc */
+	for (i = 0; i <= 0x18; i++) {	/* crtc */
+		SETIREG(SISCR, i, crtcrdata[i]);
+	}
+	for (i = 0; i <= 0x13; i++) {	/* att */
+		GETREG(SISINPSTAT, &tmp8);
+		SETREG(SISAR, i);
+		SETREG(SISAR, attrdata[i]);
+	}
+	GETREG(SISINPSTAT, &tmp8);
+	SETREG(SISAR, 0x14);
+	SETREG(SISAR, 0x00);
+	GETREG(SISINPSTAT, &tmp8);
+	SETREG(SISAR, 0x20);
+	GETREG(SISINPSTAT, &tmp8);
+	for (i = 0; i <= 0x08; i++) {	/* grc */
+		SETIREG(SISGR, i, grcdata[i]);
+	}
+	SETIREGAND(SISGR, 0x05, 0xbf);
+	for (i = 0x0A; i <= 0x0E; i++) {	/* clr ext */
+		SETIREG(SISSR, i, 0x00);
+	}
+	SETIREGAND(SISSR, 0x37, 0xfe);
+	SETREG(SISMISCW, 0xef);		/* sync */
+	SETIREG(SISCR, 0x11, 0x00);	/* crtc */
+	for (j = 0x00, i = 0; i <= 7; i++, j++) {
+		SETIREG(SISCR, j, crtcdata[i]);
+	}
+	for (j = 0x10; i <= 10; i++, j++) {
+		SETIREG(SISCR, j, crtcdata[i]);
+	}
+	for (j = 0x15; i <= 12; i++, j++) {
+		SETIREG(SISCR, j, crtcdata[i]);
+	}
+	for (j = 0x0A; i <= 15; i++, j++) {
+		SETIREG(SISSR, j, crtcdata[i]);
+	}
+	SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
+	SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
+	SETIREG(SISCR, 0x14, 0x4f);
+	du = (modex / 16) * (bpp * 2);	/* offset/pitch */
+	if (modex % 16) du += bpp;
+	SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
+	SETIREG(SISCR, 0x13, (du & 0xff));
+	du <<= 5;
+	tmp8 = du >> 8;
+	if (du & 0xff) tmp8++;
+	SETIREG(SISSR, 0x10, tmp8);
+	SETIREG(SISSR, 0x31, 0x00);	/* VCLK */
+	SETIREG(SISSR, 0x2b, 0x1b);
+	SETIREG(SISSR, 0x2c, 0xe1);
+	SETIREG(SISSR, 0x2d, 0x01);
+	SETIREGAND(SISSR, 0x3d, 0xfe);	/* FIFO */
+	SETIREG(SISSR, 0x08, 0xae);
+	SETIREGAND(SISSR, 0x09, 0xf0);
+	SETIREG(SISSR, 0x08, 0x34);
+	SETIREGOR(SISSR, 0x3d, 0x01);
+	SETIREGAND(SISSR, 0x1f, 0x3f);	/* mode regs */
+	SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
+	SETIREG(SISCR, 0x19, 0x00);
+	SETIREGAND(SISCR, 0x1a, 0xfc);
+	SETIREGAND(SISSR, 0x0f, 0xb7);
+	SETIREGAND(SISSR, 0x31, 0xfb);
+	SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
+	SETIREGAND(SISSR, 0x32, 0xf3);
+	SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
+	SETIREG(SISCR, 0x52, 0x6c);
+
+	SETIREG(SISCR, 0x0d, 0x00);	/* adjust frame */
+	SETIREG(SISCR, 0x0c, 0x00);
+	SETIREG(SISSR, 0x0d, 0x00);
+	SETIREGAND(SISSR, 0x37, 0xfe);
+
+	SETIREG(SISCR, 0x32, 0x20);
+	SETIREGAND(SISSR, 0x01, 0xdf);	/* enable display */
+	SETIREG(SISCR, 0x63, (cr63 & 0xbf));
+	SETIREG(SISSR, 0x31, (sr31 & 0xfb));
+
+	if (touchengines) {
+		SETIREG(SISSR, 0x20, 0xa1);	/* enable engines */
+		SETIREGOR(SISSR, 0x1e, 0x5a);
+
+		SETIREG(SISSR, 0x26, 0x01);	/* disable cmdqueue */
+		SETIREG(SISSR, 0x27, 0x1f);
+		SETIREG(SISSR, 0x26, 0x00);
+	}
+
+	SETIREG(SISCR, 0x34, 0x44);	/* we just set std mode #44 */
+
+	return ret;
+}
+
+static int
+sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
+{
+	int ret = 0, i, j, bw, chab, iret, retry = 3;
+	u8 tmp8, ramtype;
+	u32 tmp32;
+	static const char mclktable[] = {
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143
+	};
+	static const char eclktable[] = {
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143,
+		0x3b, 0x22, 0x01, 143
+	};
+	static const char ramtypetable1[] = {
+		0x00, 0x04, 0x60, 0x60,
+		0x0f, 0x0f, 0x1f, 0x1f,
+		0xba, 0xba, 0xba, 0xba,
+		0xa9, 0xa9, 0xac, 0xac,
+		0xa0, 0xa0, 0xa0, 0xa8,
+		0x00, 0x00, 0x02, 0x02,
+		0x30, 0x30, 0x40, 0x40
+	};
+	static const char ramtypetable2[] = {
+		0x77, 0x77, 0x44, 0x44,
+		0x77, 0x77, 0x44, 0x44,
+		0x00, 0x00, 0x00, 0x00,
+		0x5b, 0x5b, 0xab, 0xab,
+		0x00, 0x00, 0xf0, 0xf8
+	};
+
+	while (retry--) {
+
+		/* Enable VGA */
+		ret = GETREG(SISVGAEN, &tmp8);
+		ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
+
+		/* Enable GPU access to VRAM */
+		ret |= GETREG(SISMISCR, &tmp8);
+		ret |= SETREG(SISMISCW, (tmp8 | 0x01));
+
+		if (ret) continue;
+
+		/* Reset registers */
+		ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
+		ret |= SETIREG(SISSR, 0x05, 0x86);
+		ret |= SETIREGOR(SISSR, 0x20, 0x01);
+
+		ret |= SETREG(SISMISCW, 0x67);
+
+		for (i = 0x06; i <= 0x1f; i++) {
+			ret |= SETIREG(SISSR, i, 0x00);
+		}
+		for (i = 0x21; i <= 0x27; i++) {
+			ret |= SETIREG(SISSR, i, 0x00);
+		}
+		for (i = 0x31; i <= 0x3d; i++) {
+			ret |= SETIREG(SISSR, i, 0x00);
+		}
+		for (i = 0x12; i <= 0x1b; i++) {
+			ret |= SETIREG(SISSR, i, 0x00);
+		}
+		for (i = 0x79; i <= 0x7c; i++) {
+			ret |= SETIREG(SISCR, i, 0x00);
+		}
+
+		if (ret) continue;
+
+		ret |= SETIREG(SISCR, 0x63, 0x80);
+
+		ret |= GETIREG(SISSR, 0x3a, &ramtype);
+		ramtype &= 0x03;
+
+		ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
+		ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
+		ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
+
+		ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
+		ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
+		ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
+
+		ret |= SETIREG(SISSR, 0x07, 0x18);
+		ret |= SETIREG(SISSR, 0x11, 0x0f);
+
+		if (ret) continue;
+
+		for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
+			ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
+		}
+		for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
+			ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
+		}
+
+		ret |= SETIREG(SISCR, 0x49, 0xaa);
+
+		ret |= SETIREG(SISSR, 0x1f, 0x00);
+		ret |= SETIREG(SISSR, 0x20, 0xa0);
+		ret |= SETIREG(SISSR, 0x23, 0xf6);
+		ret |= SETIREG(SISSR, 0x24, 0x0d);
+		ret |= SETIREG(SISSR, 0x25, 0x33);
+
+		ret |= SETIREG(SISSR, 0x11, 0x0f);
+
+		ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
+
+		ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
+
+		if (ret) continue;
+
+		ret |= SETIREG(SISPART1, 0x00, 0x00);
+
+		ret |= GETIREG(SISSR, 0x13, &tmp8);
+		tmp8 >>= 4;
+
+		ret |= SETIREG(SISPART1, 0x02, 0x00);
+		ret |= SETIREG(SISPART1, 0x2e, 0x08);
+
+		ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
+		tmp32 &= 0x00f00000;
+		tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
+		ret |= SETIREG(SISSR, 0x25, tmp8);
+		tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
+		ret |= SETIREG(SISCR, 0x49, tmp8);
+
+		ret |= SETIREG(SISSR, 0x27, 0x1f);
+		ret |= SETIREG(SISSR, 0x31, 0x00);
+		ret |= SETIREG(SISSR, 0x32, 0x11);
+		ret |= SETIREG(SISSR, 0x33, 0x00);
+
+		if (ret) continue;
+
+		ret |= SETIREG(SISCR, 0x83, 0x00);
+
+		ret |= sisusb_set_default_mode(sisusb, 0);
+
+		ret |= SETIREGAND(SISSR, 0x21, 0xdf);
+		ret |= SETIREGOR(SISSR, 0x01, 0x20);
+		ret |= SETIREGOR(SISSR, 0x16, 0x0f);
+
+		ret |= sisusb_triggersr16(sisusb, ramtype);
+
+		/* Disable refresh */
+		ret |= SETIREGAND(SISSR, 0x17, 0xf8);
+		ret |= SETIREGOR(SISSR, 0x19, 0x03);
+
+		ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
+		ret |= sisusb_verify_mclk(sisusb);
+
+		if (ramtype <= 1) {
+			ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
+			if (iret) {
+				dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
+				ret |= SETIREG(SISSR,0x14,0x31);
+				/* TODO */
+			}
+		} else {
+			dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
+			ret |= SETIREG(SISSR,0x14,0x31);
+			/* *** TODO *** */
+		}
+
+		/* Enable refresh */
+		ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
+		ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
+		ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
+
+		ret |= SETIREGOR(SISSR, 0x21, 0x20);
+
+		ret |= SETIREG(SISSR, 0x22, 0xfb);
+		ret |= SETIREG(SISSR, 0x21, 0xa5);
+
+		if (ret == 0)
+			break;
+	}
+
+	return ret;
+}
+
+#undef SETREG
+#undef GETREG
+#undef SETIREG
+#undef GETIREG
+#undef SETIREGOR
+#undef SETIREGAND
+#undef SETIREGANDOR
+#undef READL
+#undef WRITEL
+
+static void
+sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
+{
+	u8 tmp8, tmp82, ramtype;
+	int bw = 0;
+	char *ramtypetext1 = NULL;
+	static const char ram_datarate[4] = {'S', 'S', 'D', 'D'};
+	static const char ram_dynamictype[4] = {'D', 'G', 'D', 'G'};
+	static const int busSDR[4]  = {64, 64, 128, 128};
+	static const int busDDR[4]  = {32, 32,  64,  64};
+	static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
+
+	sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
+	sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
+	sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
+	sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
+	ramtype &= 0x03;
+	switch ((tmp8 >> 2) & 0x03) {
+	case 0: ramtypetext1 = "1 ch/1 r";
+		if (tmp82 & 0x10) {
+			bw = 32;
+		} else {
+			bw = busSDR[(tmp8 & 0x03)];
+		}
+		break;
+	case 1: ramtypetext1 = "1 ch/2 r";
+		sisusb->vramsize <<= 1;
+		bw = busSDR[(tmp8 & 0x03)];
+		break;
+	case 2: ramtypetext1 = "asymmeric";
+		sisusb->vramsize += sisusb->vramsize/2;
+		bw = busDDRA[(tmp8 & 0x03)];
+		break;
+	case 3: ramtypetext1 = "2 channel";
+		sisusb->vramsize <<= 1;
+		bw = busDDR[(tmp8 & 0x03)];
+		break;
+	}
+
+
+	dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %cDR S%cRAM, bus width %d\n",
+		 sisusb->vramsize >> 20, ramtypetext1,
+		 ram_datarate[ramtype], ram_dynamictype[ramtype], bw);
+}
+
+static int
+sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
+{
+	struct sisusb_packet packet;
+	int ret;
+	u32 tmp32;
+
+	/* Do some magic */
+	packet.header  = 0x001f;
+	packet.address = 0x00000324;
+	packet.data    = 0x00000004;
+	ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	packet.header  = 0x001f;
+	packet.address = 0x00000364;
+	packet.data    = 0x00000004;
+	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	packet.header  = 0x001f;
+	packet.address = 0x00000384;
+	packet.data    = 0x00000004;
+	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	packet.header  = 0x001f;
+	packet.address = 0x00000100;
+	packet.data    = 0x00000700;
+	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	packet.header  = 0x000f;
+	packet.address = 0x00000004;
+	ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
+	packet.data |= 0x17;
+	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+
+	/* Init BAR 0 (VRAM) */
+	ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+	ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
+	ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+	tmp32 &= 0x0f;
+	tmp32 |= SISUSB_PCI_MEMBASE;
+	ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
+
+	/* Init BAR 1 (MMIO) */
+	ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+	ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
+	ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+	tmp32 &= 0x0f;
+	tmp32 |= SISUSB_PCI_MMIOBASE;
+	ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
+
+	/* Init BAR 2 (i/o ports) */
+	ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+	ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
+	ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+	tmp32 &= 0x0f;
+	tmp32 |= SISUSB_PCI_IOPORTBASE;
+	ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
+
+	/* Enable memory and i/o access */
+	ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
+	tmp32 |= 0x3;
+	ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
+
+	if (ret == 0) {
+		/* Some further magic */
+		packet.header  = 0x001f;
+		packet.address = 0x00000050;
+		packet.data    = 0x000000ff;
+		ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
+	}
+
+	return ret;
+}
+
+/* Initialize the graphics device (return 0 on success)
+ * This initializes the net2280 as well as the PCI registers
+ * of the graphics board.
+ */
+
+static int
+sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
+{
+	int ret = 0, test = 0;
+	u32 tmp32;
+
+	if (sisusb->devinit == 1) {
+		/* Read PCI BARs and see if they have been set up */
+		ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
+		if (ret) return ret;
+		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
+
+		ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
+		if (ret) return ret;
+		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
+
+		ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
+		if (ret) return ret;
+		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
+	}
+
+	/* No? So reset the device */
+	if ((sisusb->devinit == 0) || (test != 3)) {
+
+		ret |= sisusb_do_init_gfxdevice(sisusb);
+
+		if (ret == 0)
+			sisusb->devinit = 1;
+
+	}
+
+	if (sisusb->devinit) {
+		/* Initialize the graphics core */
+		if (sisusb_init_gfxcore(sisusb) == 0) {
+			sisusb->gfxinit = 1;
+			sisusb_get_ramconfig(sisusb);
+			ret |= sisusb_set_default_mode(sisusb, 1);
+			ret |= sisusb_setup_screen(sisusb, 1, initscreen);
+		}
+	}
+
+	return ret;
+}
+
+
+#ifdef INCL_SISUSB_CON
+
+/* Set up default text mode:
+   - Set text mode (0x03)
+   - Upload default font
+   - Upload user font (if available)
+*/
+
+int
+sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
+{
+	int ret = 0, slot = sisusb->font_slot, i;
+	const struct font_desc *myfont;
+	u8 *tempbuf;
+	u16 *tempbufb;
+	size_t written;
+	static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
+	static const char bootlogo[] = "(o_ //\\ V_/_";
+
+	/* sisusb->lock is down */
+
+	if (!sisusb->SiS_Pr)
+		return 1;
+
+	sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
+	sisusb->SiS_Pr->sisusb = (void *)sisusb;
+
+	/* Set mode 0x03 */
+	SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
+
+	myfont = find_font("VGA8x16");
+	if (!myfont)
+		return 1;
+
+	tempbuf = vmalloc(8192);
+	if (!tempbuf)
+		return 1;
+
+	for (i = 0; i < 256; i++)
+		memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
+
+	/* Upload default font */
+	ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
+
+	vfree(tempbuf);
+
+	/* Upload user font (and reset current slot) */
+	if (sisusb->font_backup) {
+		ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
+				8192, sisusb->font_backup_512, 1, NULL,
+				sisusb->font_backup_height, 0);
+		if (slot != 2)
+			sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
+					NULL, 16, 0);
+	}
+
+	if (init && !sisusb->scrbuf) {
+
+		tempbuf = vmalloc(8192);
+		if (tempbuf) {
+
+			i = 4096;
+			tempbufb = (u16 *)tempbuf;
+			while (i--)
+				*(tempbufb++) = 0x0720;
+
+			i = 0;
+			tempbufb = (u16 *)tempbuf;
+			while (bootlogo[i]) {
+				*(tempbufb++) = 0x0700 | bootlogo[i++];
+				if (!(i % 4))
+					tempbufb += 76;
+			}
+
+			i = 0;
+			tempbufb = (u16 *)tempbuf + 6;
+			while (bootstring[i])
+				*(tempbufb++) = 0x0700 | bootstring[i++];
+
+			ret |= sisusb_copy_memory(sisusb, tempbuf,
+				sisusb->vrambase, 8192, &written);
+
+			vfree(tempbuf);
+
+		}
+
+	} else if (sisusb->scrbuf) {
+
+		ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
+				sisusb->vrambase, sisusb->scrbuf_size, &written);
+
+	}
+
+	if (sisusb->sisusb_cursor_size_from >= 0 &&
+	    sisusb->sisusb_cursor_size_to >= 0) {
+		sisusb_setidxreg(sisusb, SISCR, 0x0a,
+				sisusb->sisusb_cursor_size_from);
+		sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
+				sisusb->sisusb_cursor_size_to);
+	} else {
+		sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
+		sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
+		sisusb->sisusb_cursor_size_to = -1;
+	}
+
+	slot = sisusb->sisusb_cursor_loc;
+	if(slot < 0) slot = 0;
+
+	sisusb->sisusb_cursor_loc = -1;
+	sisusb->bad_cursor_pos = 1;
+
+	sisusb_set_cursor(sisusb, slot);
+
+	sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
+	sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
+
+	sisusb->textmodedestroyed = 0;
+
+	/* sisusb->lock is down */
+
+	return ret;
+}
+
+#endif
+
+/* fops */
+
+static int
+sisusb_open(struct inode *inode, struct file *file)
+{
+	struct sisusb_usb_data *sisusb;
+	struct usb_interface *interface;
+	int subminor = iminor(inode);
+
+	interface = usb_find_interface(&sisusb_driver, subminor);
+	if (!interface) {
+		return -ENODEV;
+	}
+
+	sisusb = usb_get_intfdata(interface);
+	if (!sisusb) {
+		return -ENODEV;
+	}
+
+	mutex_lock(&sisusb->lock);
+
+	if (!sisusb->present || !sisusb->ready) {
+		mutex_unlock(&sisusb->lock);
+		return -ENODEV;
+	}
+
+	if (sisusb->isopen) {
+		mutex_unlock(&sisusb->lock);
+		return -EBUSY;
+	}
+
+	if (!sisusb->devinit) {
+		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH ||
+		    sisusb->sisusb_dev->speed == USB_SPEED_SUPER) {
+			if (sisusb_init_gfxdevice(sisusb, 0)) {
+				mutex_unlock(&sisusb->lock);
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
+				return -EIO;
+			}
+		} else {
+			mutex_unlock(&sisusb->lock);
+			dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
+			return -EIO;
+		}
+	}
+
+	/* Increment usage count for our sisusb */
+	kref_get(&sisusb->kref);
+
+	sisusb->isopen = 1;
+
+	file->private_data = sisusb;
+
+	mutex_unlock(&sisusb->lock);
+
+	return 0;
+}
+
+void
+sisusb_delete(struct kref *kref)
+{
+	struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
+
+	if (!sisusb)
+		return;
+
+	usb_put_dev(sisusb->sisusb_dev);
+
+	sisusb->sisusb_dev = NULL;
+	sisusb_free_buffers(sisusb);
+	sisusb_free_urbs(sisusb);
+#ifdef INCL_SISUSB_CON
+	kfree(sisusb->SiS_Pr);
+#endif
+	kfree(sisusb);
+}
+
+static int
+sisusb_release(struct inode *inode, struct file *file)
+{
+	struct sisusb_usb_data *sisusb;
+
+	sisusb = file->private_data;
+	if (!sisusb)
+		return -ENODEV;
+
+	mutex_lock(&sisusb->lock);
+
+	if (sisusb->present) {
+		/* Wait for all URBs to finish if device still present */
+		if (!sisusb_wait_all_out_complete(sisusb))
+			sisusb_kill_all_busy(sisusb);
+	}
+
+	sisusb->isopen = 0;
+	file->private_data = NULL;
+
+	mutex_unlock(&sisusb->lock);
+
+	/* decrement the usage count on our device */
+	kref_put(&sisusb->kref, sisusb_delete);
+
+	return 0;
+}
+
+static ssize_t
+sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+	struct sisusb_usb_data *sisusb;
+	ssize_t bytes_read = 0;
+	int errno = 0;
+	u8 buf8;
+	u16 buf16;
+	u32 buf32, address;
+
+	sisusb = file->private_data;
+	if (!sisusb)
+		return -ENODEV;
+
+	mutex_lock(&sisusb->lock);
+
+	/* Sanity check */
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+		mutex_unlock(&sisusb->lock);
+		return -ENODEV;
+	}
+
+	if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
+	    (*ppos) <  SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_IOPORTBASE +
+			SISUSB_PCI_IOPORTBASE;
+
+		/* Read i/o ports
+		 * Byte, word and long(32) can be read. As this
+		 * emulates inX instructions, the data returned is
+		 * in machine-endianness.
+		 */
+		switch (count) {
+
+			case 1:
+				if (sisusb_read_memio_byte(sisusb,
+							SISUSB_TYPE_IO,
+							address, &buf8))
+					errno = -EIO;
+				else if (put_user(buf8, (u8 __user *)buffer))
+					errno = -EFAULT;
+				else
+					bytes_read = 1;
+
+				break;
+
+			case 2:
+				if (sisusb_read_memio_word(sisusb,
+							SISUSB_TYPE_IO,
+							address, &buf16))
+					errno = -EIO;
+				else if (put_user(buf16, (u16 __user *)buffer))
+					errno = -EFAULT;
+				else
+					bytes_read = 2;
+
+				break;
+
+			case 4:
+				if (sisusb_read_memio_long(sisusb,
+							SISUSB_TYPE_IO,
+							address, &buf32))
+					errno = -EIO;
+				else if (put_user(buf32, (u32 __user *)buffer))
+					errno = -EFAULT;
+				else
+					bytes_read = 4;
+
+				break;
+
+			default:
+				errno = -EIO;
+
+		}
+
+	} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
+		   (*ppos) <  SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_MEMBASE +
+			SISUSB_PCI_MEMBASE;
+
+		/* Read video ram
+		 * Remember: Data delivered is never endian-corrected
+		 */
+		errno = sisusb_read_mem_bulk(sisusb, address,
+					NULL, count, buffer, &bytes_read);
+
+		if (bytes_read)
+			errno = bytes_read;
+
+	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
+		    (*ppos) <  SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_MMIOBASE +
+			SISUSB_PCI_MMIOBASE;
+
+		/* Read MMIO
+		 * Remember: Data delivered is never endian-corrected
+		 */
+		errno = sisusb_read_mem_bulk(sisusb, address,
+					NULL, count, buffer, &bytes_read);
+
+		if (bytes_read)
+			errno = bytes_read;
+
+	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
+		    (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
+
+		if (count != 4) {
+			mutex_unlock(&sisusb->lock);
+			return -EINVAL;
+		}
+
+		address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
+
+		/* Read PCI config register
+		 * Return value delivered in machine endianness.
+		 */
+		if (sisusb_read_pci_config(sisusb, address, &buf32))
+			errno = -EIO;
+		else if (put_user(buf32, (u32 __user *)buffer))
+			errno = -EFAULT;
+		else
+			bytes_read = 4;
+
+	} else {
+
+		errno = -EBADFD;
+
+	}
+
+	(*ppos) += bytes_read;
+
+	mutex_unlock(&sisusb->lock);
+
+	return errno ? errno : bytes_read;
+}
+
+static ssize_t
+sisusb_write(struct file *file, const char __user *buffer, size_t count,
+								loff_t *ppos)
+{
+	struct sisusb_usb_data *sisusb;
+	int errno = 0;
+	ssize_t bytes_written = 0;
+	u8 buf8;
+	u16 buf16;
+	u32 buf32, address;
+
+	sisusb = file->private_data;
+	if (!sisusb)
+		return -ENODEV;
+
+	mutex_lock(&sisusb->lock);
+
+	/* Sanity check */
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+		mutex_unlock(&sisusb->lock);
+		return -ENODEV;
+	}
+
+	if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
+	    (*ppos) <  SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_IOPORTBASE +
+			SISUSB_PCI_IOPORTBASE;
+
+		/* Write i/o ports
+		 * Byte, word and long(32) can be written. As this
+		 * emulates outX instructions, the data is expected
+		 * in machine-endianness.
+		 */
+		switch (count) {
+
+			case 1:
+				if (get_user(buf8, (u8 __user *)buffer))
+					errno = -EFAULT;
+				else if (sisusb_write_memio_byte(sisusb,
+							SISUSB_TYPE_IO,
+							address, buf8))
+					errno = -EIO;
+				else
+					bytes_written = 1;
+
+				break;
+
+			case 2:
+				if (get_user(buf16, (u16 __user *)buffer))
+					errno = -EFAULT;
+				else if (sisusb_write_memio_word(sisusb,
+							SISUSB_TYPE_IO,
+							address, buf16))
+					errno = -EIO;
+				else
+					bytes_written = 2;
+
+				break;
+
+			case 4:
+				if (get_user(buf32, (u32 __user *)buffer))
+					errno = -EFAULT;
+				else if (sisusb_write_memio_long(sisusb,
+							SISUSB_TYPE_IO,
+							address, buf32))
+					errno = -EIO;
+				else
+					bytes_written = 4;
+
+				break;
+
+			default:
+				errno = -EIO;
+		}
+
+	} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
+		   (*ppos) <  SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_MEMBASE +
+			SISUSB_PCI_MEMBASE;
+
+		/* Write video ram.
+		 * Buffer is copied 1:1, therefore, on big-endian
+		 * machines, the data must be swapped by userland
+		 * in advance (if applicable; no swapping in 8bpp
+		 * mode or if YUV data is being transferred).
+		 */
+		errno = sisusb_write_mem_bulk(sisusb, address, NULL,
+					count, buffer, 0, &bytes_written);
+
+		if (bytes_written)
+			errno = bytes_written;
+
+	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
+		    (*ppos) <  SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
+
+		address = (*ppos) -
+			SISUSB_PCI_PSEUDO_MMIOBASE +
+			SISUSB_PCI_MMIOBASE;
+
+		/* Write MMIO.
+		 * Buffer is copied 1:1, therefore, on big-endian
+		 * machines, the data must be swapped by userland
+		 * in advance.
+		 */
+		errno = sisusb_write_mem_bulk(sisusb, address, NULL,
+					count, buffer, 0, &bytes_written);
+
+		if (bytes_written)
+			errno = bytes_written;
+
+	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
+		    (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
+
+		if (count != 4) {
+			mutex_unlock(&sisusb->lock);
+			return -EINVAL;
+		}
+
+		address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
+
+		/* Write PCI config register.
+		 * Given value expected in machine endianness.
+		 */
+		if (get_user(buf32, (u32 __user *)buffer))
+			errno = -EFAULT;
+		else if (sisusb_write_pci_config(sisusb, address, buf32))
+			errno = -EIO;
+		else
+			bytes_written = 4;
+
+
+	} else {
+
+		/* Error */
+		errno = -EBADFD;
+
+	}
+
+	(*ppos) += bytes_written;
+
+	mutex_unlock(&sisusb->lock);
+
+	return errno ? errno : bytes_written;
+}
+
+static loff_t
+sisusb_lseek(struct file *file, loff_t offset, int orig)
+{
+	struct sisusb_usb_data *sisusb;
+	loff_t ret;
+
+	sisusb = file->private_data;
+	if (!sisusb)
+		return -ENODEV;
+
+	mutex_lock(&sisusb->lock);
+
+	/* Sanity check */
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+		mutex_unlock(&sisusb->lock);
+		return -ENODEV;
+	}
+
+	switch (orig) {
+		case 0:
+			file->f_pos = offset;
+			ret = file->f_pos;
+			/* never negative, no force_successful_syscall needed */
+			break;
+		case 1:
+			file->f_pos += offset;
+			ret = file->f_pos;
+			/* never negative, no force_successful_syscall needed */
+			break;
+		default:
+			/* seeking relative to "end of file" is not supported */
+			ret = -EINVAL;
+	}
+
+	mutex_unlock(&sisusb->lock);
+	return ret;
+}
+
+static int
+sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
+							unsigned long arg)
+{
+	int	retval, port, length;
+	u32	address;
+
+	/* All our commands require the device
+	 * to be initialized.
+	 */
+	if (!sisusb->devinit)
+		return -ENODEV;
+
+	port = y->data3 -
+		SISUSB_PCI_PSEUDO_IOPORTBASE +
+		SISUSB_PCI_IOPORTBASE;
+
+	switch (y->operation) {
+		case SUCMD_GET:
+			retval = sisusb_getidxreg(sisusb, port,
+							 y->data0, &y->data1);
+			if (!retval) {
+				if (copy_to_user((void __user *)arg, y,
+							sizeof(*y)))
+					retval = -EFAULT;
+			}
+			break;
+
+		case SUCMD_SET:
+			retval = sisusb_setidxreg(sisusb, port,
+						y->data0, y->data1);
+			break;
+
+		case SUCMD_SETOR:
+			retval = sisusb_setidxregor(sisusb, port,
+						y->data0, y->data1);
+			break;
+
+		case SUCMD_SETAND:
+			retval = sisusb_setidxregand(sisusb, port,
+						y->data0, y->data1);
+			break;
+
+		case SUCMD_SETANDOR:
+			retval = sisusb_setidxregandor(sisusb, port,
+						y->data0, y->data1, y->data2);
+			break;
+
+		case SUCMD_SETMASK:
+			retval = sisusb_setidxregmask(sisusb, port,
+						y->data0, y->data1, y->data2);
+			break;
+
+		case SUCMD_CLRSCR:
+			/* Gfx core must be initialized */
+			if (!sisusb->gfxinit)
+				return -ENODEV;
+
+			length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
+			address = y->data3 -
+				SISUSB_PCI_PSEUDO_MEMBASE +
+				SISUSB_PCI_MEMBASE;
+			retval = sisusb_clear_vram(sisusb, address, length);
+			break;
+
+		case SUCMD_HANDLETEXTMODE:
+			retval = 0;
+#ifdef INCL_SISUSB_CON
+			/* Gfx core must be initialized, SiS_Pr must exist */
+			if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+				return -ENODEV;
+
+			switch (y->data0) {
+			case 0:
+				retval = sisusb_reset_text_mode(sisusb, 0);
+				break;
+			case 1:
+				sisusb->textmodedestroyed = 1;
+				break;
+			}
+#endif
+			break;
+
+#ifdef INCL_SISUSB_CON
+		case SUCMD_SETMODE:
+			/* Gfx core must be initialized, SiS_Pr must exist */
+			if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+				return -ENODEV;
+
+			retval = 0;
+
+			sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
+			sisusb->SiS_Pr->sisusb = (void *)sisusb;
+
+			if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
+				retval = -EINVAL;
+
+			break;
+
+		case SUCMD_SETVESAMODE:
+			/* Gfx core must be initialized, SiS_Pr must exist */
+			if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+				return -ENODEV;
+
+			retval = 0;
+
+			sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
+			sisusb->SiS_Pr->sisusb = (void *)sisusb;
+
+			if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
+				retval = -EINVAL;
+
+			break;
+#endif
+
+		default:
+			retval = -EINVAL;
+	}
+
+	if (retval > 0)
+		retval = -EIO;
+
+	return retval;
+}
+
+static long
+sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct sisusb_usb_data *sisusb;
+	struct sisusb_info x;
+	struct sisusb_command y;
+	long retval = 0;
+	u32 __user *argp = (u32 __user *)arg;
+
+	sisusb = file->private_data;
+	if (!sisusb)
+		return -ENODEV;
+
+	mutex_lock(&sisusb->lock);
+
+	/* Sanity check */
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	switch (cmd) {
+
+		case SISUSB_GET_CONFIG_SIZE:
+
+			if (put_user(sizeof(x), argp))
+				retval = -EFAULT;
+
+			break;
+
+		case SISUSB_GET_CONFIG:
+
+			x.sisusb_id	    = SISUSB_ID;
+			x.sisusb_version    = SISUSB_VERSION;
+			x.sisusb_revision   = SISUSB_REVISION;
+			x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
+			x.sisusb_gfxinit    = sisusb->gfxinit;
+			x.sisusb_vrambase   = SISUSB_PCI_PSEUDO_MEMBASE;
+			x.sisusb_mmiobase   = SISUSB_PCI_PSEUDO_MMIOBASE;
+			x.sisusb_iobase     = SISUSB_PCI_PSEUDO_IOPORTBASE;
+			x.sisusb_pcibase    = SISUSB_PCI_PSEUDO_PCIBASE;
+			x.sisusb_vramsize   = sisusb->vramsize;
+			x.sisusb_minor	    = sisusb->minor;
+			x.sisusb_fbdevactive= 0;
+#ifdef INCL_SISUSB_CON
+			x.sisusb_conactive  = sisusb->haveconsole ? 1 : 0;
+#else
+			x.sisusb_conactive  = 0;
+#endif
+			memset(x.sisusb_reserved, 0, sizeof(x.sisusb_reserved));
+
+			if (copy_to_user((void __user *)arg, &x, sizeof(x)))
+				retval = -EFAULT;
+
+			break;
+
+		case SISUSB_COMMAND:
+
+			if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
+				retval = -EFAULT;
+			else
+				retval = sisusb_handle_command(sisusb, &y, arg);
+
+			break;
+
+		default:
+			retval = -ENOTTY;
+			break;
+	}
+
+err_out:
+	mutex_unlock(&sisusb->lock);
+	return retval;
+}
+
+#ifdef SISUSB_NEW_CONFIG_COMPAT
+static long
+sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+	long retval;
+
+	switch (cmd) {
+		case SISUSB_GET_CONFIG_SIZE:
+		case SISUSB_GET_CONFIG:
+		case SISUSB_COMMAND:
+			retval = sisusb_ioctl(f, cmd, arg);
+			return retval;
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+#endif
+
+static const struct file_operations usb_sisusb_fops = {
+	.owner =	THIS_MODULE,
+	.open =		sisusb_open,
+	.release =	sisusb_release,
+	.read =		sisusb_read,
+	.write =	sisusb_write,
+	.llseek =	sisusb_lseek,
+#ifdef SISUSB_NEW_CONFIG_COMPAT
+	.compat_ioctl = sisusb_compat_ioctl,
+#endif
+	.unlocked_ioctl = sisusb_ioctl
+};
+
+static struct usb_class_driver usb_sisusb_class = {
+	.name =		"sisusbvga%d",
+	.fops =		&usb_sisusb_fops,
+	.minor_base =	SISUSB_MINOR
+};
+
+static int sisusb_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct sisusb_usb_data *sisusb;
+	int retval = 0, i;
+
+	dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
+		dev->devnum);
+
+	/* Allocate memory for our private */
+	sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL);
+	if (!sisusb) {
+		dev_err(&dev->dev, "Failed to allocate memory for private data\n");
+		return -ENOMEM;
+	}
+	kref_init(&sisusb->kref);
+
+	mutex_init(&(sisusb->lock));
+
+	/* Register device */
+	retval = usb_register_dev(intf, &usb_sisusb_class);
+	if (retval) {
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
+			dev->devnum);
+		retval = -ENODEV;
+		goto error_1;
+	}
+
+	sisusb->sisusb_dev = dev;
+	sisusb->minor      = intf->minor;
+	sisusb->vrambase   = SISUSB_PCI_MEMBASE;
+	sisusb->mmiobase   = SISUSB_PCI_MMIOBASE;
+	sisusb->mmiosize   = SISUSB_PCI_MMIOSIZE;
+	sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
+	/* Everything else is zero */
+
+	/* Allocate buffers */
+	sisusb->ibufsize = SISUSB_IBUF_SIZE;
+	if (!(sisusb->ibuf = kmalloc(SISUSB_IBUF_SIZE, GFP_KERNEL))) {
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
+		retval = -ENOMEM;
+		goto error_2;
+	}
+
+	sisusb->numobufs = 0;
+	sisusb->obufsize = SISUSB_OBUF_SIZE;
+	for (i = 0; i < NUMOBUFS; i++) {
+		if (!(sisusb->obuf[i] = kmalloc(SISUSB_OBUF_SIZE, GFP_KERNEL))) {
+			if (i == 0) {
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
+				retval = -ENOMEM;
+				goto error_3;
+			}
+			break;
+		} else
+			sisusb->numobufs++;
+
+	}
+
+	/* Allocate URBs */
+	if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
+		retval = -ENOMEM;
+		goto error_3;
+	}
+	sisusb->completein = 1;
+
+	for (i = 0; i < sisusb->numobufs; i++) {
+		if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
+			dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
+			retval = -ENOMEM;
+			goto error_4;
+		}
+		sisusb->urbout_context[i].sisusb = (void *)sisusb;
+		sisusb->urbout_context[i].urbindex = i;
+		sisusb->urbstatus[i] = 0;
+	}
+
+	dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
+
+#ifdef INCL_SISUSB_CON
+	/* Allocate our SiS_Pr */
+	if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
+	}
+#endif
+
+	/* Do remaining init stuff */
+
+	init_waitqueue_head(&sisusb->wait_q);
+
+	usb_set_intfdata(intf, sisusb);
+
+	usb_get_dev(sisusb->sisusb_dev);
+
+	sisusb->present = 1;
+
+	if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) {
+		int initscreen = 1;
+#ifdef INCL_SISUSB_CON
+		if (sisusb_first_vc > 0 &&
+		    sisusb_last_vc > 0 &&
+		    sisusb_first_vc <= sisusb_last_vc &&
+		    sisusb_last_vc <= MAX_NR_CONSOLES)
+			initscreen = 0;
+#endif
+		if (sisusb_init_gfxdevice(sisusb, initscreen))
+			dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
+
+	} else
+		dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
+
+	sisusb->ready = 1;
+
+#ifdef SISUSBENDIANTEST
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
+	sisusb_testreadwrite(sisusb);
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
+#endif
+
+#ifdef INCL_SISUSB_CON
+	sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
+#endif
+
+	return 0;
+
+error_4:
+	sisusb_free_urbs(sisusb);
+error_3:
+	sisusb_free_buffers(sisusb);
+error_2:
+	usb_deregister_dev(intf, &usb_sisusb_class);
+error_1:
+	kfree(sisusb);
+	return retval;
+}
+
+static void sisusb_disconnect(struct usb_interface *intf)
+{
+	struct sisusb_usb_data *sisusb;
+
+	/* This should *not* happen */
+	sisusb = usb_get_intfdata(intf);
+	if (!sisusb)
+		return;
+
+#ifdef INCL_SISUSB_CON
+	sisusb_console_exit(sisusb);
+#endif
+
+	usb_deregister_dev(intf, &usb_sisusb_class);
+
+	mutex_lock(&sisusb->lock);
+
+	/* Wait for all URBs to complete and kill them in case (MUST do) */
+	if (!sisusb_wait_all_out_complete(sisusb))
+		sisusb_kill_all_busy(sisusb);
+
+	usb_set_intfdata(intf, NULL);
+
+	sisusb->present = 0;
+	sisusb->ready = 0;
+
+	mutex_unlock(&sisusb->lock);
+
+	/* decrement our usage count */
+	kref_put(&sisusb->kref, sisusb_delete);
+}
+
+static const struct usb_device_id sisusb_table[] = {
+	{ USB_DEVICE(0x0711, 0x0550) },
+	{ USB_DEVICE(0x0711, 0x0900) },
+	{ USB_DEVICE(0x0711, 0x0901) },
+	{ USB_DEVICE(0x0711, 0x0902) },
+	{ USB_DEVICE(0x0711, 0x0903) },
+	{ USB_DEVICE(0x0711, 0x0918) },
+	{ USB_DEVICE(0x0711, 0x0920) },
+	{ USB_DEVICE(0x0711, 0x0950) },
+	{ USB_DEVICE(0x0711, 0x5200) },
+	{ USB_DEVICE(0x182d, 0x021c) },
+	{ USB_DEVICE(0x182d, 0x0269) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE (usb, sisusb_table);
+
+static struct usb_driver sisusb_driver = {
+	.name =		"sisusb",
+	.probe =	sisusb_probe,
+	.disconnect =	sisusb_disconnect,
+	.id_table =	sisusb_table,
+};
+
+static int __init usb_sisusb_init(void)
+{
+
+#ifdef INCL_SISUSB_CON
+	sisusb_init_concode();
+#endif
+
+	return usb_register(&sisusb_driver);
+}
+
+static void __exit usb_sisusb_exit(void)
+{
+	usb_deregister(&sisusb_driver);
+}
+
+module_init(usb_sisusb_init);
+module_exit(usb_sisusb_exit);
+
+MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
+MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
new file mode 100644
index 0000000..55492a5
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -0,0 +1,311 @@
+/*
+ * sisusb - usb kernel driver for Net2280/SiS315 based USB2VGA dongles
+ *
+ * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _SISUSB_H_
+#define _SISUSB_H_
+
+#ifdef CONFIG_COMPAT
+#define SISUSB_NEW_CONFIG_COMPAT
+#endif
+
+#include <linux/mutex.h>
+
+/* For older kernels, support for text consoles is by default
+ * off. To enable text console support, change the following:
+ */
+/* #define CONFIG_USB_SISUSBVGA_CON */
+
+/* Version Information */
+
+#define SISUSB_VERSION		0
+#define SISUSB_REVISION		0
+#define SISUSB_PATCHLEVEL	8
+
+/* Include console and mode switching code? */
+
+#ifdef CONFIG_USB_SISUSBVGA_CON
+#define INCL_SISUSB_CON		1
+#endif
+
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include "sisusb_struct.h"
+
+/* USB related */
+
+#define SISUSB_MINOR		133	/* official */
+
+/* Size of the sisusb input/output buffers */
+#define SISUSB_IBUF_SIZE  0x01000
+#define SISUSB_OBUF_SIZE  0x10000	/* fixed */
+
+#define NUMOBUFS 8		/* max number of output buffers/output URBs */
+
+/* About endianness:
+ *
+ * 1) I/O ports, PCI config registers. The read/write()
+ *    calls emulate inX/outX. Hence, the data is
+ *    expected/delivered in machine endiannes by this
+ *    driver.
+ * 2) Video memory. The data is copied 1:1. There is
+ *    no swapping. Ever. This means for userland that
+ *    the data has to be prepared properly. (Hint:
+ *    think graphics data format, command queue,
+ *    hardware cursor.)
+ * 3) MMIO. Data is copied 1:1. MMIO must be swapped
+ *    properly by userland.
+ *
+ */
+
+#ifdef __BIG_ENDIAN
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)		\
+	do {						\
+		p->header  = cpu_to_le16(p->header);	\
+		p->address = cpu_to_le32(p->address);	\
+		p->data    = cpu_to_le32(p->data);	\
+	} while(0)
+#else
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)
+#endif
+
+struct sisusb_usb_data;
+
+struct sisusb_urb_context {	/* urb->context for outbound bulk URBs */
+	struct sisusb_usb_data *sisusb;
+	int urbindex;
+	int *actual_length;
+};
+
+struct sisusb_usb_data {
+	struct usb_device *sisusb_dev;
+	struct usb_interface *interface;
+	struct kref kref;
+	wait_queue_head_t wait_q;	/* for syncind and timeouts */
+	struct mutex lock;	/* general race avoidance */
+	unsigned int ifnum;	/* interface number of the USB device */
+	int minor;		/* minor (for logging clarity) */
+	int isopen;		/* !=0 if open */
+	int present;		/* !=0 if device is present on the bus */
+	int ready;		/* !=0 if device is ready for userland */
+	int numobufs;		/* number of obufs = number of out urbs */
+	char *obuf[NUMOBUFS], *ibuf;	/* transfer buffers */
+	int obufsize, ibufsize;
+	struct urb *sisurbout[NUMOBUFS];
+	struct urb *sisurbin;
+	unsigned char urbstatus[NUMOBUFS];
+	unsigned char completein;
+	struct sisusb_urb_context urbout_context[NUMOBUFS];
+	unsigned long flagb0;
+	unsigned long vrambase;	/* framebuffer base */
+	unsigned int vramsize;	/* framebuffer size (bytes) */
+	unsigned long mmiobase;
+	unsigned int mmiosize;
+	unsigned long ioportbase;
+	unsigned char devinit;	/* device initialized? */
+	unsigned char gfxinit;	/* graphics core initialized? */
+	unsigned short chipid, chipvendor;
+	unsigned short chiprevision;
+#ifdef INCL_SISUSB_CON
+	struct SiS_Private *SiS_Pr;
+	unsigned long scrbuf;
+	unsigned int scrbuf_size;
+	int haveconsole, con_first, con_last;
+	int havethisconsole[MAX_NR_CONSOLES];
+	int textmodedestroyed;
+	unsigned int sisusb_num_columns;	/* real number, not vt's idea */
+	int cur_start_addr, con_rolled_over;
+	int sisusb_cursor_loc, bad_cursor_pos;
+	int sisusb_cursor_size_from;
+	int sisusb_cursor_size_to;
+	int current_font_height, current_font_512;
+	int font_backup_size, font_backup_height, font_backup_512;
+	char *font_backup;
+	int font_slot;
+	struct vc_data *sisusb_display_fg;
+	int is_gfx;
+	int con_blanked;
+#endif
+};
+
+#define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref)
+
+/* USB transport related */
+
+/* urbstatus */
+#define SU_URB_BUSY   1
+#define SU_URB_ALLOC  2
+
+/* Endpoints */
+
+#define SISUSB_EP_GFX_IN	0x0e	/* gfx std packet out(0e)/in(8e) */
+#define SISUSB_EP_GFX_OUT	0x0e
+
+#define SISUSB_EP_GFX_BULK_OUT	0x01	/* gfx mem bulk out/in */
+#define SISUSB_EP_GFX_BULK_IN	0x02	/* ? 2 is "OUT" ? */
+
+#define SISUSB_EP_GFX_LBULK_OUT	0x03	/* gfx large mem bulk out */
+
+#define SISUSB_EP_UNKNOWN_04	0x04	/* ? 4 is "OUT" ? - unused */
+
+#define SISUSB_EP_BRIDGE_IN	0x0d	/* Net2280 out(0d)/in(8d) */
+#define SISUSB_EP_BRIDGE_OUT	0x0d
+
+#define SISUSB_TYPE_MEM		0
+#define SISUSB_TYPE_IO		1
+
+struct sisusb_packet {
+	unsigned short header;
+	u32 address;
+	u32 data;
+} __attribute__ ((__packed__));
+
+#define CLEARPACKET(packet) memset(packet, 0, 10)
+
+/* PCI bridge related */
+
+#define SISUSB_PCI_MEMBASE	0xd0000000
+#define SISUSB_PCI_MMIOBASE	0xe4000000
+#define SISUSB_PCI_IOPORTBASE	0x0000d000
+
+#define SISUSB_PCI_PSEUDO_MEMBASE	0x10000000
+#define SISUSB_PCI_PSEUDO_MMIOBASE	0x20000000
+#define SISUSB_PCI_PSEUDO_IOPORTBASE	0x0000d000
+#define SISUSB_PCI_PSEUDO_PCIBASE	0x00010000
+
+#define SISUSB_PCI_MMIOSIZE	(128*1024)
+#define SISUSB_PCI_PCONFSIZE	0x5c
+
+/* graphics core related */
+
+#define AROFFSET	0x40
+#define ARROFFSET	0x41
+#define GROFFSET	0x4e
+#define SROFFSET	0x44
+#define CROFFSET	0x54
+#define MISCROFFSET	0x4c
+#define MISCWOFFSET	0x42
+#define INPUTSTATOFFSET 0x5A
+#define PART1OFFSET	0x04
+#define PART2OFFSET	0x10
+#define PART3OFFSET	0x12
+#define PART4OFFSET	0x14
+#define PART5OFFSET	0x16
+#define CAPTUREOFFSET	0x00
+#define VIDEOOFFSET	0x02
+#define COLREGOFFSET	0x48
+#define PELMASKOFFSET	0x46
+#define VGAENABLE	0x43
+
+#define SISAR		SISUSB_PCI_IOPORTBASE + AROFFSET
+#define SISARR		SISUSB_PCI_IOPORTBASE + ARROFFSET
+#define SISGR		SISUSB_PCI_IOPORTBASE + GROFFSET
+#define SISSR		SISUSB_PCI_IOPORTBASE + SROFFSET
+#define SISCR		SISUSB_PCI_IOPORTBASE + CROFFSET
+#define SISMISCR	SISUSB_PCI_IOPORTBASE + MISCROFFSET
+#define SISMISCW	SISUSB_PCI_IOPORTBASE + MISCWOFFSET
+#define SISINPSTAT	SISUSB_PCI_IOPORTBASE + INPUTSTATOFFSET
+#define SISPART1	SISUSB_PCI_IOPORTBASE + PART1OFFSET
+#define SISPART2	SISUSB_PCI_IOPORTBASE + PART2OFFSET
+#define SISPART3	SISUSB_PCI_IOPORTBASE + PART3OFFSET
+#define SISPART4	SISUSB_PCI_IOPORTBASE + PART4OFFSET
+#define SISPART5	SISUSB_PCI_IOPORTBASE + PART5OFFSET
+#define SISCAP		SISUSB_PCI_IOPORTBASE + CAPTUREOFFSET
+#define SISVID		SISUSB_PCI_IOPORTBASE + VIDEOOFFSET
+#define SISCOLIDXR	SISUSB_PCI_IOPORTBASE + COLREGOFFSET - 1
+#define SISCOLIDX	SISUSB_PCI_IOPORTBASE + COLREGOFFSET
+#define SISCOLDATA	SISUSB_PCI_IOPORTBASE + COLREGOFFSET + 1
+#define SISCOL2IDX	SISPART5
+#define SISCOL2DATA	SISPART5 + 1
+#define SISPEL		SISUSB_PCI_IOPORTBASE + PELMASKOFFSET
+#define SISVGAEN	SISUSB_PCI_IOPORTBASE + VGAENABLE
+#define SISDACA		SISCOLIDX
+#define SISDACD		SISCOLDATA
+
+/* ioctl related */
+
+/* Structure argument for SISUSB_GET_INFO ioctl  */
+struct sisusb_info {
+	__u32 sisusb_id;	/* for identifying sisusb */
+#define SISUSB_ID  0x53495355	/* Identify myself with 'SISU' */
+	__u8 sisusb_version;
+	__u8 sisusb_revision;
+	__u8 sisusb_patchlevel;
+	__u8 sisusb_gfxinit;	/* graphics core initialized? */
+
+	__u32 sisusb_vrambase;
+	__u32 sisusb_mmiobase;
+	__u32 sisusb_iobase;
+	__u32 sisusb_pcibase;
+
+	__u32 sisusb_vramsize;	/* framebuffer size in bytes */
+
+	__u32 sisusb_minor;
+
+	__u32 sisusb_fbdevactive;	/* != 0 if framebuffer device active */
+
+	__u32 sisusb_conactive;	/* != 0 if console driver active */
+
+	__u8 sisusb_reserved[28];	/* for future use */
+};
+
+struct sisusb_command {
+	__u8 operation;		/* see below */
+	__u8 data0;		/* operation dependent */
+	__u8 data1;		/* operation dependent */
+	__u8 data2;		/* operation dependent */
+	__u32 data3;		/* operation dependent */
+	__u32 data4;		/* for future use */
+};
+
+#define SUCMD_GET	0x01	/* for all: data0 = index, data3 = port */
+#define SUCMD_SET	0x02	/* data1 = value */
+#define SUCMD_SETOR	0x03	/* data1 = or */
+#define SUCMD_SETAND	0x04	/* data1 = and */
+#define SUCMD_SETANDOR	0x05	/* data1 = and, data2 = or */
+#define SUCMD_SETMASK	0x06	/* data1 = data, data2 = mask */
+
+#define SUCMD_CLRSCR	0x07	/* data0:1:2 = length, data3 = address */
+
+#define SUCMD_HANDLETEXTMODE 0x08	/* Reset/destroy text mode */
+
+#define SUCMD_SETMODE	0x09	/* Set a display mode (data3 = SiS mode) */
+#define SUCMD_SETVESAMODE 0x0a	/* Set a display mode (data3 = VESA mode) */
+
+#define SISUSB_COMMAND		_IOWR(0xF3,0x3D,struct sisusb_command)
+#define SISUSB_GET_CONFIG_SIZE	_IOR(0xF3,0x3E,__u32)
+#define SISUSB_GET_CONFIG	_IOR(0xF3,0x3F,struct sisusb_info)
+
+#endif /* SISUSB_H */
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
new file mode 100644
index 0000000..ace3430
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -0,0 +1,1586 @@
+/*
+ * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
+ *
+ * VGA text mode console part
+ *
+ * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific psisusbr written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Portions based on vgacon.c which are
+ *	Created 28 Sep 1997 by Geert Uytterhoeven
+ *      Rewritten by Martin Mares <mj@ucw.cz>, July 1998
+ *      based on code Copyright (C) 1991, 1992  Linus Torvalds
+ *			    1995  Jay Estabrook
+ *
+ * A note on using in_atomic() in here: We can't handle console
+ * calls from non-schedulable context due to our USB-dependend
+ * nature. For now, this driver just ignores any calls if it
+ * detects this state.
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/usb.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/kd.h>
+#include <linux/init.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+
+#include "sisusb.h"
+#include "sisusb_init.h"
+
+#ifdef INCL_SISUSB_CON
+
+#define sisusbcon_writew(val, addr)	(*(addr) = (val))
+#define sisusbcon_readw(addr)		(*(addr))
+#define sisusbcon_memmovew(d, s, c)	memmove(d, s, c)
+#define sisusbcon_memcpyw(d, s, c)	memcpy(d, s, c)
+
+/* vc_data -> sisusb conversion table */
+static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES];
+
+/* Forward declaration */
+static const struct consw sisusb_con;
+
+static inline void
+sisusbcon_memsetw(u16 *s, u16 c, unsigned int count)
+{
+	count /= 2;
+	while (count--)
+		sisusbcon_writew(c, s++);
+}
+
+static inline void
+sisusb_initialize(struct sisusb_usb_data *sisusb)
+{
+	/* Reset cursor and start address */
+	if (sisusb_setidxreg(sisusb, SISCR, 0x0c, 0x00))
+		return;
+	if (sisusb_setidxreg(sisusb, SISCR, 0x0d, 0x00))
+		return;
+	if (sisusb_setidxreg(sisusb, SISCR, 0x0e, 0x00))
+		return;
+	sisusb_setidxreg(sisusb, SISCR, 0x0f, 0x00);
+}
+
+static inline void
+sisusbcon_set_start_address(struct sisusb_usb_data *sisusb, struct vc_data *c)
+{
+	sisusb->cur_start_addr = (c->vc_visible_origin - sisusb->scrbuf) / 2;
+
+	sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
+	sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
+}
+
+void
+sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location)
+{
+	if (sisusb->sisusb_cursor_loc == location)
+		return;
+
+	sisusb->sisusb_cursor_loc = location;
+
+	/* Hardware bug: Text cursor appears twice or not at all
+	 * at some positions. Work around it with the cursor skew
+	 * bits.
+	 */
+
+	if ((location & 0x0007) == 0x0007) {
+		sisusb->bad_cursor_pos = 1;
+		location--;
+		if (sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0x1f, 0x20))
+			return;
+	} else if (sisusb->bad_cursor_pos) {
+		if (sisusb_setidxregand(sisusb, SISCR, 0x0b, 0x1f))
+			return;
+		sisusb->bad_cursor_pos = 0;
+	}
+
+	if (sisusb_setidxreg(sisusb, SISCR, 0x0e, (location >> 8)))
+		return;
+	sisusb_setidxreg(sisusb, SISCR, 0x0f, (location & 0xff));
+}
+
+static inline struct sisusb_usb_data *
+sisusb_get_sisusb(unsigned short console)
+{
+	return mysisusbs[console];
+}
+
+static inline int
+sisusb_sisusb_valid(struct sisusb_usb_data *sisusb)
+{
+	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev)
+		return 0;
+
+	return 1;
+}
+
+static struct sisusb_usb_data *
+sisusb_get_sisusb_lock_and_check(unsigned short console)
+{
+	struct sisusb_usb_data *sisusb;
+
+	/* We can't handle console calls in non-schedulable
+	 * context due to our locks and the USB transport.
+	 * So we simply ignore them. This should only affect
+	 * some calls to printk.
+	 */
+	if (in_atomic())
+		return NULL;
+
+	sisusb = sisusb_get_sisusb(console);
+	if (!sisusb)
+		return NULL;
+
+	mutex_lock(&sisusb->lock);
+
+	if (!sisusb_sisusb_valid(sisusb) ||
+	    !sisusb->havethisconsole[console]) {
+		mutex_unlock(&sisusb->lock);
+		return NULL;
+	}
+
+	return sisusb;
+}
+
+static int
+sisusb_is_inactive(struct vc_data *c, struct sisusb_usb_data *sisusb)
+{
+	if (sisusb->is_gfx ||
+	    sisusb->textmodedestroyed ||
+	    c->vc_mode != KD_TEXT)
+		return 1;
+
+	return 0;
+}
+
+/* con_startup console interface routine */
+static const char *
+sisusbcon_startup(void)
+{
+	return "SISUSBCON";
+}
+
+/* con_init console interface routine */
+static void
+sisusbcon_init(struct vc_data *c, int init)
+{
+	struct sisusb_usb_data *sisusb;
+	int cols, rows;
+
+	/* This is called by do_take_over_console(),
+	 * ie by us/under our control. It is
+	 * only called after text mode and fonts
+	 * are set up/restored.
+	 */
+
+	sisusb = sisusb_get_sisusb(c->vc_num);
+	if (!sisusb)
+		return;
+
+	mutex_lock(&sisusb->lock);
+
+	if (!sisusb_sisusb_valid(sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return;
+	}
+
+	c->vc_can_do_color = 1;
+
+	c->vc_complement_mask = 0x7700;
+
+	c->vc_hi_font_mask = sisusb->current_font_512 ? 0x0800 : 0;
+
+	sisusb->haveconsole = 1;
+
+	sisusb->havethisconsole[c->vc_num] = 1;
+
+	/* We only support 640x400 */
+	c->vc_scan_lines = 400;
+
+	c->vc_font.height = sisusb->current_font_height;
+
+	/* We only support width = 8 */
+	cols = 80;
+	rows = c->vc_scan_lines / c->vc_font.height;
+
+	/* Increment usage count for our sisusb.
+	 * Doing so saves us from upping/downing
+	 * the disconnect semaphore; we can't
+	 * lose our sisusb until this is undone
+	 * in con_deinit. For all other console
+	 * interface functions, it suffices to
+	 * use sisusb->lock and do a quick check
+	 * of sisusb for device disconnection.
+	 */
+	kref_get(&sisusb->kref);
+
+	if (!*c->vc_uni_pagedir_loc)
+		con_set_default_unimap(c);
+
+	mutex_unlock(&sisusb->lock);
+
+	if (init) {
+		c->vc_cols = cols;
+		c->vc_rows = rows;
+	} else
+		vc_resize(c, cols, rows);
+}
+
+/* con_deinit console interface routine */
+static void
+sisusbcon_deinit(struct vc_data *c)
+{
+	struct sisusb_usb_data *sisusb;
+	int i;
+
+	/* This is called by do_take_over_console()
+	 * and others, ie not under our control.
+	 */
+
+	sisusb = sisusb_get_sisusb(c->vc_num);
+	if (!sisusb)
+		return;
+
+	mutex_lock(&sisusb->lock);
+
+	/* Clear ourselves in mysisusbs */
+	mysisusbs[c->vc_num] = NULL;
+
+	sisusb->havethisconsole[c->vc_num] = 0;
+
+	/* Free our font buffer if all consoles are gone */
+	if (sisusb->font_backup) {
+		for(i = 0; i < MAX_NR_CONSOLES; i++) {
+			if (sisusb->havethisconsole[c->vc_num])
+				break;
+		}
+		if (i == MAX_NR_CONSOLES) {
+			vfree(sisusb->font_backup);
+			sisusb->font_backup = NULL;
+		}
+	}
+
+	mutex_unlock(&sisusb->lock);
+
+	/* decrement the usage count on our sisusb */
+	kref_put(&sisusb->kref, sisusb_delete);
+}
+
+/* interface routine */
+static u8
+sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity,
+			    u8 blink, u8 underline, u8 reverse, u8 unused)
+{
+	u8 attr = color;
+
+	if (underline)
+		attr = (attr & 0xf0) | c->vc_ulcolor;
+	else if (intensity == 0)
+		attr = (attr & 0xf0) | c->vc_halfcolor;
+
+	if (reverse)
+		attr = ((attr) & 0x88) |
+		       ((((attr) >> 4) |
+		       ((attr) << 4)) & 0x77);
+
+	if (blink)
+		attr ^= 0x80;
+
+	if (intensity == 2)
+		attr ^= 0x08;
+
+	return attr;
+}
+
+/* Interface routine */
+static void
+sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count)
+{
+	/* Invert a region. This is called with a pointer
+	 * to the console's internal screen buffer. So we
+	 * simply do the inversion there and rely on
+	 * a call to putc(s) to update the real screen.
+	 */
+
+	while (count--) {
+		u16 a = sisusbcon_readw(p);
+
+		a = ((a) & 0x88ff)        |
+		    (((a) & 0x7000) >> 4) |
+		    (((a) & 0x0700) << 4);
+
+		sisusbcon_writew(a, p++);
+	}
+}
+
+#define SISUSB_VADDR(x,y) \
+	((u16 *)c->vc_origin + \
+	(y) * sisusb->sisusb_num_columns + \
+	(x))
+
+#define SISUSB_HADDR(x,y) \
+	((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \
+	(y) * sisusb->sisusb_num_columns + \
+	(x))
+
+/* Interface routine */
+static void
+sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
+{
+	struct sisusb_usb_data *sisusb;
+	ssize_t written;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return;
+
+	/* sisusb->lock is down */
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return;
+	}
+
+
+	sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
+				(long)SISUSB_HADDR(x, y), 2, &written);
+
+	mutex_unlock(&sisusb->lock);
+}
+
+/* Interface routine */
+static void
+sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
+		         int count, int y, int x)
+{
+	struct sisusb_usb_data *sisusb;
+	ssize_t written;
+	u16 *dest;
+	int i;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return;
+
+	/* sisusb->lock is down */
+
+	/* Need to put the characters into the buffer ourselves,
+	 * because the vt does this AFTER calling us.
+	 */
+
+	dest = SISUSB_VADDR(x, y);
+
+	for (i = count; i > 0; i--)
+		sisusbcon_writew(sisusbcon_readw(s++), dest++);
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return;
+	}
+
+	sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
+				(long)SISUSB_HADDR(x, y), count * 2, &written);
+
+	mutex_unlock(&sisusb->lock);
+}
+
+/* Interface routine */
+static void
+sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
+{
+	struct sisusb_usb_data *sisusb;
+	u16 eattr = c->vc_video_erase_char;
+	ssize_t written;
+	int i, length, cols;
+	u16 *dest;
+
+	if (width <= 0 || height <= 0)
+		return;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return;
+
+	/* sisusb->lock is down */
+
+	/* Need to clear buffer ourselves, because the vt does
+	 * this AFTER calling us.
+	 */
+
+	dest = SISUSB_VADDR(x, y);
+
+	cols = sisusb->sisusb_num_columns;
+
+	if (width > cols)
+		width = cols;
+
+	if (x == 0 && width >= c->vc_cols) {
+
+		sisusbcon_memsetw(dest, eattr, height * cols * 2);
+
+	} else {
+
+		for (i = height; i > 0; i--, dest += cols)
+			sisusbcon_memsetw(dest, eattr, width * 2);
+
+	}
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return;
+	}
+
+	length = ((height * cols) - x - (cols - width - x)) * 2;
+
+
+	sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
+				(long)SISUSB_HADDR(x, y), length, &written);
+
+	mutex_unlock(&sisusb->lock);
+}
+
+/* Interface routine */
+static void
+sisusbcon_bmove(struct vc_data *c, int sy, int sx,
+			 int dy, int dx, int height, int width)
+{
+	struct sisusb_usb_data *sisusb;
+	ssize_t written;
+	int cols, length;
+
+	if (width <= 0 || height <= 0)
+		return;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return;
+
+	/* sisusb->lock is down */
+
+	cols = sisusb->sisusb_num_columns;
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return;
+	}
+
+	length = ((height * cols) - dx - (cols - width - dx)) * 2;
+
+
+	sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy),
+				(long)SISUSB_HADDR(dx, dy), length, &written);
+
+	mutex_unlock(&sisusb->lock);
+}
+
+/* interface routine */
+static int
+sisusbcon_switch(struct vc_data *c)
+{
+	struct sisusb_usb_data *sisusb;
+	ssize_t written;
+	int length;
+
+	/* Returnvalue 0 means we have fully restored screen,
+	 *	and vt doesn't need to call do_update_region().
+	 * Returnvalue != 0 naturally means the opposite.
+	 */
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return 0;
+
+	/* sisusb->lock is down */
+
+	/* Don't write to screen if in gfx mode */
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return 0;
+	}
+
+	/* That really should not happen. It would mean we are
+	 * being called while the vc is using its private buffer
+	 * as origin.
+	 */
+	if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
+		mutex_unlock(&sisusb->lock);
+		dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
+		return 0;
+	}
+
+	/* Check that we don't copy too much */
+	length = min((int)c->vc_screenbuf_size,
+			(int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
+
+	/* Restore the screen contents */
+	sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf,
+								length);
+
+	sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin,
+				(long)SISUSB_HADDR(0, 0),
+				length, &written);
+
+	mutex_unlock(&sisusb->lock);
+
+	return 0;
+}
+
+/* interface routine */
+static void
+sisusbcon_save_screen(struct vc_data *c)
+{
+	struct sisusb_usb_data *sisusb;
+	int length;
+
+	/* Save the current screen contents to vc's private
+	 * buffer.
+	 */
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return;
+
+	/* sisusb->lock is down */
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return;
+	}
+
+	/* Check that we don't copy too much */
+	length = min((int)c->vc_screenbuf_size,
+			(int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
+
+	/* Save the screen contents to vc's private buffer */
+	sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin,
+								length);
+
+	mutex_unlock(&sisusb->lock);
+}
+
+/* interface routine */
+static int
+sisusbcon_set_palette(struct vc_data *c, unsigned char *table)
+{
+	struct sisusb_usb_data *sisusb;
+	int i, j;
+
+	/* Return value not used by vt */
+
+	if (!CON_IS_VISIBLE(c))
+		return -EINVAL;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return -EINVAL;
+
+	/* sisusb->lock is down */
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return -EINVAL;
+	}
+
+	for (i = j = 0; i < 16; i++) {
+		if (sisusb_setreg(sisusb, SISCOLIDX, table[i]))
+			break;
+		if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
+			break;
+		if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
+			break;
+		if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
+			break;
+	}
+
+	mutex_unlock(&sisusb->lock);
+
+	return 0;
+}
+
+/* interface routine */
+static int
+sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
+{
+	struct sisusb_usb_data *sisusb;
+	u8 sr1, cr17, pmreg, cr63;
+	ssize_t written;
+	int ret = 0;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return 0;
+
+	/* sisusb->lock is down */
+
+	if (mode_switch)
+		sisusb->is_gfx = blank ? 1 : 0;
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return 0;
+	}
+
+	switch (blank) {
+
+	case 1:		/* Normal blanking: Clear screen */
+	case -1:
+		sisusbcon_memsetw((u16 *)c->vc_origin,
+				c->vc_video_erase_char,
+				c->vc_screenbuf_size);
+		sisusb_copy_memory(sisusb,
+				(unsigned char *)c->vc_origin,
+				(u32)(sisusb->vrambase +
+					(c->vc_origin - sisusb->scrbuf)),
+				c->vc_screenbuf_size, &written);
+		sisusb->con_blanked = 1;
+		ret = 1;
+		break;
+
+	default:	/* VESA blanking */
+		switch (blank) {
+		case 0: /* Unblank */
+			sr1   = 0x00;
+			cr17  = 0x80;
+			pmreg = 0x00;
+			cr63  = 0x00;
+			ret = 1;
+			sisusb->con_blanked = 0;
+			break;
+		case VESA_VSYNC_SUSPEND + 1:
+			sr1   = 0x20;
+			cr17  = 0x80;
+			pmreg = 0x80;
+			cr63  = 0x40;
+			break;
+		case VESA_HSYNC_SUSPEND + 1:
+			sr1   = 0x20;
+			cr17  = 0x80;
+			pmreg = 0x40;
+			cr63  = 0x40;
+			break;
+		case VESA_POWERDOWN + 1:
+			sr1   = 0x20;
+			cr17  = 0x00;
+			pmreg = 0xc0;
+			cr63  = 0x40;
+			break;
+		default:
+			mutex_unlock(&sisusb->lock);
+			return -EINVAL;
+		}
+
+		sisusb_setidxregandor(sisusb, SISSR, 0x01, ~0x20, sr1);
+		sisusb_setidxregandor(sisusb, SISCR, 0x17, 0x7f, cr17);
+		sisusb_setidxregandor(sisusb, SISSR, 0x1f, 0x3f, pmreg);
+		sisusb_setidxregandor(sisusb, SISCR, 0x63, 0xbf, cr63);
+
+	}
+
+	mutex_unlock(&sisusb->lock);
+
+	return ret;
+}
+
+/* interface routine */
+static int
+sisusbcon_scrolldelta(struct vc_data *c, int lines)
+{
+	struct sisusb_usb_data *sisusb;
+	int margin = c->vc_size_row * 4;
+	int ul, we, p, st;
+
+	/* The return value does not seem to be used */
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return 0;
+
+	/* sisusb->lock is down */
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return 0;
+	}
+
+	if (!lines)		/* Turn scrollback off */
+		c->vc_visible_origin = c->vc_origin;
+	else {
+
+		if (sisusb->con_rolled_over >
+				(c->vc_scr_end - sisusb->scrbuf) + margin) {
+
+			ul = c->vc_scr_end - sisusb->scrbuf;
+			we = sisusb->con_rolled_over + c->vc_size_row;
+
+		} else {
+
+			ul = 0;
+			we = sisusb->scrbuf_size;
+
+		}
+
+		p = (c->vc_visible_origin - sisusb->scrbuf - ul + we) % we +
+				lines * c->vc_size_row;
+
+		st = (c->vc_origin - sisusb->scrbuf - ul + we) % we;
+
+		if (st < 2 * margin)
+			margin = 0;
+
+		if (p < margin)
+			p = 0;
+
+		if (p > st - margin)
+			p = st;
+
+		c->vc_visible_origin = sisusb->scrbuf + (p + ul) % we;
+	}
+
+	sisusbcon_set_start_address(sisusb, c);
+
+	mutex_unlock(&sisusb->lock);
+
+	return 1;
+}
+
+/* Interface routine */
+static void
+sisusbcon_cursor(struct vc_data *c, int mode)
+{
+	struct sisusb_usb_data *sisusb;
+	int from, to, baseline;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return;
+
+	/* sisusb->lock is down */
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return;
+	}
+
+	if (c->vc_origin != c->vc_visible_origin) {
+		c->vc_visible_origin = c->vc_origin;
+		sisusbcon_set_start_address(sisusb, c);
+	}
+
+	if (mode == CM_ERASE) {
+		sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20);
+		sisusb->sisusb_cursor_size_to = -1;
+		mutex_unlock(&sisusb->lock);
+		return;
+	}
+
+	sisusb_set_cursor(sisusb, (c->vc_pos - sisusb->scrbuf) / 2);
+
+	baseline = c->vc_font.height - (c->vc_font.height < 10 ? 1 : 2);
+
+	switch (c->vc_cursor_type & 0x0f) {
+		case CUR_BLOCK:		from = 1;
+					to   = c->vc_font.height;
+					break;
+		case CUR_TWO_THIRDS:	from = c->vc_font.height / 3;
+					to   = baseline;
+					break;
+		case CUR_LOWER_HALF:	from = c->vc_font.height / 2;
+					to   = baseline;
+					break;
+		case CUR_LOWER_THIRD:	from = (c->vc_font.height * 2) / 3;
+					to   = baseline;
+					break;
+		case CUR_NONE:		from = 31;
+					to = 30;
+					break;
+		default:
+		case CUR_UNDERLINE:	from = baseline - 1;
+					to   = baseline;
+					break;
+	}
+
+	if (sisusb->sisusb_cursor_size_from != from ||
+	    sisusb->sisusb_cursor_size_to != to) {
+
+		sisusb_setidxreg(sisusb, SISCR, 0x0a, from);
+		sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, to);
+
+		sisusb->sisusb_cursor_size_from = from;
+		sisusb->sisusb_cursor_size_to   = to;
+	}
+
+	mutex_unlock(&sisusb->lock);
+}
+
+static int
+sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
+					int t, int b, int dir, int lines)
+{
+	int cols = sisusb->sisusb_num_columns;
+	int length = ((b - t) * cols) * 2;
+	u16 eattr = c->vc_video_erase_char;
+	ssize_t written;
+
+	/* sisusb->lock is down */
+
+	/* Scroll an area which does not match the
+	 * visible screen's dimensions. This needs
+	 * to be done separately, as it does not
+	 * use hardware panning.
+	 */
+
+	switch (dir) {
+
+		case SM_UP:
+			sisusbcon_memmovew(SISUSB_VADDR(0, t),
+					   SISUSB_VADDR(0, t + lines),
+					   (b - t - lines) * cols * 2);
+			sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr,
+					  lines * cols * 2);
+			break;
+
+		case SM_DOWN:
+			sisusbcon_memmovew(SISUSB_VADDR(0, t + lines),
+					   SISUSB_VADDR(0, t),
+					   (b - t - lines) * cols * 2);
+			sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr,
+					  lines * cols * 2);
+			break;
+	}
+
+	sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t),
+				(long)SISUSB_HADDR(0, t), length, &written);
+
+	mutex_unlock(&sisusb->lock);
+
+	return 1;
+}
+
+/* Interface routine */
+static int
+sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
+{
+	struct sisusb_usb_data *sisusb;
+	u16 eattr = c->vc_video_erase_char;
+	ssize_t written;
+	int copyall = 0;
+	unsigned long oldorigin;
+	unsigned int delta = lines * c->vc_size_row;
+	u32 originoffset;
+
+	/* Returning != 0 means we have done the scrolling successfully.
+	 * Returning 0 makes vt do the scrolling on its own.
+	 * Note that con_scroll is only called if the console is
+	 * visible. In that case, the origin should be our buffer,
+	 * not the vt's private one.
+	 */
+
+	if (!lines)
+		return 1;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return 0;
+
+	/* sisusb->lock is down */
+
+	if (sisusb_is_inactive(c, sisusb)) {
+		mutex_unlock(&sisusb->lock);
+		return 0;
+	}
+
+	/* Special case */
+	if (t || b != c->vc_rows)
+		return sisusbcon_scroll_area(c, sisusb, t, b, dir, lines);
+
+	if (c->vc_origin != c->vc_visible_origin) {
+		c->vc_visible_origin = c->vc_origin;
+		sisusbcon_set_start_address(sisusb, c);
+	}
+
+	/* limit amount to maximum realistic size */
+	if (lines > c->vc_rows)
+		lines = c->vc_rows;
+
+	oldorigin = c->vc_origin;
+
+	switch (dir) {
+
+	case SM_UP:
+
+		if (c->vc_scr_end + delta >=
+				sisusb->scrbuf + sisusb->scrbuf_size) {
+			sisusbcon_memcpyw((u16 *)sisusb->scrbuf,
+					  (u16 *)(oldorigin + delta),
+					  c->vc_screenbuf_size - delta);
+			c->vc_origin = sisusb->scrbuf;
+			sisusb->con_rolled_over = oldorigin - sisusb->scrbuf;
+			copyall = 1;
+		} else
+			c->vc_origin += delta;
+
+		sisusbcon_memsetw(
+			(u16 *)(c->vc_origin + c->vc_screenbuf_size - delta),
+					eattr, delta);
+
+		break;
+
+	case SM_DOWN:
+
+		if (oldorigin - delta < sisusb->scrbuf) {
+			sisusbcon_memmovew((u16 *)(sisusb->scrbuf +
+							sisusb->scrbuf_size -
+							c->vc_screenbuf_size +
+							delta),
+					   (u16 *)oldorigin,
+					   c->vc_screenbuf_size - delta);
+			c->vc_origin = sisusb->scrbuf +
+					sisusb->scrbuf_size -
+					c->vc_screenbuf_size;
+			sisusb->con_rolled_over = 0;
+			copyall = 1;
+		} else
+			c->vc_origin -= delta;
+
+		c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
+
+		scr_memsetw((u16 *)(c->vc_origin), eattr, delta);
+
+		break;
+	}
+
+	originoffset = (u32)(c->vc_origin - sisusb->scrbuf);
+
+	if (copyall)
+		sisusb_copy_memory(sisusb,
+			(char *)c->vc_origin,
+			(u32)(sisusb->vrambase + originoffset),
+			c->vc_screenbuf_size, &written);
+	else if (dir == SM_UP)
+		sisusb_copy_memory(sisusb,
+			(char *)c->vc_origin + c->vc_screenbuf_size - delta,
+			(u32)sisusb->vrambase + originoffset +
+					c->vc_screenbuf_size - delta,
+			delta, &written);
+	else
+		sisusb_copy_memory(sisusb,
+			(char *)c->vc_origin,
+			(u32)(sisusb->vrambase + originoffset),
+			delta, &written);
+
+	c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
+	c->vc_visible_origin = c->vc_origin;
+
+	sisusbcon_set_start_address(sisusb, c);
+
+	c->vc_pos = c->vc_pos - oldorigin + c->vc_origin;
+
+	mutex_unlock(&sisusb->lock);
+
+	return 1;
+}
+
+/* Interface routine */
+static int
+sisusbcon_set_origin(struct vc_data *c)
+{
+	struct sisusb_usb_data *sisusb;
+
+	/* Returning != 0 means we were successful.
+	 * Returning 0 will vt make to use its own
+	 *	screenbuffer as the origin.
+	 */
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return 0;
+
+	/* sisusb->lock is down */
+
+	if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) {
+		mutex_unlock(&sisusb->lock);
+		return 0;
+	}
+
+	c->vc_origin = c->vc_visible_origin = sisusb->scrbuf;
+
+	sisusbcon_set_start_address(sisusb, c);
+
+	sisusb->con_rolled_over = 0;
+
+	mutex_unlock(&sisusb->lock);
+
+	return 1;
+}
+
+/* Interface routine */
+static int
+sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows,
+		 unsigned int user)
+{
+	struct sisusb_usb_data *sisusb;
+	int fh;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return -ENODEV;
+
+	fh = sisusb->current_font_height;
+
+	mutex_unlock(&sisusb->lock);
+
+	/* We are quite unflexible as regards resizing. The vt code
+	 * handles sizes where the line length isn't equal the pitch
+	 * quite badly. As regards the rows, our panning tricks only
+	 * work well if the number of rows equals the visible number
+	 * of rows.
+	 */
+
+	if (newcols != 80 || c->vc_scan_lines / fh != newrows)
+		return -EINVAL;
+
+	return 0;
+}
+
+int
+sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
+			u8 *arg, int cmapsz, int ch512, int dorecalc,
+			struct vc_data *c, int fh, int uplock)
+{
+	int font_select = 0x00, i, err = 0;
+	u32 offset = 0;
+	u8 dummy;
+
+	/* sisusb->lock is down */
+
+	/*
+	 * The default font is kept in slot 0.
+	 * A user font is loaded in slot 2 (256 ch)
+	 * or 2+3 (512 ch).
+	 */
+
+	if ((slot != 0 && slot != 2) || !fh) {
+		if (uplock)
+			mutex_unlock(&sisusb->lock);
+		return -EINVAL;
+	}
+
+	if (set)
+		sisusb->font_slot = slot;
+
+	/* Default font is always 256 */
+	if (slot == 0)
+		ch512 = 0;
+	else
+		offset = 4 * cmapsz;
+
+	font_select = (slot == 0) ? 0x00 : (ch512 ? 0x0e : 0x0a);
+
+	err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */
+	err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x04); /* Write to plane 2 */
+	err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x07); /* Memory mode a0-bf */
+	err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset */
+
+	if (err)
+		goto font_op_error;
+
+	err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x03); /* Select plane read 2 */
+	err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x00); /* Disable odd/even */
+	err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x00); /* Address range a0-bf */
+
+	if (err)
+		goto font_op_error;
+
+	if (arg) {
+		if (set)
+			for (i = 0; i < cmapsz; i++) {
+				err |= sisusb_writeb(sisusb,
+					sisusb->vrambase + offset + i,
+					arg[i]);
+				if (err)
+					break;
+			}
+		else
+			for (i = 0; i < cmapsz; i++) {
+				err |= sisusb_readb(sisusb,
+					sisusb->vrambase + offset + i,
+					&arg[i]);
+				if (err)
+					break;
+			}
+
+		/*
+		 * In 512-character mode, the character map is not contiguous if
+		 * we want to remain EGA compatible -- which we do
+		 */
+
+		if (ch512) {
+			if (set)
+				for (i = 0; i < cmapsz; i++) {
+					err |= sisusb_writeb(sisusb,
+						sisusb->vrambase + offset +
+							(2 * cmapsz) + i,
+						arg[cmapsz + i]);
+					if (err)
+						break;
+				}
+			else
+				for (i = 0; i < cmapsz; i++) {
+					err |= sisusb_readb(sisusb,
+						sisusb->vrambase + offset +
+							(2 * cmapsz) + i,
+						&arg[cmapsz + i]);
+					if (err)
+						break;
+				}
+		}
+	}
+
+	if (err)
+		goto font_op_error;
+
+	err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */
+	err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x03); /* Write to planes 0+1 */
+	err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x03); /* Memory mode a0-bf */
+	if (set)
+		sisusb_setidxreg(sisusb, SISSR, 0x03, font_select);
+	err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset end */
+
+	if (err)
+		goto font_op_error;
+
+	err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x00); /* Select plane read 0 */
+	err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x10); /* Enable odd/even */
+	err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x06); /* Address range b8-bf */
+
+	if (err)
+		goto font_op_error;
+
+	if ((set) && (ch512 != sisusb->current_font_512)) {
+
+		/* Font is shared among all our consoles.
+		 * And so is the hi_font_mask.
+		 */
+		for (i = 0; i < MAX_NR_CONSOLES; i++) {
+			struct vc_data *d = vc_cons[i].d;
+			if (d && d->vc_sw == &sisusb_con)
+				d->vc_hi_font_mask = ch512 ? 0x0800 : 0;
+		}
+
+		sisusb->current_font_512 = ch512;
+
+		/* color plane enable register:
+			256-char: enable intensity bit
+			512-char: disable intensity bit */
+		sisusb_getreg(sisusb, SISINPSTAT, &dummy);
+		sisusb_setreg(sisusb, SISAR, 0x12);
+		sisusb_setreg(sisusb, SISAR, ch512 ? 0x07 : 0x0f);
+
+		sisusb_getreg(sisusb, SISINPSTAT, &dummy);
+		sisusb_setreg(sisusb, SISAR, 0x20);
+		sisusb_getreg(sisusb, SISINPSTAT, &dummy);
+	}
+
+	if (dorecalc) {
+
+		/*
+		 * Adjust the screen to fit a font of a certain height
+		 */
+
+		unsigned char ovr, vde, fsr;
+		int rows = 0, maxscan = 0;
+
+		if (c) {
+
+			/* Number of video rows */
+			rows = c->vc_scan_lines / fh;
+			/* Scan lines to actually display-1 */
+			maxscan = rows * fh - 1;
+
+			/*printk(KERN_DEBUG "sisusb recalc rows %d maxscan %d fh %d sl %d\n",
+				rows, maxscan, fh, c->vc_scan_lines);*/
+
+			sisusb_getidxreg(sisusb, SISCR, 0x07, &ovr);
+			vde = maxscan & 0xff;
+			ovr = (ovr & 0xbd) |
+			      ((maxscan & 0x100) >> 7) |
+			      ((maxscan & 0x200) >> 3);
+			sisusb_setidxreg(sisusb, SISCR, 0x07, ovr);
+			sisusb_setidxreg(sisusb, SISCR, 0x12, vde);
+
+		}
+
+		sisusb_getidxreg(sisusb, SISCR, 0x09, &fsr);
+		fsr = (fsr & 0xe0) | (fh - 1);
+		sisusb_setidxreg(sisusb, SISCR, 0x09, fsr);
+		sisusb->current_font_height = fh;
+
+		sisusb->sisusb_cursor_size_from = -1;
+		sisusb->sisusb_cursor_size_to   = -1;
+
+	}
+
+	if (uplock)
+		mutex_unlock(&sisusb->lock);
+
+	if (dorecalc && c) {
+		int rows = c->vc_scan_lines / fh;
+
+		/* Now adjust our consoles' size */
+
+		for (i = 0; i < MAX_NR_CONSOLES; i++) {
+			struct vc_data *vc = vc_cons[i].d;
+
+			if (vc && vc->vc_sw == &sisusb_con) {
+				if (CON_IS_VISIBLE(vc)) {
+					vc->vc_sw->con_cursor(vc, CM_DRAW);
+				}
+				vc->vc_font.height = fh;
+				vc_resize(vc, 0, rows);
+			}
+		}
+	}
+
+	return 0;
+
+font_op_error:
+	if (uplock)
+		mutex_unlock(&sisusb->lock);
+
+	return -EIO;
+}
+
+/* Interface routine */
+static int
+sisusbcon_font_set(struct vc_data *c, struct console_font *font,
+							unsigned flags)
+{
+	struct sisusb_usb_data *sisusb;
+	unsigned charcount = font->charcount;
+
+	if (font->width != 8 || (charcount != 256 && charcount != 512))
+		return -EINVAL;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return -ENODEV;
+
+	/* sisusb->lock is down */
+
+	/* Save the user-provided font into a buffer. This
+	 * is used for restoring text mode after quitting
+	 * from X and for the con_getfont routine.
+	 */
+	if (sisusb->font_backup) {
+		if (sisusb->font_backup_size < charcount) {
+			vfree(sisusb->font_backup);
+			sisusb->font_backup = NULL;
+		}
+	}
+
+	if (!sisusb->font_backup)
+		sisusb->font_backup = vmalloc(charcount * 32);
+
+	if (sisusb->font_backup) {
+		memcpy(sisusb->font_backup, font->data, charcount * 32);
+		sisusb->font_backup_size = charcount;
+		sisusb->font_backup_height = font->height;
+		sisusb->font_backup_512 = (charcount == 512) ? 1 : 0;
+	}
+
+	/* do_font_op ups sisusb->lock */
+
+	return sisusbcon_do_font_op(sisusb, 1, 2, font->data,
+			8192, (charcount == 512),
+			(!(flags & KD_FONT_FLAG_DONT_RECALC)) ? 1 : 0,
+			c, font->height, 1);
+}
+
+/* Interface routine */
+static int
+sisusbcon_font_get(struct vc_data *c, struct console_font *font)
+{
+	struct sisusb_usb_data *sisusb;
+
+	sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
+	if (!sisusb)
+		return -ENODEV;
+
+	/* sisusb->lock is down */
+
+	font->width = 8;
+	font->height = c->vc_font.height;
+	font->charcount = 256;
+
+	if (!font->data) {
+		mutex_unlock(&sisusb->lock);
+		return 0;
+	}
+
+	if (!sisusb->font_backup) {
+		mutex_unlock(&sisusb->lock);
+		return -ENODEV;
+	}
+
+	/* Copy 256 chars only, like vgacon */
+	memcpy(font->data, sisusb->font_backup, 256 * 32);
+
+	mutex_unlock(&sisusb->lock);
+
+	return 0;
+}
+
+/*
+ *  The console `switch' structure for the sisusb console
+ */
+
+static const struct consw sisusb_con = {
+	.owner =		THIS_MODULE,
+	.con_startup =		sisusbcon_startup,
+	.con_init =		sisusbcon_init,
+	.con_deinit =		sisusbcon_deinit,
+	.con_clear =		sisusbcon_clear,
+	.con_putc =		sisusbcon_putc,
+	.con_putcs =		sisusbcon_putcs,
+	.con_cursor =		sisusbcon_cursor,
+	.con_scroll =		sisusbcon_scroll,
+	.con_bmove =		sisusbcon_bmove,
+	.con_switch =		sisusbcon_switch,
+	.con_blank =		sisusbcon_blank,
+	.con_font_set =		sisusbcon_font_set,
+	.con_font_get =		sisusbcon_font_get,
+	.con_set_palette =	sisusbcon_set_palette,
+	.con_scrolldelta =	sisusbcon_scrolldelta,
+	.con_build_attr =	sisusbcon_build_attr,
+	.con_invert_region =	sisusbcon_invert_region,
+	.con_set_origin =	sisusbcon_set_origin,
+	.con_save_screen =	sisusbcon_save_screen,
+	.con_resize =		sisusbcon_resize,
+};
+
+/* Our very own dummy console driver */
+
+static const char *sisusbdummycon_startup(void)
+{
+    return "SISUSBVGADUMMY";
+}
+
+static void sisusbdummycon_init(struct vc_data *vc, int init)
+{
+    vc->vc_can_do_color = 1;
+    if (init) {
+	vc->vc_cols = 80;
+	vc->vc_rows = 25;
+    } else
+	vc_resize(vc, 80, 25);
+}
+
+static int sisusbdummycon_dummy(void)
+{
+    return 0;
+}
+
+#define SISUSBCONDUMMY	(void *)sisusbdummycon_dummy
+
+static const struct consw sisusb_dummy_con = {
+	.owner =		THIS_MODULE,
+	.con_startup =		sisusbdummycon_startup,
+	.con_init =		sisusbdummycon_init,
+	.con_deinit =		SISUSBCONDUMMY,
+	.con_clear =		SISUSBCONDUMMY,
+	.con_putc =		SISUSBCONDUMMY,
+	.con_putcs =		SISUSBCONDUMMY,
+	.con_cursor =		SISUSBCONDUMMY,
+	.con_scroll =		SISUSBCONDUMMY,
+	.con_bmove =		SISUSBCONDUMMY,
+	.con_switch =		SISUSBCONDUMMY,
+	.con_blank =		SISUSBCONDUMMY,
+	.con_font_set =		SISUSBCONDUMMY,
+	.con_font_get =		SISUSBCONDUMMY,
+	.con_font_default =	SISUSBCONDUMMY,
+	.con_font_copy =	SISUSBCONDUMMY,
+	.con_set_palette =	SISUSBCONDUMMY,
+	.con_scrolldelta =	SISUSBCONDUMMY,
+};
+
+int
+sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
+{
+	int i, ret;
+
+	mutex_lock(&sisusb->lock);
+
+	/* Erm.. that should not happen */
+	if (sisusb->haveconsole || !sisusb->SiS_Pr) {
+		mutex_unlock(&sisusb->lock);
+		return 1;
+	}
+
+	sisusb->con_first = first;
+	sisusb->con_last  = last;
+
+	if (first > last ||
+	    first > MAX_NR_CONSOLES ||
+	    last > MAX_NR_CONSOLES) {
+		mutex_unlock(&sisusb->lock);
+		return 1;
+	}
+
+	/* If gfxcore not initialized or no consoles given, quit graciously */
+	if (!sisusb->gfxinit || first < 1 || last < 1) {
+		mutex_unlock(&sisusb->lock);
+		return 0;
+	}
+
+	sisusb->sisusb_cursor_loc       = -1;
+	sisusb->sisusb_cursor_size_from = -1;
+	sisusb->sisusb_cursor_size_to   = -1;
+
+	/* Set up text mode (and upload  default font) */
+	if (sisusb_reset_text_mode(sisusb, 1)) {
+		mutex_unlock(&sisusb->lock);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
+		return 1;
+	}
+
+	/* Initialize some gfx registers */
+	sisusb_initialize(sisusb);
+
+	for (i = first - 1; i <= last - 1; i++) {
+		/* Save sisusb for our interface routines */
+		mysisusbs[i] = sisusb;
+	}
+
+	/* Initial console setup */
+	sisusb->sisusb_num_columns = 80;
+
+	/* Use a 32K buffer (matches b8000-bffff area) */
+	sisusb->scrbuf_size = 32 * 1024;
+
+	/* Allocate screen buffer */
+	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
+		mutex_unlock(&sisusb->lock);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
+		return 1;
+	}
+
+	mutex_unlock(&sisusb->lock);
+
+	/* Now grab the desired console(s) */
+	console_lock();
+	ret = do_take_over_console(&sisusb_con, first - 1, last - 1, 0);
+	console_unlock();
+	if (!ret)
+		sisusb->haveconsole = 1;
+	else {
+		for (i = first - 1; i <= last - 1; i++)
+			mysisusbs[i] = NULL;
+	}
+
+	return ret;
+}
+
+void
+sisusb_console_exit(struct sisusb_usb_data *sisusb)
+{
+	int i;
+
+	/* This is called if the device is disconnected
+	 * and while disconnect and lock semaphores
+	 * are up. This should be save because we
+	 * can't lose our sisusb any other way but by
+	 * disconnection (and hence, the disconnect
+	 * sema is for protecting all other access
+	 * functions from disconnection, not the
+	 * other way round).
+	 */
+
+	/* Now what do we do in case of disconnection:
+	 * One alternative would be to simply call
+	 * give_up_console(). Nah, not a good idea.
+	 * give_up_console() is obviously buggy as it
+	 * only discards the consw pointer from the
+	 * driver_map, but doesn't adapt vc->vc_sw
+	 * of the affected consoles. Hence, the next
+	 * call to any of the console functions will
+	 * eventually take a trip to oops county.
+	 * Also, give_up_console for some reason
+	 * doesn't decrement our module refcount.
+	 * Instead, we switch our consoles to a private
+	 * dummy console. This, of course, keeps our
+	 * refcount up as well, but it works perfectly.
+	 */
+
+	if (sisusb->haveconsole) {
+		for (i = 0; i < MAX_NR_CONSOLES; i++)
+			if (sisusb->havethisconsole[i]) {
+				console_lock();
+				do_take_over_console(&sisusb_dummy_con, i, i, 0);
+				console_unlock();
+				/* At this point, con_deinit for all our
+				 * consoles is executed by do_take_over_console().
+				 */
+			}
+		sisusb->haveconsole = 0;
+	}
+
+	vfree((void *)sisusb->scrbuf);
+	sisusb->scrbuf = 0;
+
+	vfree(sisusb->font_backup);
+	sisusb->font_backup = NULL;
+}
+
+void __init sisusb_init_concode(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		mysisusbs[i] = NULL;
+}
+
+#endif /* INCL_CON */
+
+
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
new file mode 100644
index 0000000..bf0032c
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -0,0 +1,958 @@
+/*
+ * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
+ *
+ * Display mode initializing code
+ *
+ * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+
+#include "sisusb.h"
+
+#ifdef INCL_SISUSB_CON
+
+#include "sisusb_init.h"
+
+/*********************************************/
+/*         POINTER INITIALIZATION            */
+/*********************************************/
+
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+{
+	SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+	SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
+
+	SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+	SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+	SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+	SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
+
+	SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
+}
+
+/*********************************************/
+/*          HELPER: SetReg, GetReg           */
+/*********************************************/
+
+static void
+SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
+	   unsigned short index, unsigned short data)
+{
+	sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
+}
+
+static void
+SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
+	       unsigned short data)
+{
+	sisusb_setreg(SiS_Pr->sisusb, port, data);
+}
+
+static unsigned char
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
+{
+	u8 data;
+
+	sisusb_getidxreg(SiS_Pr->sisusb, port, index, &data);
+
+	return data;
+}
+
+static unsigned char
+SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
+{
+	u8 data;
+
+	sisusb_getreg(SiS_Pr->sisusb, port, &data);
+
+	return data;
+}
+
+static void
+SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
+		unsigned short index, unsigned short DataAND,
+		unsigned short DataOR)
+{
+	sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
+}
+
+static void
+SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
+	      unsigned short index, unsigned short DataAND)
+{
+	sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
+}
+
+static void
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+	     unsigned short index, unsigned short DataOR)
+{
+	sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
+}
+
+/*********************************************/
+/*      HELPER: DisplayOn, DisplayOff        */
+/*********************************************/
+
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+{
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
+}
+
+/*********************************************/
+/*        HELPER: Init Port Addresses        */
+/*********************************************/
+
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+{
+	SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
+	SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
+	SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
+	SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
+	SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
+	SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
+	SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
+	SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
+	SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
+	SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
+	SiS_Pr->SiS_P3cb = BaseAddr + 0x1b;
+	SiS_Pr->SiS_P3cc = BaseAddr + 0x1c;
+	SiS_Pr->SiS_P3cd = BaseAddr + 0x1d;
+	SiS_Pr->SiS_P3da = BaseAddr + 0x2a;
+	SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;
+}
+
+/*********************************************/
+/*             HELPER: GetSysFlags           */
+/*********************************************/
+
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+{
+	SiS_Pr->SiS_MyCR63 = 0x63;
+}
+
+/*********************************************/
+/*         HELPER: Init PCI & Engines        */
+/*********************************************/
+
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+{
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
+	/*  - Enable 2D (0x40)
+	 *  - Enable 3D (0x02)
+	 *  - Enable 3D vertex command fetch (0x10)
+	 *  - Enable 3D command parser (0x08)
+	 *  - Enable 3D G/L transformation engine (0x80)
+	 */
+	SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1E, 0xDA);
+}
+
+/*********************************************/
+/*        HELPER: SET SEGMENT REGISTERS      */
+/*********************************************/
+
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+{
+	unsigned short temp;
+
+	value &= 0x00ff;
+	temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0xf0;
+	temp |= (value >> 4);
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
+	temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0xf0;
+	temp |= (value & 0x0f);
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
+}
+
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+{
+	unsigned short temp;
+
+	value &= 0x00ff;
+	temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0x0f;
+	temp |= (value & 0xf0);
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
+	temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0x0f;
+	temp |= (value << 4);
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
+}
+
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+{
+	SiS_SetSegRegLower(SiS_Pr, value);
+	SiS_SetSegRegUpper(SiS_Pr, value);
+}
+
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+{
+	SiS_SetSegmentReg(SiS_Pr, 0);
+}
+
+static void
+SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
+{
+	unsigned short temp = value >> 8;
+
+	temp &= 0x07;
+	temp |= (temp << 4);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1d, temp);
+	SiS_SetSegmentReg(SiS_Pr, value);
+}
+
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+{
+	SiS_SetSegmentRegOver(SiS_Pr, 0);
+}
+
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+{
+	SiS_ResetSegmentReg(SiS_Pr);
+	SiS_ResetSegmentRegOver(SiS_Pr);
+}
+
+/*********************************************/
+/*           HELPER: SearchModeID            */
+/*********************************************/
+
+static int
+SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
+		 unsigned short *ModeIdIndex)
+{
+	if ((*ModeNo) <= 0x13) {
+
+		if ((*ModeNo) != 0x03)
+			return 0;
+
+		(*ModeIdIndex) = 0;
+
+	} else {
+
+		for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
+
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    (*ModeNo))
+				break;
+
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    0xFF)
+				return 0;
+		}
+
+	}
+
+	return 1;
+}
+
+/*********************************************/
+/*            HELPER: ENABLE CRT1            */
+/*********************************************/
+
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+{
+	/* Enable CRT1 gating */
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
+}
+
+/*********************************************/
+/*           HELPER: GetColorDepth           */
+/*********************************************/
+
+static unsigned short
+SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+		  unsigned short ModeIdIndex)
+{
+	static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
+	unsigned short modeflag;
+	short index;
+
+	if (ModeNo <= 0x13) {
+		modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	} else {
+		modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	}
+
+	index = (modeflag & ModeTypeMask) - ModeEGA;
+	if (index < 0)
+		index = 0;
+	return ColorDepth[index];
+}
+
+/*********************************************/
+/*             HELPER: GetOffset             */
+/*********************************************/
+
+static unsigned short
+SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+	      unsigned short ModeIdIndex, unsigned short rrti)
+{
+	unsigned short xres, temp, colordepth, infoflag;
+
+	infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+	xres = SiS_Pr->SiS_RefIndex[rrti].XRes;
+
+	colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex);
+
+	temp = xres / 16;
+
+	if (infoflag & InterlaceMode)
+		temp <<= 1;
+
+	temp *= colordepth;
+
+	if (xres % 16)
+		temp += (colordepth >> 1);
+
+	return temp;
+}
+
+/*********************************************/
+/*                   SEQ                     */
+/*********************************************/
+
+static void
+SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+	unsigned char SRdata;
+	int i;
+
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x00, 0x03);
+
+	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
+
+	for (i = 2; i <= 4; i++) {
+		SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
+	}
+}
+
+/*********************************************/
+/*                  MISC                     */
+/*********************************************/
+
+static void
+SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+	unsigned char Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
+
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, Miscdata);
+}
+
+/*********************************************/
+/*                  CRTC                     */
+/*********************************************/
+
+static void
+SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+	unsigned char CRTCdata;
+	unsigned short i;
+
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
+
+	for (i = 0; i <= 0x18; i++) {
+		CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
+	}
+}
+
+/*********************************************/
+/*                   ATT                     */
+/*********************************************/
+
+static void
+SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+	unsigned char ARdata;
+	unsigned short i;
+
+	for (i = 0; i <= 0x13; i++) {
+		ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
+		SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
+		SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
+		SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, ARdata);
+	}
+	SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x14);
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x00);
+
+	SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x20);
+	SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
+}
+
+/*********************************************/
+/*                   GRC                     */
+/*********************************************/
+
+static void
+SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+	unsigned char GRdata;
+	unsigned short i;
+
+	for (i = 0; i <= 0x08; i++) {
+		GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
+	}
+
+	if (SiS_Pr->SiS_ModeType > ModeVGA) {
+		/* 256 color disable */
+		SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3ce, 0x05, 0xBF);
+	}
+}
+
+/*********************************************/
+/*          CLEAR EXTENDED REGISTERS         */
+/*********************************************/
+
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+{
+	int i;
+
+	for (i = 0x0A; i <= 0x0E; i++) {
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
+	}
+
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x37, 0xFE);
+}
+
+/*********************************************/
+/*              Get rate index               */
+/*********************************************/
+
+static unsigned short
+SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+	       unsigned short ModeIdIndex)
+{
+	unsigned short rrti, i, index, temp;
+
+	if (ModeNo <= 0x13)
+		return 0xFFFF;
+
+	index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+	if (index > 0)
+		index--;
+
+	rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+	ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
+
+	i = 0;
+	do {
+		if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
+			break;
+
+		temp =
+		    SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+		if (temp < SiS_Pr->SiS_ModeType)
+			break;
+
+		i++;
+		index--;
+	} while (index != 0xFFFF);
+
+	i--;
+
+	return (rrti + i);
+}
+
+/*********************************************/
+/*                  SYNC                     */
+/*********************************************/
+
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+{
+	unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
+	sync &= 0xC0;
+	sync |= 0x2f;
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, sync);
+}
+
+/*********************************************/
+/*                  CRTC/2                   */
+/*********************************************/
+
+static void
+SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+		unsigned short ModeIdIndex, unsigned short rrti)
+{
+	unsigned char index;
+	unsigned short temp, i, j, modeflag;
+
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
+
+	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+
+	index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
+
+	for (i = 0, j = 0; i <= 7; i++, j++) {
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
+	}
+	for (j = 0x10; i <= 10; i++, j++) {
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
+	}
+	for (j = 0x15; i <= 12; i++, j++) {
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
+	}
+	for (j = 0x0A; i <= 15; i++, j++) {
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
+	}
+
+	temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
+
+	temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
+	if (modeflag & DoubleScanMode)
+		temp |= 0x80;
+	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
+
+	if (SiS_Pr->SiS_ModeType > ModeVGA)
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x14, 0x4F);
+}
+
+/*********************************************/
+/*               OFFSET & PITCH              */
+/*********************************************/
+/*  (partly overruled by SetPitch() in XF86) */
+/*********************************************/
+
+static void
+SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+		  unsigned short ModeIdIndex, unsigned short rrti)
+{
+	unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
+	unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+	unsigned short temp;
+
+	temp = (du >> 8) & 0x0f;
+	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, 0xF0, temp);
+
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
+
+	if (infoflag & InterlaceMode)
+		du >>= 1;
+
+	du <<= 5;
+	temp = (du >> 8) & 0xff;
+	if (du & 0xff)
+		temp++;
+	temp++;
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
+}
+
+/*********************************************/
+/*                  VCLK                     */
+/*********************************************/
+
+static void
+SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+		unsigned short rrti)
+{
+	unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
+	unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
+	unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
+
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
+
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
+}
+
+/*********************************************/
+/*                  FIFO                     */
+/*********************************************/
+
+static void
+SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+		    unsigned short mi)
+{
+	unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
+
+	/* disable auto-threshold */
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0xFE);
+
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0xAE);
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x09, 0xF0);
+
+	if (ModeNo <= 0x13)
+		return;
+
+	if ((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0x34);
+		SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0x01);
+	}
+}
+
+/*********************************************/
+/*              MODE REGISTERS               */
+/*********************************************/
+
+static void
+SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+		 unsigned short rrti)
+{
+	unsigned short data = 0, VCLK = 0, index = 0;
+
+	if (ModeNo > 0x13) {
+		index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
+		VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
+	}
+
+	if (VCLK >= 166)
+		data |= 0x0c;
+	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
+
+	if (VCLK >= 166)
+		SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1f, 0xe7);
+
+	/* DAC speed */
+	data = 0x03;
+	if (VCLK >= 260)
+		data = 0x00;
+	else if (VCLK >= 160)
+		data = 0x01;
+	else if (VCLK >= 135)
+		data = 0x02;
+
+	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x07, 0xF8, data);
+}
+
+static void
+SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+		    unsigned short ModeIdIndex, unsigned short rrti)
+{
+	unsigned short data, infoflag = 0, modeflag;
+
+	if (ModeNo <= 0x13)
+		modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	else {
+		modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+		infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+	}
+
+	/* Disable DPMS */
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1F, 0x3F);
+
+	data = 0;
+	if (ModeNo > 0x13) {
+		if (SiS_Pr->SiS_ModeType > ModeEGA) {
+			data |= 0x02;
+			data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
+		}
+		if (infoflag & InterlaceMode)
+			data |= 0x20;
+	}
+	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
+
+	data = 0;
+	if (infoflag & InterlaceMode) {
+		/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
+		unsigned short hrs =
+		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+		    - 3;
+		unsigned short hto =
+		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+		    + 5;
+		data = hrs - (hto >> 1) + 3;
+	}
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
+	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x1a, 0xFC, (data >> 8));
+
+	if (modeflag & HalfDCLK)
+		SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0x08);
+
+	data = 0;
+	if (modeflag & LineCompareOff)
+		data = 0x08;
+	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0xB7, data);
+
+	if ((SiS_Pr->SiS_ModeType == ModeEGA) && (ModeNo > 0x13))
+		SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0x40);
+
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xfb);
+
+	data = 0x60;
+	if (SiS_Pr->SiS_ModeType != ModeText) {
+		data ^= 0x60;
+		if (SiS_Pr->SiS_ModeType != ModeEGA)
+			data ^= 0xA0;
+	}
+	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x21, 0x1F, data);
+
+	SiS_SetVCLKState(SiS_Pr, ModeNo, rrti);
+
+	if (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x31) & 0x40)
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x2c);
+	else
+		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x6c);
+}
+
+/*********************************************/
+/*                 LOAD DAC                  */
+/*********************************************/
+
+static void
+SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
+	     unsigned short shiftflag, unsigned short dl, unsigned short ah,
+	     unsigned short al, unsigned short dh)
+{
+	unsigned short d1, d2, d3;
+
+	switch (dl) {
+	case 0:
+		d1 = dh;
+		d2 = ah;
+		d3 = al;
+		break;
+	case 1:
+		d1 = ah;
+		d2 = al;
+		d3 = dh;
+		break;
+	default:
+		d1 = al;
+		d2 = dh;
+		d3 = ah;
+	}
+	SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
+	SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
+	SiS_SetRegByte(SiS_Pr, DACData, (d3 << shiftflag));
+}
+
+static void
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+	    unsigned short mi)
+{
+	unsigned short data, data2, time, i, j, k, m, n, o;
+	unsigned short si, di, bx, sf;
+	unsigned long DACAddr, DACData;
+	const unsigned char *table = NULL;
+
+	if (ModeNo < 0x13)
+		data = SiS_Pr->SiS_SModeIDTable[mi].St_ModeFlag;
+	else
+		data = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
+
+	data &= DACInfoFlag;
+
+	j = time = 64;
+	if (data == 0x00)
+		table = SiS_MDA_DAC;
+	else if (data == 0x08)
+		table = SiS_CGA_DAC;
+	else if (data == 0x10)
+		table = SiS_EGA_DAC;
+	else {
+		j = 16;
+		time = 256;
+		table = SiS_VGA_DAC;
+	}
+
+	DACAddr = SiS_Pr->SiS_P3c8;
+	DACData = SiS_Pr->SiS_P3c9;
+	sf = 0;
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
+
+	SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
+
+	for (i = 0; i < j; i++) {
+		data = table[i];
+		for (k = 0; k < 3; k++) {
+			data2 = 0;
+			if (data & 0x01)
+				data2 += 0x2A;
+			if (data & 0x02)
+				data2 += 0x15;
+			SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
+			data >>= 2;
+		}
+	}
+
+	if (time == 256) {
+		for (i = 16; i < 32; i++) {
+			data = table[i] << sf;
+			for (k = 0; k < 3; k++)
+				SiS_SetRegByte(SiS_Pr, DACData, data);
+		}
+		si = 32;
+		for (m = 0; m < 9; m++) {
+			di = si;
+			bx = si + 4;
+			for (n = 0; n < 3; n++) {
+				for (o = 0; o < 5; o++) {
+					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
+						     table[di], table[bx],
+						     table[si]);
+					si++;
+				}
+				si -= 2;
+				for (o = 0; o < 3; o++) {
+					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
+						     table[di], table[si],
+						     table[bx]);
+					si--;
+				}
+			}
+			si += 5;
+		}
+	}
+}
+
+/*********************************************/
+/*         SET CRT1 REGISTER GROUP           */
+/*********************************************/
+
+static void
+SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+		 unsigned short ModeIdIndex)
+{
+	unsigned short StandTableIndex, rrti;
+
+	SiS_Pr->SiS_CRT1Mode = ModeNo;
+
+	if (ModeNo <= 0x13)
+		StandTableIndex = 0;
+	else
+		StandTableIndex = 1;
+
+	SiS_ResetSegmentRegisters(SiS_Pr);
+	SiS_SetSeqRegs(SiS_Pr, StandTableIndex);
+	SiS_SetMiscRegs(SiS_Pr, StandTableIndex);
+	SiS_SetCRTCRegs(SiS_Pr, StandTableIndex);
+	SiS_SetATTRegs(SiS_Pr, StandTableIndex);
+	SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
+	SiS_ClearExt1Regs(SiS_Pr, ModeNo);
+
+	rrti = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex);
+
+	if (rrti != 0xFFFF) {
+		SiS_SetCRT1Sync(SiS_Pr, rrti);
+		SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, rrti);
+		SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
+		SiS_SetCRT1VCLK(SiS_Pr, ModeNo, rrti);
+	}
+
+	SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex);
+
+	SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, rrti);
+
+	SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex);
+
+	SiS_DisplayOn(SiS_Pr);
+}
+
+/*********************************************/
+/*                 SiSSetMode()              */
+/*********************************************/
+
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+{
+	unsigned short ModeIdIndex;
+	unsigned long BaseAddr = SiS_Pr->IOAddress;
+
+	SiSUSB_InitPtr(SiS_Pr);
+	SiSUSBRegInit(SiS_Pr, BaseAddr);
+	SiS_GetSysFlags(SiS_Pr);
+
+	if (!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex)))
+		return 0;
+
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x05, 0x86);
+
+	SiSInitPCIetc(SiS_Pr);
+
+	ModeNo &= 0x7f;
+
+	SiS_Pr->SiS_ModeType =
+	    SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+
+	SiS_Pr->SiS_SetFlag = LowModeTests;
+
+	/* Set mode on CRT1 */
+	SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
+
+	SiS_HandleCRT1(SiS_Pr);
+
+	SiS_DisplayOn(SiS_Pr);
+	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
+
+	/* Store mode number */
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x34, ModeNo);
+
+	return 1;
+}
+
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+{
+	unsigned short ModeNo = 0;
+	int i;
+
+	SiSUSB_InitPtr(SiS_Pr);
+
+	if (VModeNo == 0x03) {
+
+		ModeNo = 0x03;
+
+	} else {
+
+		i = 0;
+		do {
+
+			if (SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID == VModeNo) {
+				ModeNo = SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID;
+				break;
+			}
+
+		} while (SiS_Pr->SiS_EModeIDTable[i++].Ext_ModeID != 0xff);
+
+	}
+
+	if (!ModeNo)
+		return 0;
+
+	return SiSUSBSetMode(SiS_Pr, ModeNo);
+}
+
+#endif /* INCL_SISUSB_CON */
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
new file mode 100644
index 0000000..c46ce42
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -0,0 +1,841 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Data and prototypes for init.c
+ *
+ * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * 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 named License,
+ * * or 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
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _SISUSB_INIT_H_
+#define _SISUSB_INIT_H_
+
+/* SiS_ModeType */
+#define ModeText		0x00
+#define ModeCGA			0x01
+#define ModeEGA			0x02
+#define ModeVGA			0x03
+#define Mode15Bpp		0x04
+#define Mode16Bpp		0x05
+#define Mode24Bpp		0x06
+#define Mode32Bpp		0x07
+
+#define ModeTypeMask		0x07
+#define IsTextMode		0x07
+
+#define DACInfoFlag		0x0018
+#define MemoryInfoFlag		0x01E0
+#define MemorySizeShift		5
+
+/* modeflag */
+#define Charx8Dot		0x0200
+#define LineCompareOff		0x0400
+#define CRT2Mode		0x0800
+#define HalfDCLK		0x1000
+#define NoSupportSimuTV		0x2000
+#define NoSupportLCDScale	0x4000	/* SiS bridge: No scaling possible (no matter what panel) */
+#define DoubleScanMode		0x8000
+
+/* Infoflag */
+#define SupportTV		0x0008
+#define SupportTV1024		0x0800
+#define SupportCHTV		0x0800
+#define Support64048060Hz	0x0800	/* Special for 640x480 LCD */
+#define SupportHiVision		0x0010
+#define SupportYPbPr750p	0x1000
+#define SupportLCD		0x0020
+#define SupportRAMDAC2		0x0040	/* All           (<= 100Mhz) */
+#define SupportRAMDAC2_135	0x0100	/* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162	0x0200	/* B, C          (<= 162Mhz) */
+#define SupportRAMDAC2_202	0x0400	/* C             (<= 202Mhz) */
+#define InterlaceMode		0x0080
+#define SyncPP			0x0000
+#define SyncPN			0x4000
+#define SyncNP			0x8000
+#define SyncNN			0xc000
+
+/* SetFlag */
+#define ProgrammingCRT2		0x0001
+#define LowModeTests		0x0002
+#define LCDVESATiming		0x0008
+#define EnableLVDSDDA		0x0010
+#define SetDispDevSwitchFlag	0x0020
+#define CheckWinDos		0x0040
+#define SetDOSMode		0x0080
+
+/* Index in ModeResInfo table */
+#define SIS_RI_320x200		0
+#define SIS_RI_320x240		1
+#define SIS_RI_320x400		2
+#define SIS_RI_400x300		3
+#define SIS_RI_512x384		4
+#define SIS_RI_640x400		5
+#define SIS_RI_640x480		6
+#define SIS_RI_800x600		7
+#define SIS_RI_1024x768		8
+#define SIS_RI_1280x1024	9
+#define SIS_RI_1600x1200	10
+#define SIS_RI_1920x1440	11
+#define SIS_RI_2048x1536	12
+#define SIS_RI_720x480		13
+#define SIS_RI_720x576		14
+#define SIS_RI_1280x960		15
+#define SIS_RI_800x480		16
+#define SIS_RI_1024x576		17
+#define SIS_RI_1280x720		18
+#define SIS_RI_856x480		19
+#define SIS_RI_1280x768		20
+#define SIS_RI_1400x1050	21
+#define SIS_RI_1152x864		22	/* Up to here SiS conforming */
+#define SIS_RI_848x480		23
+#define SIS_RI_1360x768		24
+#define SIS_RI_1024x600		25
+#define SIS_RI_1152x768		26
+#define SIS_RI_768x576		27
+#define SIS_RI_1360x1024	28
+#define SIS_RI_1680x1050	29
+#define SIS_RI_1280x800		30
+#define SIS_RI_1920x1080	31
+#define SIS_RI_960x540		32
+#define SIS_RI_960x600		33
+
+#define SIS_VIDEO_CAPTURE	0x00 - 0x30
+#define SIS_VIDEO_PLAYBACK	0x02 - 0x30
+#define SIS_CRT2_PORT_04	0x04 - 0x30
+
+/* Mode numbers */
+static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f };
+static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 };
+static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 };
+static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c };
+static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e };
+static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 };
+static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 };
+static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 };
+static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 };
+static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 };
+static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 };
+static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e };
+static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 };
+static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f };
+static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 };
+static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 };
+static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 };
+static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b };
+static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 };
+static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 };
+static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 };
+
+static const unsigned char SiS_MDA_DAC[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
+};
+
+static const unsigned char SiS_CGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
+};
+
+static const unsigned char SiS_EGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+	0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+	0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+	0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+	0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+	0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+	0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
+};
+
+static const unsigned char SiS_VGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+	0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+	0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+	0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+	0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+	0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+	0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+	0x0B, 0x0C, 0x0D, 0x0F, 0x10
+};
+
+static const struct SiS_St SiSUSB_SModeIDTable[] = {
+	{0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40},
+	{0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = {
+	{640, 400},
+	{640, 350},
+	{720, 400},
+	{720, 350},
+	{640, 480}
+};
+
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = {
+	{320, 200, 8, 8},	/* 0x00 */
+	{320, 240, 8, 8},	/* 0x01 */
+	{320, 400, 8, 8},	/* 0x02 */
+	{400, 300, 8, 8},	/* 0x03 */
+	{512, 384, 8, 8},	/* 0x04 */
+	{640, 400, 8, 16},	/* 0x05 */
+	{640, 480, 8, 16},	/* 0x06 */
+	{800, 600, 8, 16},	/* 0x07 */
+	{1024, 768, 8, 16},	/* 0x08 */
+	{1280, 1024, 8, 16},	/* 0x09 */
+	{1600, 1200, 8, 16},	/* 0x0a */
+	{1920, 1440, 8, 16},	/* 0x0b */
+	{2048, 1536, 8, 16},	/* 0x0c */
+	{720, 480, 8, 16},	/* 0x0d */
+	{720, 576, 8, 16},	/* 0x0e */
+	{1280, 960, 8, 16},	/* 0x0f */
+	{800, 480, 8, 16},	/* 0x10 */
+	{1024, 576, 8, 16},	/* 0x11 */
+	{1280, 720, 8, 16},	/* 0x12 */
+	{856, 480, 8, 16},	/* 0x13 */
+	{1280, 768, 8, 16},	/* 0x14 */
+	{1400, 1050, 8, 16},	/* 0x15 */
+	{1152, 864, 8, 16},	/* 0x16 */
+	{848, 480, 8, 16},	/* 0x17 */
+	{1360, 768, 8, 16},	/* 0x18 */
+	{1024, 600, 8, 16},	/* 0x19 */
+	{1152, 768, 8, 16},	/* 0x1a */
+	{768, 576, 8, 16},	/* 0x1b */
+	{1360, 1024, 8, 16},	/* 0x1c */
+	{1680, 1050, 8, 16},	/* 0x1d */
+	{1280, 800, 8, 16},	/* 0x1e */
+	{1920, 1080, 8, 16},	/* 0x1f */
+	{960, 540, 8, 16},	/* 0x20 */
+	{960, 600, 8, 16}	/* 0x21 */
+};
+
+static const struct SiS_StandTable SiSUSB_StandTable[] = {
+	/* MD_3_400 - mode 0x03 - 400 */
+	{
+	 0x50, 0x18, 0x10, 0x1000,
+	 {0x00, 0x03, 0x00, 0x02},
+	 0x67,
+	 {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+	  0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	  0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+	  0xff},
+	 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+	  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+	  0x0c, 0x00, 0x0f, 0x08},
+	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff}
+	 },
+	/* Generic for VGA and higher */
+	{
+	 0x00, 0x00, 0x00, 0x0000,
+	 {0x01, 0x0f, 0x00, 0x0e},
+	 0x23,
+	 {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+	  0xff},
+	 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	  0x01, 0x00, 0x00, 0x00},
+	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff}
+	 }
+};
+
+static const struct SiS_Ext SiSUSB_EModeIDTable[] = {
+	{0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x8 */
+	{0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0},	/* 640x400x8 */
+	{0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x8 */
+	{0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x8 */
+	{0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x8 */
+	{0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x16 */
+	{0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x16 */
+	{0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x32 */
+	{0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x32 */
+	{0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x8 */
+	{0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x8 */
+	{0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x16 */
+	{0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x16 */
+	{0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x16 */
+	{0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x16 */
+	{0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x16 */
+	{0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x8  */
+	{0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x8  */
+	{0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x8  */
+	{0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x16 */
+	{0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x16 */
+	{0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x16 */
+	{0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x8  */
+	{0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x32 */
+	{0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},	/* 640x400x16 */
+	{0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},	/* 640x400x32 */
+	{0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x32 */
+	{0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x32 */
+	{0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x32 */
+	{0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x32 */
+	{0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x8 */
+	{0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x8 */
+	{0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x16 */
+	{0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x16 */
+	{0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x32 */
+	{0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x32 */
+	{0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x32 */
+	{0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x8 */
+	{0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x16 */
+	{0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x8 */
+	{0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x16 */
+	{0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x32 */
+	{0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1},	/* 848x480 */
+	{0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+	 -1},
+	{0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+	 -1},
+	{0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1},	/* 856x480 */
+	{0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+	 -1},
+	{0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+	 -1},
+	{0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x32 */
+	{0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x32 */
+	{0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x32 */
+	{0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1},	/* 768x576 */
+	{0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+	 -1},
+	{0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+	 -1},
+	{0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1},	/* 960x540 */
+	{0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+	 -1},
+	{0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+	 -1},
+	{0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1},	/* 960x600 */
+	{0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+	 -1},
+	{0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+	 -1},
+	{0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1},	/* 1152x864 */
+	{0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+	 -1},
+	{0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+	 -1},
+	{0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1}
+};
+
+static const struct SiS_Ext2 SiSUSB_RefIndex[] = {
+	{0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x0 */
+	{0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x1 */
+	{0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x2 */
+	{0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x3 */
+	{0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x4 */
+	{0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x5 */
+	{0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},	/* 0x6 */
+	{0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},	/* 0x7 */
+	{0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0x8 */
+	{0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0x9 */
+	{0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xa */
+	{0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xb */
+	{0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xc */
+	{0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xd */
+	{0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xe */
+	{0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xf */
+	{0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e},	/* 0x10 */
+	{0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00},	/* 0x11 */
+	{0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00},	/* 0x12 (6f was 03) */
+	{0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00},	/* 0x13 */
+	{0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x14 */
+	{0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x15 */
+	{0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x16 */
+	{0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x17 */
+	{0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},	/* 0x18 */
+	{0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},	/* 0x19 */
+	{0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e},	/* 0x1a */
+	{0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00},	/* 0x1b */
+	{0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00},	/* 0x1c */
+	{0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00},	/* 0x1d */
+	{0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x1e */
+	{0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x1f */
+	{0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x20 */
+	{0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x21 */
+	{0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x22 */
+	{0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x23 */
+	{0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x24 */
+	{0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x25 */
+	{0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x26 */
+	{0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00},	/* 0x27 */
+	{0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},	/* 0x28 38Hzi  */
+	{0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},	/* 0x29 848x480-60Hz   */
+	{0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},	/* 0x2a 856x480-38Hzi  */
+	{0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},	/* 0x2b 856x480-60Hz   */
+	{0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00},	/* 0x2c 768x576-56Hz   */
+	{0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00},	/* 0x2d 960x540 60Hz */
+	{0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00},	/* 0x2e 960x600 60Hz */
+	{0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00},	/* 0x2f */
+	{0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x30 */
+	{0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x31 */
+	{0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x32 */
+	{0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x33 1152x864-60Hz  */
+	{0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x34 1152x864-75Hz  */
+	{0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x35 1152x864-85Hz  */
+	{0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00}
+};
+
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = {
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
+	  0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00,
+	  0x00}},		/* 0x0 */
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+	  0x00}},		/* 0x1 */
+	{{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0,
+	  0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05,
+	  0x01}},		/* 0x2 */
+	{{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01,
+	  0x01}},		/* 0x3 */
+	{{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+	  0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05,
+	  0x00}},		/* 0x4 */
+	{{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
+	  0x00}},		/* 0x5 */
+	{{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e,
+	  0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01,
+	  0x00}},		/* 0x6 */
+	{{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01,
+	  0x00}},		/* 0x7 */
+	{{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+	  0x00}},		/* 0x8 */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+	  0x61}},		/* 0x9 */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e,
+	  0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05,
+	  0x61}},		/* 0xa */
+	{{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e,
+	  0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05,
+	  0x61}},		/* 0xb */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f,
+	  0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01,
+	  0x00}},		/* 0xc */
+	{{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0,
+	  0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05,
+	  0x01}},		/* 0xd */
+	{{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0,
+	  0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0xe */
+	{{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0,
+	  0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0xf */
+	{{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0x10 */
+	{{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0x11 */
+	{{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x12 */
+	{{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x13 */
+	{{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x14 */
+	{{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f,
+	  0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02,
+	  0x00}},		/* 0x15 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x16 */
+	{{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x17 */
+	{{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x18 */
+	{{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x19 */
+	{{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02,
+	  0x62}},		/* 0x1a */
+	{{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02,
+	  0x62}},		/* 0x1b */
+	{{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03,
+	  0x00}},		/* 0x1c */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1d */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1e */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1f */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x20 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x21 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x22 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x23 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x24 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x25 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x26 */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x27 */
+	{{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05,
+	  0x63}},		/* 0x28 */
+	{{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05,
+	  0x63}},		/* 0x29 */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2a */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2b */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2c */
+	{{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2d */
+	{{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2e */
+	{{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2f */
+	{{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba,
+	  0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x30 */
+	{{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba,
+	  0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05,
+	  0x00}},		/* 0x31 */
+	{{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba,
+	  0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x32 */
+	{{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba,
+	  0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x33 */
+	{{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba,
+	  0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x34 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1,
+	  0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x35 */
+	{{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1,
+	  0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x36 */
+	{{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1,
+	  0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x37 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4,
+	  0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x38 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4,
+	  0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x39 */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4,
+	  0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x3a */
+	{{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff,
+	  0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x3b */
+	{{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05,
+	  0x00}},		/* 0x3c */
+	{{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0,
+	  0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+	  0x41}},		/* 0x3d */
+	{{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15,
+	  0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x3e */
+	{{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e,
+	  0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02,
+	  0x00}},		/* 0x3f */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1,
+	  0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x40 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x41 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5,
+	  0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x42 */
+	{{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10,
+	  0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03,
+	  0x00}},		/* 0x43 */
+	{{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef,
+	  0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x44 */
+	{{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+	  0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x45 */
+	{{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E,
+	  0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06,
+	  0x00}},		/* 0x46 */
+	{{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+	  0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x47 */
+	{{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E,
+	  0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02,
+	  0x00}},		/* 0x48 */
+	{{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd,
+	  0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03,
+	  0x01}},		/* 0x49 */
+	{{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff,
+	  0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03,
+	  0x01}},		/* 0x4a */
+	{{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10,
+	  0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03,
+	  0x00}},		/* 0x4b */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff,
+	  0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x4c */
+	{{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0,
+	  0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+	  0x41}},
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+	  0x00}},		/* 0x4e */
+	{{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff,
+	  0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07,
+	  0x21}},		/* 0x4f */
+	{{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10,
+	  0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c,
+	  0x20}},		/* 0x50 */
+	{{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0,
+	  0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00,
+	  0x61}},		/* 0x51 */
+	{{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0,
+	  0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02,
+	  0x41}},		/* 0x52 */
+	{{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0,
+	  0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02,
+	  0x01}},		/* 0x53 */
+	{{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff,
+	  0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07,
+	  0x41}}		/* 0x54 */
+};
+
+static const struct SiS_VCLKData SiSUSB_VCLKData[] = {
+	{0x1b, 0xe1, 25},	/* 0x00 */
+	{0x4e, 0xe4, 28},	/* 0x01 */
+	{0x57, 0xe4, 31},	/* 0x02 */
+	{0xc3, 0xc8, 36},	/* 0x03 */
+	{0x42, 0xe2, 40},	/* 0x04 */
+	{0xfe, 0xcd, 43},	/* 0x05 */
+	{0x5d, 0xc4, 44},	/* 0x06 */
+	{0x52, 0xe2, 49},	/* 0x07 */
+	{0x53, 0xe2, 50},	/* 0x08 */
+	{0x74, 0x67, 52},	/* 0x09 */
+	{0x6d, 0x66, 56},	/* 0x0a */
+	{0x5a, 0x64, 65},	/* 0x0b */
+	{0x46, 0x44, 67},	/* 0x0c */
+	{0xb1, 0x46, 68},	/* 0x0d */
+	{0xd3, 0x4a, 72},	/* 0x0e */
+	{0x29, 0x61, 75},	/* 0x0f */
+	{0x6e, 0x46, 76},	/* 0x10 */
+	{0x2b, 0x61, 78},	/* 0x11 */
+	{0x31, 0x42, 79},	/* 0x12 */
+	{0xab, 0x44, 83},	/* 0x13 */
+	{0x46, 0x25, 84},	/* 0x14 */
+	{0x78, 0x29, 86},	/* 0x15 */
+	{0x62, 0x44, 94},	/* 0x16 */
+	{0x2b, 0x41, 104},	/* 0x17 */
+	{0x3a, 0x23, 105},	/* 0x18 */
+	{0x70, 0x44, 108},	/* 0x19 */
+	{0x3c, 0x23, 109},	/* 0x1a */
+	{0x5e, 0x43, 113},	/* 0x1b */
+	{0xbc, 0x44, 116},	/* 0x1c */
+	{0xe0, 0x46, 132},	/* 0x1d */
+	{0x54, 0x42, 135},	/* 0x1e */
+	{0xea, 0x2a, 139},	/* 0x1f */
+	{0x41, 0x22, 157},	/* 0x20 */
+	{0x70, 0x24, 162},	/* 0x21 */
+	{0x30, 0x21, 175},	/* 0x22 */
+	{0x4e, 0x22, 189},	/* 0x23 */
+	{0xde, 0x26, 194},	/* 0x24 */
+	{0x62, 0x06, 202},	/* 0x25 */
+	{0x3f, 0x03, 229},	/* 0x26 */
+	{0xb8, 0x06, 234},	/* 0x27 */
+	{0x34, 0x02, 253},	/* 0x28 */
+	{0x58, 0x04, 255},	/* 0x29 */
+	{0x24, 0x01, 265},	/* 0x2a */
+	{0x9b, 0x02, 267},	/* 0x2b */
+	{0x70, 0x05, 270},	/* 0x2c */
+	{0x25, 0x01, 272},	/* 0x2d */
+	{0x9c, 0x02, 277},	/* 0x2e */
+	{0x27, 0x01, 286},	/* 0x2f */
+	{0x3c, 0x02, 291},	/* 0x30 */
+	{0xef, 0x0a, 292},	/* 0x31 */
+	{0xf6, 0x0a, 310},	/* 0x32 */
+	{0x95, 0x01, 315},	/* 0x33 */
+	{0xf0, 0x09, 324},	/* 0x34 */
+	{0xfe, 0x0a, 331},	/* 0x35 */
+	{0xf3, 0x09, 332},	/* 0x36 */
+	{0xea, 0x08, 340},	/* 0x37 */
+	{0xe8, 0x07, 376},	/* 0x38 */
+	{0xde, 0x06, 389},	/* 0x39 */
+	{0x52, 0x2a, 54},	/* 0x3a 301 TV */
+	{0x52, 0x6a, 27},	/* 0x3b 301 TV */
+	{0x62, 0x24, 70},	/* 0x3c 301 TV */
+	{0x62, 0x64, 70},	/* 0x3d 301 TV */
+	{0xa8, 0x4c, 30},	/* 0x3e 301 TV */
+	{0x20, 0x26, 33},	/* 0x3f 301 TV */
+	{0x31, 0xc2, 39},	/* 0x40 */
+	{0x60, 0x36, 30},	/* 0x41 Chrontel */
+	{0x40, 0x4a, 28},	/* 0x42 Chrontel */
+	{0x9f, 0x46, 44},	/* 0x43 Chrontel */
+	{0x97, 0x2c, 26},	/* 0x44 */
+	{0x44, 0xe4, 25},	/* 0x45 Chrontel */
+	{0x7e, 0x32, 47},	/* 0x46 Chrontel */
+	{0x8a, 0x24, 31},	/* 0x47 Chrontel */
+	{0x97, 0x2c, 26},	/* 0x48 Chrontel */
+	{0xce, 0x3c, 39},	/* 0x49 */
+	{0x52, 0x4a, 36},	/* 0x4a Chrontel */
+	{0x34, 0x61, 95},	/* 0x4b */
+	{0x78, 0x27, 108},	/* 0x4c - was 102 */
+	{0x66, 0x43, 123},	/* 0x4d Modes 0x26-0x28 (1400x1050) */
+	{0x41, 0x4e, 21},	/* 0x4e */
+	{0xa1, 0x4a, 29},	/* 0x4f Chrontel */
+	{0x19, 0x42, 42},	/* 0x50 */
+	{0x54, 0x46, 58},	/* 0x51 Chrontel */
+	{0x25, 0x42, 61},	/* 0x52 */
+	{0x44, 0x44, 66},	/* 0x53 Chrontel */
+	{0x3a, 0x62, 70},	/* 0x54 Chrontel */
+	{0x62, 0xc6, 34},	/* 0x55 848x480-60 */
+	{0x6a, 0xc6, 37},	/* 0x56 848x480-75 - TEMP */
+	{0xbf, 0xc8, 35},	/* 0x57 856x480-38i,60 */
+	{0x30, 0x23, 88},	/* 0x58 1360x768-62 (is 60Hz!) */
+	{0x52, 0x07, 149},	/* 0x59 1280x960-85 */
+	{0x56, 0x07, 156},	/* 0x5a 1400x1050-75 */
+	{0x70, 0x29, 81},	/* 0x5b 1280x768 LCD */
+	{0x45, 0x25, 83},	/* 0x5c 1280x800  */
+	{0x70, 0x0a, 147},	/* 0x5d 1680x1050 */
+	{0x70, 0x24, 162},	/* 0x5e 1600x1200 */
+	{0x5a, 0x64, 65},	/* 0x5f 1280x720 - temp */
+	{0x63, 0x46, 68},	/* 0x60 1280x768_2 */
+	{0x31, 0x42, 79},	/* 0x61 1280x768_3 - temp */
+	{0, 0, 0},		/* 0x62 - custom (will be filled out at run-time) */
+	{0x5a, 0x64, 65},	/* 0x63 1280x720 (LCD LVDS) */
+	{0x70, 0x28, 90},	/* 0x64 1152x864@60 */
+	{0x41, 0xc4, 32},	/* 0x65 848x480@60 */
+	{0x5c, 0xc6, 32},	/* 0x66 856x480@60 */
+	{0x76, 0xe7, 27},	/* 0x67 720x480@60 */
+	{0x5f, 0xc6, 33},	/* 0x68 720/768x576@60 */
+	{0x52, 0x27, 75},	/* 0x69 1920x1080i 60Hz interlaced */
+	{0x7c, 0x6b, 38},	/* 0x6a 960x540@60 */
+	{0xe3, 0x56, 41},	/* 0x6b 960x600@60 */
+	{0x45, 0x25, 83},	/* 0x6c 1280x800 */
+	{0x70, 0x28, 90},	/* 0x6d 1152x864@60 */
+	{0x15, 0xe1, 20},	/* 0x6e 640x400@60 (fake, not actually used) */
+	{0x5f, 0xc6, 33},	/* 0x6f 720x576@60 */
+	{0x37, 0x5a, 10},	/* 0x70 320x200@60 (fake, not actually used) */
+	{0x2b, 0xc2, 35}	/* 0x71 768@576@60 */
+};
+
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+			    u8 index, u8 data);
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+			    u8 index, u8 * data);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+				 u8 idx, u8 myand, u8 myor);
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+			      u8 index, u8 myor);
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+			       u8 idx, u8 myand);
+
+void sisusb_delete(struct kref *kref);
+int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
+int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
+		       u32 dest, int length, size_t * bytes_written);
+int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
+int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
+			 u8 * arg, int cmapsz, int ch512, int dorecalc,
+			 struct vc_data *c, int fh, int uplock);
+void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
+int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
+void sisusb_console_exit(struct sisusb_usb_data *sisusb);
+void sisusb_init_concode(void);
+
+#endif
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h
new file mode 100644
index 0000000..1c4240e
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h
@@ -0,0 +1,161 @@
+/*
+ * General structure definitions for universal mode switching modules
+ *
+ * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * 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 named License,
+ * * or 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
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _SISUSB_STRUCT_H_
+#define _SISUSB_STRUCT_H_
+
+struct SiS_St {
+	unsigned char St_ModeID;
+	unsigned short St_ModeFlag;
+	unsigned char St_StTableIndex;
+	unsigned char St_CRT2CRTC;
+	unsigned char St_ResInfo;
+	unsigned char VB_StTVFlickerIndex;
+	unsigned char VB_StTVEdgeIndex;
+	unsigned char VB_StTVYFilterIndex;
+	unsigned char St_PDC;
+};
+
+struct SiS_StandTable {
+	unsigned char CRT_COLS;
+	unsigned char ROWS;
+	unsigned char CHAR_HEIGHT;
+	unsigned short CRT_LEN;
+	unsigned char SR[4];
+	unsigned char MISC;
+	unsigned char CRTC[0x19];
+	unsigned char ATTR[0x14];
+	unsigned char GRC[9];
+};
+
+struct SiS_StResInfo_S {
+	unsigned short HTotal;
+	unsigned short VTotal;
+};
+
+struct SiS_Ext {
+	unsigned char Ext_ModeID;
+	unsigned short Ext_ModeFlag;
+	unsigned short Ext_VESAID;
+	unsigned char Ext_RESINFO;
+	unsigned char VB_ExtTVFlickerIndex;
+	unsigned char VB_ExtTVEdgeIndex;
+	unsigned char VB_ExtTVYFilterIndex;
+	unsigned char VB_ExtTVYFilterIndexROM661;
+	unsigned char REFindex;
+	char ROMMODEIDX661;
+};
+
+struct SiS_Ext2 {
+	unsigned short Ext_InfoFlag;
+	unsigned char Ext_CRT1CRTC;
+	unsigned char Ext_CRTVCLK;
+	unsigned char Ext_CRT2CRTC;
+	unsigned char Ext_CRT2CRTC_NS;
+	unsigned char ModeID;
+	unsigned short XRes;
+	unsigned short YRes;
+	unsigned char Ext_PDC;
+	unsigned char Ext_FakeCRT2CRTC;
+	unsigned char Ext_FakeCRT2Clk;
+};
+
+struct SiS_CRT1Table {
+	unsigned char CR[17];
+};
+
+struct SiS_VCLKData {
+	unsigned char SR2B, SR2C;
+	unsigned short CLOCK;
+};
+
+struct SiS_ModeResInfo {
+	unsigned short HTotal;
+	unsigned short VTotal;
+	unsigned char XChar;
+	unsigned char YChar;
+};
+
+struct SiS_Private {
+	void *sisusb;
+
+	unsigned long IOAddress;
+
+	unsigned long SiS_P3c4;
+	unsigned long SiS_P3d4;
+	unsigned long SiS_P3c0;
+	unsigned long SiS_P3ce;
+	unsigned long SiS_P3c2;
+	unsigned long SiS_P3ca;
+	unsigned long SiS_P3c6;
+	unsigned long SiS_P3c7;
+	unsigned long SiS_P3c8;
+	unsigned long SiS_P3c9;
+	unsigned long SiS_P3cb;
+	unsigned long SiS_P3cc;
+	unsigned long SiS_P3cd;
+	unsigned long SiS_P3da;
+	unsigned long SiS_Part1Port;
+
+	unsigned char SiS_MyCR63;
+	unsigned short SiS_CRT1Mode;
+	unsigned short SiS_ModeType;
+	unsigned short SiS_SetFlag;
+
+	const struct SiS_StandTable *SiS_StandTable;
+	const struct SiS_St *SiS_SModeIDTable;
+	const struct SiS_Ext *SiS_EModeIDTable;
+	const struct SiS_Ext2 *SiS_RefIndex;
+	const struct SiS_CRT1Table *SiS_CRT1Table;
+	const struct SiS_VCLKData *SiS_VCLKData;
+	const struct SiS_ModeResInfo *SiS_ModeResInfo;
+};
+
+#endif