Commit 1bbb4f20 authored by Thomas Winischhofer's avatar Thomas Winischhofer Committed by Greg Kroah-Hartman

[PATCH] USB: sisusb[vga] update

here is a new and extended version of the sisusbvga (previously: sisusb)
driver. The patch is against 2.6.13 and updates the driver to version 0.0.8.

Additions include complete VGA/EGA text console support and a build-in
display mode infrastructure for userland applications that don't know
 about the graphics internals.

Fixes include some BE/LE issues and a get/put_dev bug in the previous
version.

Other changes include a change of the module name from "sisusb" to
"sisusbvga". The previous one was too generic IMHO.

Please note that the patch also affects the Makefile in
drivers/video/console as the driver requires the VGA 8x16 font in case
the text console part is selected.

Heavily tested, as usual. Please apply.

One thing though: I already prepared for removal of the "mode" field and
the changed "name" field in the usb_class_driver structure. This will
perhaps need some refinement depending on whether you/Linus merge the
respective core changes before or after 2.6.14.
Signed-off-by: default avatarThomas Winischhofer <thomas@winischhofer.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 80908309
......@@ -9,6 +9,38 @@ config USB_SISUSBVGA
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 sisusb. If unsure, say N.
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
......@@ -2,5 +2,7 @@
# Makefile for the sisusb driver (if driver is inside kernel tree).
#
obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o
sisusbvga-objs := sisusb.o sisusb_init.o sisusb_con.o
/*
* 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
......@@ -48,16 +50,60 @@
#include <linux/kref.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include "sisusb.h"
#ifdef INCL_SISUSB_CON
#include <linux/font.h>
#endif
#define SISUSB_DONTSYNC
/* Forward declarations / clean-up routines */
#ifdef INCL_SISUSB_CON
int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data);
int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data);
int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor);
int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor);
int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand);
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_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *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);
extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
extern int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
extern void sisusb_init_concode(void);
extern int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
extern void sisusb_console_exit(struct sisusb_usb_data *sisusb);
extern void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
extern 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);
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 DECLARE_MUTEX(disconnect_sem);
DECLARE_MUTEX(disconnect_sem);
static void
sisusb_free_buffers(struct sisusb_usb_data *sisusb)
......@@ -639,7 +685,10 @@ static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
/* The following routines assume being used to transfer byte, word,
* long etc.
* This means that they assume "data" in machine endianness format.
* 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,
......@@ -839,7 +888,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
if (get_user(swap16, (u16 __user *)userbuffer))
return -EFAULT;
} else
swap16 = (kernbuffer[0] << 8) | kernbuffer[1];
swap16 = *((u16 *)kernbuffer);
ret = sisusb_write_memio_word(sisusb,
SISUSB_TYPE_MEM,
......@@ -855,14 +904,25 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
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,
......@@ -879,10 +939,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
if (get_user(swap32, (u32 __user *)userbuffer))
return -EFAULT;
} else
swap32 = (kernbuffer[0] << 24) |
(kernbuffer[1] << 16) |
(kernbuffer[2] << 8) |
kernbuffer[3];
swap32 = *((u32 *)kernbuffer);
ret = sisusb_write_memio_long(sisusb,
SISUSB_TYPE_MEM,
......@@ -1005,6 +1062,10 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
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)
{
......@@ -1191,8 +1252,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
(u16 __user *)userbuffer))
return -EFAULT;
} else {
kernbuffer[0] = swap16 >> 8;
kernbuffer[1] = swap16 & 0xff;
*((u16 *)kernbuffer) = swap16;
}
}
return ret;
......@@ -1202,9 +1262,15 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
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;
......@@ -1228,10 +1294,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
userbuffer += 4;
} else {
kernbuffer[0] = (swap32 >> 24) & 0xff;
kernbuffer[1] = (swap32 >> 16) & 0xff;
kernbuffer[2] = (swap32 >> 8) & 0xff;
kernbuffer[3] = swap32 & 0xff;
*((u32 *)kernbuffer) = swap32;
kernbuffer += 4;
}
addr += 4;
......@@ -1289,7 +1352,24 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
/* High level: Gfx (indexed) register access */
static int
#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
#ifndef INCL_SISUSB_CON
static
#endif
int
sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
{
int ret;
......@@ -1298,7 +1378,10 @@ sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
return ret;
}
static int
#ifndef INCL_SISUSB_CON
static
#endif
int
sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
{
int ret;
......@@ -1307,7 +1390,10 @@ sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
return ret;
}
static int
#ifndef INCL_SISUSB_CON
static
#endif
int
sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
u8 myand, u8 myor)
{
......@@ -1336,18 +1422,89 @@ sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
return ret;
}
static int
#ifndef INCL_SISUSB_CON
static
#endif
int
sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
{
return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
}
static int
#ifndef INCL_SISUSB_CON
static
#endif
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_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
{
return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
}
int
sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
{
return(sisusb_read_memio_word(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++) {
printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
for(j = 0; j < i; j++) {
printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
}
}
}
#endif
/* access pci config registers (reg numbers 0, 4, 8, etc) */
static int
......@@ -2270,6 +2427,129 @@ sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int 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;
struct font_desc *myfont;
u8 *tempbuf;
u16 *tempbufb;
size_t written;
static char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
static 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);
if (!(myfont = find_font("VGA8x16")))
return 1;
if (!(tempbuf = vmalloc(8192)))
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) {
if ((tempbuf = vmalloc(8192))) {
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
......@@ -2329,7 +2609,7 @@ sisusb_open(struct inode *inode, struct file *file)
}
}
/* increment usage count for the device */
/* Increment usage count for our sisusb */
kref_get(&sisusb->kref);
sisusb->isopen = 1;
......@@ -2340,12 +2620,10 @@ sisusb_open(struct inode *inode, struct file *file)
up(&disconnect_sem);
printk(KERN_DEBUG "sisusbvga[%d]: opened", sisusb->minor);
return 0;
}
static void
void
sisusb_delete(struct kref *kref)
{
struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
......@@ -2359,6 +2637,9 @@ sisusb_delete(struct kref *kref)
sisusb->sisusb_dev = NULL;
sisusb_free_buffers(sisusb);
sisusb_free_urbs(sisusb);
#ifdef INCL_SISUSB_CON
kfree(sisusb->SiS_Pr);
#endif
kfree(sisusb);
}
......@@ -2395,8 +2676,6 @@ sisusb_release(struct inode *inode, struct file *file)
up(&disconnect_sem);
printk(KERN_DEBUG "sisusbvga[%d]: released", myminor);
return 0;
}
......@@ -2733,6 +3012,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
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;
......@@ -2774,6 +3059,10 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
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 +
......@@ -2781,11 +3070,61 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
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)
if (retval > 0)
retval = -EIO;
return retval;
......@@ -2835,6 +3174,11 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
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
if (copy_to_user((void __user *)arg, &x, sizeof(x)))
retval = -EFAULT;
......@@ -2895,9 +3239,13 @@ static struct file_operations usb_sisusb_fops = {
};
static struct usb_class_driver usb_sisusb_class = {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
.name = "usb/sisusbvga%d",
.fops = &usb_sisusb_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
#else
.name = "sisusbvga%d",
#endif
.fops = &usb_sisusb_fops,
.minor_base = SISUSB_MINOR
};
......@@ -2994,12 +3342,25 @@ static int sisusb_probe(struct usb_interface *intf,
printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
sisusb->minor, sisusb->numobufs);
#ifdef INCL_SISUSB_CON
/* Allocate our SiS_Pr */
if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
printk(KERN_ERR
"sisusbvga[%d]: Failed to allocate SiS_Pr\n",
sisusb->minor);
}
#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;
#ifdef SISUSB_OLD_CONFIG_COMPAT
{
int ret;
......@@ -3014,14 +3375,19 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->minor);
else
sisusb->ioctl32registered = 1;
}
#endif
sisusb->present = 1;
if (dev->speed == USB_SPEED_HIGH) {
if (sisusb_init_gfxdevice(sisusb, 1))
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))
printk(KERN_ERR
"sisusbvga[%d]: Failed to early "
"initialize device\n",
......@@ -3035,6 +3401,16 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->ready = 1;
#ifdef SISUSBENDIANTEST
printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
sisusb_testreadwrite(sisusb);
printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
#endif
#ifdef INCL_SISUSB_CON
sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
#endif
return 0;
error_4:
......@@ -3053,13 +3429,20 @@ static void sisusb_disconnect(struct usb_interface *intf)
struct sisusb_usb_data *sisusb;
int minor;
down(&disconnect_sem);
/* This should *not* happen */
if (!(sisusb = usb_get_intfdata(intf))) {
up(&disconnect_sem);
if (!(sisusb = usb_get_intfdata(intf)))
return;
}
#ifdef INCL_SISUSB_CON
sisusb_console_exit(sisusb);
#endif
/* The above code doesn't need the disconnect
* semaphore to be down; its meaning is to
* protect all other routines from the disconnect
* case, not the other way round.
*/
down(&disconnect_sem);
down(&sisusb->lock);
......@@ -3123,11 +3506,17 @@ static int __init usb_sisusb_init(void)
{
int retval;
#ifdef INCL_SISUSB_CON
sisusb_init_concode();
#endif
if (!(retval = usb_register(&sisusb_driver))) {
printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
printk(KERN_INFO
"sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
}
return retval;
......@@ -3142,6 +3531,6 @@ module_init(usb_sisusb_init);
module_exit(usb_sisusb_exit);
MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles");
MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
MODULE_LICENSE("GPL");
......@@ -46,15 +46,36 @@
#endif
#endif
/* For older kernels, support for text consoles is by default
* off. To ensable text console support, change the following:
*/
#if 0
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
#define CONFIG_USB_SISUSBVGA_CON
#endif
#endif
/* Version Information */
#define SISUSB_VERSION 0
#define SISUSB_REVISION 0
#define SISUSB_PATCHLEVEL 7
#define SISUSB_PATCHLEVEL 8
/* Include console and mode switching code? */
#ifdef CONFIG_USB_SISUSBVGA_CON
#define INCL_SISUSB_CON 1
#endif
#ifdef INCL_SISUSB_CON
#include <linux/console.h>
#include <linux/vt_kern.h>
#include "sisusb_struct.h"
#endif
/* USB related */
#define SISUSB_MINOR 133 /* FIXME */
#define SISUSB_MINOR 133 /* official */
/* Size of the sisusb input/output buffers */
#define SISUSB_IBUF_SIZE 0x01000
......@@ -131,6 +152,26 @@ struct sisusb_usb_data {
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)
......@@ -249,7 +290,9 @@ struct sisusb_info {
__u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
__u8 sisusb_reserved[32]; /* for future use */
__u32 sisusb_conactive; /* != 0 if console driver active */
__u8 sisusb_reserved[28]; /* for future use */
};
struct sisusb_command {
......@@ -270,9 +313,15 @@ struct sisusb_command {
#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 */
/*
* 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/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/kd.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/spinlock.h>
#include <linux/kref.h>
#include <linux/smp_lock.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
#include "sisusb.h"
#ifdef INCL_SISUSB_CON
extern int sisusb_setreg(struct sisusb_usb_data *, int, u8);
extern int sisusb_getreg(struct sisusb_usb_data *, int, u8 *);
extern int sisusb_setidxreg(struct sisusb_usb_data *, int, u8, u8);
extern int sisusb_getidxreg(struct sisusb_usb_data *, int, u8, u8 *);
extern int sisusb_setidxregor(struct sisusb_usb_data *, int, u8, u8);
extern int sisusb_setidxregand(struct sisusb_usb_data *, int, u8, u8);
extern int sisusb_setidxregandor(struct sisusb_usb_data *, int, u8, u8, u8);
extern int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
extern int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
extern int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
extern int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
extern int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
u32 dest, int length, size_t *bytes_written);
extern void sisusb_delete(struct kref *kref);
extern int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
#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;
extern struct semaphore disconnect_sem;
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;
if (!(sisusb = sisusb_get_sisusb(console)))
return NULL;
down(&sisusb->lock);
if (!sisusb_sisusb_valid(sisusb) ||
!sisusb->havethisconsole[console]) {
up(&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 take_over_console(),
* ie by us/under our control. It is
* only called after text mode and fonts
* are set up/restored.
*/
down(&disconnect_sem);
if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
up(&disconnect_sem);
return;
}
down(&sisusb->lock);
if (!sisusb_sisusb_valid(sisusb)) {
up(&sisusb->lock);
up(&disconnect_sem);
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);
up(&sisusb->lock);
up(&disconnect_sem);
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 take_over_console()
* and others, ie not under our control.
*/
down(&disconnect_sem);
if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
up(&disconnect_sem);
return;
}
down(&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;
}
}
up(&sisusb->lock);
/* decrement the usage count on our sisusb */
kref_put(&sisusb->kref, sisusb_delete);
up(&disconnect_sem);
}
/* interface routine */
static u8
sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity,
u8 blink, u8 underline, u8 reverse)
{
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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return;
/* sisusb->lock is down */
/* Don't need to put the character into buffer ourselves,
* because the vt does this BEFORE calling us.
*/
#if 0
sisusbcon_writew(ch, SISUSB_VADDR(x, y));
#endif
if (sisusb_is_inactive(c, sisusb)) {
up(&sisusb->lock);
return;
}
sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
(u32)SISUSB_HADDR(x, y), 2, &written);
up(&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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
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)) {
up(&sisusb->lock);
return;
}
sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
(u32)SISUSB_HADDR(x, y), count * 2, &written);
up(&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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
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)) {
up(&sisusb->lock);
return;
}
length = ((height * cols) - x - (cols - width - x)) * 2;
sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
(u32)SISUSB_HADDR(x, y), length, &written);
up(&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 0
u16 *src, *dest;
int i;
#endif
if (width <= 0 || height <= 0)
return;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return;
/* sisusb->lock is down */
cols = sisusb->sisusb_num_columns;
/* Don't need to move data outselves, because
* vt does this BEFORE calling us.
* This is only used by vt's insert/deletechar.
*/
#if 0
if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
height * width * 2);
} else if (dy < sy || (dy == sy && dx < sx)) {
src = SISUSB_VADDR(sx, sy);
dest = SISUSB_VADDR(dx, dy);
for (i = height; i > 0; i--) {
sisusbcon_memmovew(dest, src, width * 2);
src += cols;
dest += cols;
}
} else {
src = SISUSB_VADDR(sx, sy + height - 1);
dest = SISUSB_VADDR(dx, dy + height - 1);
for (i = height; i > 0; i--) {
sisusbcon_memmovew(dest, src, width * 2);
src -= cols;
dest -= cols;
}
}
#endif
if (sisusb_is_inactive(c, sisusb)) {
up(&sisusb->lock);
return;
}
length = ((height * cols) - dx - (cols - width - dx)) * 2;
sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy),
(u32)SISUSB_HADDR(dx, dy), length, &written);
up(&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.
*/
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return 0;
/* sisusb->lock is down */
/* Don't write to screen if in gfx mode */
if (sisusb_is_inactive(c, sisusb)) {
up(&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) {
up(&sisusb->lock);
printk(KERN_DEBUG "sisusb: 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,
(u32)SISUSB_HADDR(0, 0),
length, &written);
up(&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.
*/
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return;
/* sisusb->lock is down */
if (sisusb_is_inactive(c, sisusb)) {
up(&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);
up(&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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return -EINVAL;
/* sisusb->lock is down */
if (sisusb_is_inactive(c, sisusb)) {
up(&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;
}
up(&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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return 0;
/* sisusb->lock is down */
if (mode_switch)
sisusb->is_gfx = blank ? 1 : 0;
if (sisusb_is_inactive(c, sisusb)) {
up(&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:
up(&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);
}
up(&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 */
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return 0;
/* sisusb->lock is down */
if (sisusb_is_inactive(c, sisusb)) {
up(&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);
up(&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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return;
/* sisusb->lock is down */
if (sisusb_is_inactive(c, sisusb)) {
up(&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;
up(&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;
}
up(&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),
(u32)SISUSB_HADDR(0, t), length, &written);
up(&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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return 0;
/* sisusb->lock is down */
if (sisusb_is_inactive(c, sisusb)) {
up(&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;
up(&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.
*/
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return 0;
/* sisusb->lock is down */
if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) {
up(&sisusb->lock);
return 0;
}
c->vc_origin = c->vc_visible_origin = sisusb->scrbuf;
sisusbcon_set_start_address(sisusb, c);
sisusb->con_rolled_over = 0;
up(&sisusb->lock);
return 1;
}
/* Interface routine */
static int
sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows)
{
struct sisusb_usb_data *sisusb;
int fh;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return -ENODEV;
fh = sisusb->current_font_height;
up(&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)
up(&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 *c = vc_cons[i].d;
if (c && c->vc_sw == &sisusb_con)
c->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)
up(&sisusb->lock);
if (dorecalc && c) {
int i, 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)
up(&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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
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;
if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
return -ENODEV;
/* sisusb->lock is down */
font->width = 8;
font->height = c->vc_font.height;
font->charcount = 256;
if (!font->data) {
up(&sisusb->lock);
return 0;
}
if (!sisusb->font_backup) {
up(&sisusb->lock);
return -ENODEV;
}
/* Copy 256 chars only, like vgacon */
memcpy(font->data, sisusb->font_backup, 256 * 32);
up(&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
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, minor = sisusb->minor;
down(&disconnect_sem);
down(&sisusb->lock);
/* Erm.. that should not happen */
if (sisusb->haveconsole || !sisusb->SiS_Pr) {
up(&sisusb->lock);
up(&disconnect_sem);
return 1;
}
sisusb->con_first = first;
sisusb->con_last = last;
if (first > last ||
first > MAX_NR_CONSOLES ||
last > MAX_NR_CONSOLES) {
up(&sisusb->lock);
up(&disconnect_sem);
return 1;
}
/* If gfxcore not initialized or no consoles given, quit graciously */
if (!sisusb->gfxinit || first < 1 || last < 1) {
up(&sisusb->lock);
up(&disconnect_sem);
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)) {
up(&sisusb->lock);
up(&disconnect_sem);
printk(KERN_ERR
"sisusbvga[%d]: Failed to set up text mode\n",
minor);
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))) {
up(&sisusb->lock);
up(&disconnect_sem);
printk(KERN_ERR
"sisusbvga[%d]: Failed to allocate screen buffer\n",
minor);
return 1;
}
up(&sisusb->lock);
up(&disconnect_sem);
/* Now grab the desired console(s) */
ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
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])
take_over_console(&sisusb_dummy_con, i, i, 0);
/* At this point, con_deinit for all our
* consoles is executed by 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 */
/*
* 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/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.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 "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: Get ModeID */
/*********************************************/
unsigned short
SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
{
unsigned short ModeIndex = 0;
switch (HDisplay)
{
case 320:
if (VDisplay == 200)
ModeIndex = ModeIndex_320x200[Depth];
else if (VDisplay == 240)
ModeIndex = ModeIndex_320x240[Depth];
break;
case 400:
if (VDisplay == 300)
ModeIndex = ModeIndex_400x300[Depth];
break;
case 512:
if (VDisplay == 384)
ModeIndex = ModeIndex_512x384[Depth];
break;
case 640:
if (VDisplay == 480)
ModeIndex = ModeIndex_640x480[Depth];
else if (VDisplay == 400)
ModeIndex = ModeIndex_640x400[Depth];
break;
case 720:
if (VDisplay == 480)
ModeIndex = ModeIndex_720x480[Depth];
else if (VDisplay == 576)
ModeIndex = ModeIndex_720x576[Depth];
break;
case 768:
if (VDisplay == 576)
ModeIndex = ModeIndex_768x576[Depth];
break;
case 800:
if (VDisplay == 600)
ModeIndex = ModeIndex_800x600[Depth];
else if (VDisplay == 480)
ModeIndex = ModeIndex_800x480[Depth];
break;
case 848:
if (VDisplay == 480)
ModeIndex = ModeIndex_848x480[Depth];
break;
case 856:
if (VDisplay == 480)
ModeIndex = ModeIndex_856x480[Depth];
break;
case 960:
if (VDisplay == 540)
ModeIndex = ModeIndex_960x540[Depth];
else if (VDisplay == 600)
ModeIndex = ModeIndex_960x600[Depth];
break;
case 1024:
if (VDisplay == 576)
ModeIndex = ModeIndex_1024x576[Depth];
else if (VDisplay == 768)
ModeIndex = ModeIndex_1024x768[Depth];
break;
case 1152:
if (VDisplay == 864)
ModeIndex = ModeIndex_1152x864[Depth];
break;
case 1280:
switch (VDisplay) {
case 720:
ModeIndex = ModeIndex_1280x720[Depth];
break;
case 768:
ModeIndex = ModeIndex_1280x768[Depth];
break;
case 1024:
ModeIndex = ModeIndex_1280x1024[Depth];
break;
}
}
return ModeIndex;
}
/*********************************************/
/* 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 */
/*********************************************/
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 */
/* $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 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 */
};
void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr);
unsigned short SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth);
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);
#endif
/*
* 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;
struct SiS_VCLKData *SiS_VCLKData;
const struct SiS_ModeResInfo *SiS_ModeResInfo;
};
#endif
......@@ -137,7 +137,7 @@ config FONT_8x8
config FONT_8x16
bool "VGA 8x16 font" if FONTS
depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y
depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || USB_SISUSBVGA_CON
default y if !SPARC32 && !SPARC64 && !FONTS
help
This is the "high resolution" font for the VGA frame buffer (the one
......
......@@ -33,6 +33,10 @@ endif
obj-$(CONFIG_FB_STI) += sticore.o font.o
ifeq ($(CONFIG_USB_SISUSBVGA_CON),y)
obj-$(CONFIG_USB_SISUSBVGA) += font.o
endif
# Targets that kbuild needs to know about
targets := promcon_tbl.c
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment