S: Germany
N: Stephen Rothwell
-E: sfr@linuxcare.com
+E: sfr@linuxcare.com.au
W: http://linuxcare.com.au/sfr
P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02
D: Boot/setup/build work for setup > 2K
D: Author, APM driver
+D: Directory notification
S: 66 Maltby Circuit
S: Wanniassa ACT 2903
S: Australia
If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'.
+TCP Explicit Congestion Notification support
+CONFIG_INET_ECN
+ Explicit Congestion Notification (ECN) allows routers to notify
+ clients about network congestion, resulting in fewer dropped packets
+ and increased network performance. This option adds ECN support to the
+ Linux kernel, as well as a sysctl (/proc/sys/net/ipv4/tcp_ecn) which
+ allows ECN support to be disabled at runtime.
+
+ Note that, on the Internet, there are many broken firewalls which
+ refuse connections from ECN-enabled machines, and it may be a while
+ before these firewalls are fixed. Until then, to access a site behind
+ such a firewall (some of which are major sites, at the time of this
+ writing) you will have to disable this option, either by saying N now
+ or by using the sysctl.
+
+ If in doubt, say N.
+
SYN flood protection
CONFIG_SYN_COOKIES
Normal TCP/IP networking is open to an attack known as "SYN
If D-cache aliasing is not an issue, this routine may
simply be defined as a nop on that architecture.
- TODO: If we set aside a few bits in page->flags as
- "architecture private", these interfaces could
- be implemented much more efficiently. This would
- allow one to "defer" (perhaps indefinitely) the
- actual flush if there are currently no user processes
- mapping this page.
-
- The idea is, first at flush_dcache_page() time, if
- page->mapping->i_mmap is an empty list, just mark
- one of the architecture private page flag bits.
- Later, in update_mmu_cache(), a check could be made
- of this flag bit, and if set the flush is done
- and the flag bit is cleared.
+ There is a bit set aside in page->flags (PG_arch_1) as
+ "architecture private". The kernel guarentees that,
+ for pagecache pages, it will clear this bit when such
+ a page first enters the pagecache.
+
+ This allows these interfaces to be implemented much more
+ efficiently. It allows one to "defer" (perhaps indefinitely)
+ the actual flush if there are currently no user processes
+ mapping this page. See sparc64's flush_dcache_page and
+ update_mmu_cache implementations for an example of how to go
+ about doing this.
+
+ The idea is, first at flush_dcache_page() time, if
+ page->mapping->i_mmap{,_shared} are empty lists, just mark the
+ architecture private page flag bit. Later, in
+ update_mmu_cache(), a check is made of this flag bit, and if
+ set the flush is done and the flag bit is cleared.
XXX Not documented: flush_icache_page(), need to talk to Paul
Mackerras, David Mosberger-Tang, et al.
In order to use the ethernet bridging functionality you'll need the
-userspace tools available at ftp://openrock.net/bridge. The tarball
-available there contains extensive documentation, but if you still have
-questions, don't hesitate to post to the mailing list (more info at
-http://openrock.net/mailman/listinfo/bridge). You can also mail me at
-buytenh@openrock.net.
+userspace tools available at http://www.math.leidenuniv.nl/~buytenh/bridge.
+The tarball available there contains extensive documentation, but if you
+still have questions, don't hesitate to post to the mailing list (more info
+at http://www.math.leidenuniv.nl/mailman/listinfo/bridge). You can also
+mail me at buytenh@gnu.org.
Lennert Buytenhek
-<buytenh@openrock.net>
+<buytenh@gnu.org>
tcp_dsack - BOOLEAN
Allows TCP to send "duplicate" SACKs.
-tcp_ecn - BOOLEN
+tcp_ecn - BOOLEAN
Enable Explicit Congestion Notification in TCP.
tcp_reordering - INTEGER
Updated by:
Andi Kleen
ak@muc.de
-$Id: ip-sysctl.txt,v 1.16 2000/08/13 18:24:11 davem Exp $
+$Id: ip-sysctl.txt,v 1.17 2000/11/06 07:15:36 davem Exp $
--- /dev/null
+
+Network Devices, the Kernel, and You!
+
+
+Introduction
+============
+The following is a random collection of documentation regarding
+network devices.
+
+
+
+struct net_device synchronization rules
+=======================================
+dev->open:
+ Locking: Inside rtnl_lock() semaphore.
+ Sleeping: OK
+
+dev->stop:
+ Locking: Inside rtnl_lock() semaphore.
+ Sleeping: OK
+
+dev->do_ioctl:
+ Locking: Inside rtnl_lock() semaphore.
+ Sleeping: OK
+
+dev->get_stats:
+ Locking: Inside dev_base_lock spinlock.
+ Sleeping: NO
+
+dev->hard_start_xmit:
+ Locking: Inside dev->xmit_lock spinlock.
+ Sleeping: NO
+
+dev->tx_timeout:
+ Locking: Inside dev->xmit_lock spinlock.
+ Sleeping: NO
+
+dev->set_multicast_list:
+ Locking: Inside dev->xmit_lock spinlock.
+ Sleeping: NO
+
+
L: digilnux@dgii.com
S: Maintained
+DIRECTORY NOTIFICATION
+P: Stephen Rothwell
+M: sfr@linuxcare.com.au
+L: linux-kernel@vger.kernel.org
+S: Supported
+
DISK GEOMETRY AND PARTITION HANDLING
P: Andries Brouwer
M: aeb@veritas.com
ETHERNET BRIDGE
P: Lennert Buytenhek
-M: buytenh@openrock.net
-L: bridge@openrock.net
-W: http://openrock.net/bridge
+M: buytenh@gnu.org
+L: bridge@math.leidenuniv.nl
+W: http://www.math.leidenuniv.nl/~buytenh/bridge
S: Maintained
ETHERTEAM 16I DRIVER
clean: archclean
rm -f kernel/ksyms.lst include/linux/compile.h
- find . -name '*.[oas]' -type f -print | grep -v lxdialog/ | xargs rm -f
- rm -f core `find . -type f -name 'core' -print`
- rm -f core `find . -type f -name '.*.flags' -print`
+ find . \( -name '*.[oas]' -o -name core -o -name '.*.flags' \) -type f -print \
+ | grep -v lxdialog/ | xargs rm -f
rm -f vmlinux System.map
rm -f .tmp*
rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c
rm -f .menuconfig.log
rm -f include/asm
rm -rf include/config
- rm -f .depend `find . -type f -name .depend -print`
- rm -f core `find . -type f -size 0 -print`
+ find . \( -size 0 -o -name .depend \) -type f -print | xargs rm -f
rm -f .hdepend scripts/mkdep scripts/split-include scripts/docproc
rm -f $(TOPDIR)/include/linux/modversions.h
rm -rf $(TOPDIR)/include/linux/modules
endif
ifdef CONFIG_MCRUSOE
-CFLAGS += -march=i586
+CFLAGS += -march=i686 -malign-functions=0 -malign-jumps=0 -malign-loops=0
endif
ifdef CONFIG_MWINCHIPC6
if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
BUG();
- value = apic_read(APIC_SPIV);
- value &= ~APIC_VECTOR_MASK;
- /*
- * Enable APIC
- */
- value |= (1<<8);
-
- /*
- * Some unknown Intel IO/APIC (or APIC) errata is biting us with
- * certain networking cards. If high frequency interrupts are
- * happening on a particular IOAPIC pin, plus the IOAPIC routing
- * entry is masked/unmasked at a high rate as well then sooner or
- * later IOAPIC line gets 'stuck', no more interrupts are received
- * from the device. If focus CPU is disabled then the hang goes
- * away, oh well :-(
- *
- * [ This bug can be reproduced easily with a level-triggered
- * PCI Ne2000 networking cards and PII/PIII processors, dual
- * BX chipset. ]
- */
-#if 0
- /* Enable focus processor (bit==0) */
- value &= ~(1<<9);
-#else
- /* Disable focus processor (bit==1) */
- value |= (1<<9);
-#endif
- /*
- * Set spurious IRQ vector
- */
- value |= SPURIOUS_APIC_VECTOR;
- apic_write_around(APIC_SPIV, value);
-
/*
* Set up LVT0, LVT1:
*
* Must be "all ones" explicitly for 82489DX.
*/
apic_write_around(APIC_DFR, 0xffffffff);
+
+ /*
+ * Now that we are all set up, enable the APIC
+ */
+ value = apic_read(APIC_SPIV);
+ value &= ~APIC_VECTOR_MASK;
+ /*
+ * Enable APIC
+ */
+ value |= (1<<8);
+
+ /*
+ * Some unknown Intel IO/APIC (or APIC) errata is biting us with
+ * certain networking cards. If high frequency interrupts are
+ * happening on a particular IOAPIC pin, plus the IOAPIC routing
+ * entry is masked/unmasked at a high rate as well then sooner or
+ * later IOAPIC line gets 'stuck', no more interrupts are received
+ * from the device. If focus CPU is disabled then the hang goes
+ * away, oh well :-(
+ *
+ * [ This bug can be reproduced easily with a level-triggered
+ * PCI Ne2000 networking cards and PII/PIII processors, dual
+ * BX chipset. ]
+ */
+#if 0
+ /* Enable focus processor (bit==0) */
+ value &= ~(1<<9);
+#else
+ /* Disable focus processor (bit==1) */
+ value |= (1<<9);
+#endif
+ /*
+ * Set spurious IRQ vector
+ */
+ value |= SPURIOUS_APIC_VECTOR;
+ apic_write_around(APIC_SPIV, value);
}
void __init init_apic_mappings(void)
static int banks;
-void mcheck_fault(void)
+void do_machine_check(struct pt_regs * regs, long error_code)
{
int recover=1;
u32 alow, ahigh, high, low;
pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
jmp error_code
-ENTRY(reserved)
- pushl $0
- pushl $ SYMBOL_NAME(do_reserved)
- jmp error_code
-
ENTRY(double_fault)
pushl $ SYMBOL_NAME(do_double_fault)
jmp error_code
ENTRY(machine_check)
pushl $0
- pushl $ SYMBOL_NAME(mcheck_fault)
+ pushl $ SYMBOL_NAME(do_machine_check)
jmp error_code
ENTRY(spurious_interrupt_bug)
display_cacheinfo(c);
return r;
}
+
+static void __init intel_model(struct cpuinfo_x86 *c)
+{
+ unsigned int *v = (unsigned int *) c->x86_model_id;
+ cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+ c->x86_model_id[48] = 0;
+ printk("CPU: %s\n", c->x86_model_id);
+}
/*
/* Pentium IV. */
if (c->x86 == 15) {
- get_model_name(c);
+ intel_model(c);
return;
}
asmlinkage void page_fault(void);
asmlinkage void coprocessor_error(void);
asmlinkage void simd_coprocessor_error(void);
-asmlinkage void reserved(void);
asmlinkage void alignment_check(void);
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void machine_check(void);
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
-DO_ERROR(18, SIGSEGV, "reserved", reserved)
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
__setup("nmi_watchdog=", setup_nmi_watchdog);
-extern spinlock_t console_lock;
+extern spinlock_t console_lock, timerlist_lock;
static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out (timerlist_lock is aquired through the
+ * console unblank code)
+ */
+void bust_spinlocks(void)
+{
+ spin_lock_init(&console_lock);
+ spin_lock_init(&timerlist_lock);
+}
+
inline void nmi_watchdog_tick(struct pt_regs * regs)
{
/*
* We are in trouble anyway, lets at least try
* to get a message out.
*/
- spin_trylock(&console_lock);
- spin_unlock(&console_lock);
+ bust_spinlocks();
printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu);
show_registers(regs);
printk("console shuts up ...\n");
* Add *user handling. Checksums are not a win with MMX on any CPU
* tested so far for any MMX solution figured.
*
+ * 22/09/2000 - Arjan van de Ven
+ * Improved for non-egineering-sample Athlons
+ *
*/
void *_mmx_memcpy(void *to, const void *from, size_t len)
" pxor %%mm0, %%mm0\n" : :
);
- for(i=0;i<4096/128;i++)
+ for(i=0;i<4096/64;i++)
{
__asm__ __volatile__ (
- " movq %%mm0, (%0)\n"
- " movq %%mm0, 8(%0)\n"
- " movq %%mm0, 16(%0)\n"
- " movq %%mm0, 24(%0)\n"
- " movq %%mm0, 32(%0)\n"
- " movq %%mm0, 40(%0)\n"
- " movq %%mm0, 48(%0)\n"
- " movq %%mm0, 56(%0)\n"
- " movq %%mm0, 64(%0)\n"
- " movq %%mm0, 72(%0)\n"
- " movq %%mm0, 80(%0)\n"
- " movq %%mm0, 88(%0)\n"
- " movq %%mm0, 96(%0)\n"
- " movq %%mm0, 104(%0)\n"
- " movq %%mm0, 112(%0)\n"
- " movq %%mm0, 120(%0)\n"
+ " movntq %%mm0, (%0)\n"
+ " movntq %%mm0, 8(%0)\n"
+ " movntq %%mm0, 16(%0)\n"
+ " movntq %%mm0, 24(%0)\n"
+ " movntq %%mm0, 32(%0)\n"
+ " movntq %%mm0, 40(%0)\n"
+ " movntq %%mm0, 48(%0)\n"
+ " movntq %%mm0, 56(%0)\n"
: : "r" (page) : "memory");
- page+=128;
+ page+=64;
}
+ /* since movntq is weakly-ordered, a "sfence" is needed to become
+ * ordered again.
+ */
+ __asm__ __volatile__ (
+ " sfence \n" : :
+ );
stts();
}
current->flags &= ~PF_USEDFPU;
}
+ /* maybe the prefetch stuff can go before the expensive fnsave...
+ * but that is for later. -AV
+ */
__asm__ __volatile__ (
"1: prefetch (%0)\n"
" prefetch 64(%0)\n"
__asm__ __volatile__ (
"1: prefetch 320(%0)\n"
"2: movq (%0), %%mm0\n"
+ " movntq %%mm0, (%1)\n"
" movq 8(%0), %%mm1\n"
+ " movntq %%mm1, 8(%1)\n"
" movq 16(%0), %%mm2\n"
+ " movntq %%mm2, 16(%1)\n"
" movq 24(%0), %%mm3\n"
- " movq %%mm0, (%1)\n"
- " movq %%mm1, 8(%1)\n"
- " movq %%mm2, 16(%1)\n"
- " movq %%mm3, 24(%1)\n"
- " movq 32(%0), %%mm0\n"
- " movq 40(%0), %%mm1\n"
- " movq 48(%0), %%mm2\n"
- " movq 56(%0), %%mm3\n"
- " movq %%mm0, 32(%1)\n"
- " movq %%mm1, 40(%1)\n"
- " movq %%mm2, 48(%1)\n"
- " movq %%mm3, 56(%1)\n"
+ " movntq %%mm3, 24(%1)\n"
+ " movq 32(%0), %%mm4\n"
+ " movntq %%mm4, 32(%1)\n"
+ " movq 40(%0), %%mm5\n"
+ " movntq %%mm5, 40(%1)\n"
+ " movq 48(%0), %%mm6\n"
+ " movntq %%mm6, 48(%1)\n"
+ " movq 56(%0), %%mm7\n"
+ " movntq %%mm7, 56(%1)\n"
".section .fixup, \"ax\"\n"
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
" jmp 2b\n"
from+=64;
to+=64;
}
+ /* since movntq is weakly-ordered, a "sfence" is needed to become
+ * ordered again.
+ */
+ __asm__ __volatile__ (
+ " sfence \n" : :
+ );
stts();
}
#include <asm/hardirq.h>
extern void die(const char *,struct pt_regs *,long);
+extern void bust_spinlocks(void);
/*
* Ugly, ugly, but the goto's result in better assembly..
* terminate things with extreme prejudice.
*/
+ bust_spinlocks();
+
if (address < PAGE_SIZE)
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
else
return -ENOMEM;
new = 1;
}
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
if (new && offset)
memset(kaddr, 0, offset);
void flush_page_to_ram(struct page *page)
{
- unsigned long vaddr = kmap(page);
+ unsigned long vaddr = (unsigned long) kmap(page);
__flush_page_to_ram(vaddr);
kunmap(page);
}
-/* $Id: ebus.c,v 1.11 2000/10/10 01:07:38 davem Exp $
+/* $Id: ebus.c,v 1.15 2000/11/08 05:06:21 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
struct linux_ebus *ebus_chain = 0;
-#ifdef CONFIG_SUN_OPENPROMIO
-extern int openprom_init(void);
-#endif
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
-#ifdef CONFIG_OBP_FLASH
-extern int flash_init(void);
-#endif
-#ifdef CONFIG_ENVCTRL
-extern int envctrl_init(void);
-#endif
/* We are together with pcic.c under CONFIG_PCI. */
extern unsigned int pcic_pin_to_irq(unsigned int, char *name);
++num_ebus;
}
-#ifdef CONFIG_SUN_OPENPROMIO
- openprom_init();
-#endif
-
-#ifdef CONFIG_SUN_BPP
- bpp_init();
-#endif
#ifdef CONFIG_SUN_AUXIO
auxio_probe();
#endif
-#ifdef CONFIG_ENVCTRL
- envctrl_init();
-#endif
-#ifdef CONFIG_OBP_FLASH
- flash_init();
-#endif
}
-/* $Id: pcic.c,v 1.18 2000/09/25 06:09:12 anton Exp $
+/* $Id: pcic.c,v 1.19 2000/11/08 04:49:17 davem Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
void flush_page_to_ram(struct page *page)
{
- unsigned long vaddr;
- vaddr = kmap(page);
- __flush_page_to_ram((unsigned long)page_address(page));
+ unsigned long vaddr = (unsigned long) kmap(page);
+ __flush_page_to_ram(vaddr);
kunmap(page);
}
-/* $Id: srmmu.c,v 1.223 2000/10/16 14:32:49 anton Exp $
+/* $Id: srmmu.c,v 1.224 2000/11/09 22:40:05 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
void (*poke_srmmu)(void) __initdata = NULL;
-extern unsigned long bootmem_init(void);
+extern void bootmem_init(void);
extern void sun_serial_setup(void);
void __init srmmu_paging_init(void)
-/* $Id: sun4c.c,v 1.200 2000/10/16 14:32:49 anton Exp $
+/* $Id: sun4c.c,v 1.201 2000/11/09 22:39:36 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
extern void sparc_context_init(int);
extern unsigned long end;
-extern unsigned long bootmem_init(void);
+extern void bootmem_init(void);
extern unsigned long last_valid_pfn;
extern void sun_serial_setup(void);
kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4);
kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
- last_valid_pfn = end_pfn = bootmem_init();
+ bootmem_init();
+ end_pfn = last_valid_pfn;
/* This does not logically belong here, but we need to
* call it at the moment we are able to use the bootmem
__start___ksymtab = .;
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
+ __start___kallsyms = .; /* All kernel symbols */
+ __kallsyms : { *(__kallsyms) }
+ __stop___kallsyms = .;
. = ALIGN(4096);
__init_begin = .;
-/* $Id: ebus.c,v 1.48 2000/08/02 06:22:35 davem Exp $
+/* $Id: ebus.c,v 1.53 2000/11/08 05:08:23 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
struct linux_ebus *ebus_chain = 0;
-#ifdef CONFIG_SUN_OPENPROMIO
-extern int openprom_init(void);
-#endif
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
-#ifdef CONFIG_OBP_FLASH
-extern int flash_init(void);
-#endif
-#ifdef CONFIG_ENVCTRL
-extern int envctrl_init(void);
-#endif
-#ifdef CONFIG_DISPLAY7SEG
-extern int d7s_init(void);
-#endif
static inline void *ebus_alloc(size_t size)
{
++num_ebus;
}
-#ifdef CONFIG_SUN_OPENPROMIO
- openprom_init();
-#endif
-#ifdef CONFIG_SUN_BPP
- bpp_init();
-#endif
#ifdef CONFIG_SUN_AUXIO
auxio_probe();
-#endif
-#ifdef CONFIG_ENVCTRL
- envctrl_init();
-#endif
-#ifdef CONFIG_OBP_FLASH
- flash_init();
-#endif
-#ifdef CONFIG_DISPLAY7SEG
- d7s_init();
#endif
clock_probe();
power_init();
-/* $Id: ioctl32.c,v 1.99 2000/10/17 16:20:33 davem Exp $
+/* $Id: ioctl32.c,v 1.102 2000/11/08 05:13:30 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
#include <asm/audioio.h>
#include <asm/ethtool.h>
#include <asm/display7seg.h>
+#include <asm/module.h>
#include <linux/soundcard.h>
#include <linux/atm.h>
COMPATIBLE_IOCTL(ENVCTRL_RD_ETHERNET_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_MTHRBD_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_CPU_VOLTAGE)
+COMPATIBLE_IOCTL(ENVCTRL_RD_GLOBALADDRESS)
/* COMPATIBLE_IOCTL(D7SIOCRD) same value as ENVCTRL_RD_VOLTAGE_STATUS */
COMPATIBLE_IOCTL(D7SIOCWR)
COMPATIBLE_IOCTL(D7SIOCTM)
COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */
/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */
COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */
/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */
-/* $Id: pci.c,v 1.18 2000/10/03 11:31:42 anton Exp $
+/* $Id: pci.c,v 1.19 2000/11/08 04:49:17 davem Exp $
* pci.c: UltraSparc PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
-/* $Id: process.c,v 1.112 2000/09/06 00:45:01 davem Exp $
+/* $Id: process.c,v 1.113 2000/11/08 08:14:58 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
{
long retval;
- __asm__ __volatile("mov %1, %%g1\n\t"
+ /* If the parent runs before fn(arg) is called by the child,
+ * the input registers of this function can be clobbered.
+ * So we stash 'fn' and 'arg' into global registers which
+ * will not be modified by the parent.
+ */
+ __asm__ __volatile("mov %4, %%g2\n\t" /* Save FN into global */
+ "mov %5, %%g3\n\t" /* Save ARG into global */
+ "mov %1, %%g1\n\t" /* Clone syscall nr. */
"mov %2, %%o0\n\t" /* Clone flags. */
"mov 0, %%o1\n\t" /* usp arg == 0 */
"t 0x6d\n\t" /* Linux/Sparc clone(). */
"brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
" mov %%o0, %0\n\t"
- "jmpl %4, %%o7\n\t" /* Call the function. */
- " mov %5, %%o0\n\t" /* Set arg in delay. */
+ "jmpl %%g2, %%o7\n\t" /* Call the function. */
+ " mov %%g3, %%o0\n\t" /* Set arg in delay. */
"mov %3, %%g1\n\t"
"t 0x6d\n\t" /* Linux/Sparc exit(). */
/* Notreached by child. */
"=r" (retval) :
"i" (__NR_clone), "r" (flags | CLONE_VM),
"i" (__NR_exit), "r" (fn), "r" (arg) :
- "g1", "o0", "o1", "memory", "cc");
+ "g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
}
-/* $Id: sparc64_ksyms.c,v 1.95 2000/10/30 21:01:40 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.96 2000/11/06 06:59:03 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
extern int unregister_ioctl32_conversion(unsigned int cmd);
extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
-extern void __flush_dcache_page(void *addr);
extern int __ashrdi3(int, int);
return -ENOMEM;
new = 1;
}
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
if (new && offset)
memset(kaddr, 0, offset);
err = copy_from_user(kaddr + offset, (char *)A(str),
bytes_to_copy);
flush_page_to_ram(page);
- kunmap((unsigned long)kaddr);
+ kunmap(page);
if (err)
return -EFAULT;
-# $Id: Makefile,v 1.23 2000/07/10 20:57:34 davem Exp $
+# $Id: Makefile,v 1.24 2000/11/01 07:33:47 davem Exp $
# Makefile for Sparc64 library files..
#
memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \
VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \
- dec_and_lock.o
+ dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \
+ U3copy_in_user.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
--- /dev/null
+/* $Id: U3copy_from_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
+ * U3memcpy.S: UltraSparc-III optimized copy from userspace.
+ *
+ * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#undef SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ ba,pt %xcc, U3cfu_fixup; \
+ a, b, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ ba,pt %xcc, U3cfu_fixup; \
+ a, b, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX2(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o1; \
+ add %o1, %o4, %o1; \
+ ba,pt %xcc, U3cfu_fixup; \
+ add %o1, 0x1c0, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX3(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o1; \
+ sll %g3, 6, %g3; \
+ add %o1, 0x80, %o1; \
+ ba,pt %xcc, U3cfu_fixup; \
+ add %o1, %g3, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX4(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o1; \
+ add %o1, 0x40, %o1; \
+ ba,pt %xcc, U3cfu_fixup; \
+ add %o1, %g3, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#else
+#define ASI_BLK_P 0xf0
+#define FPRS_FEF 0x04
+#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#define SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) x,y;
+#define EX(x,y,a,b) x,y;
+#define EX2(x,y) x,y;
+#define EX3(x,y) x,y;
+#define EX4(x,y) x,y;
+#endif
+
+ /* Special/non-trivial issues of this code:
+ *
+ * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
+ * 2) Only low 32 FPU registers are used so that only the
+ * lower half of the FPU register set is dirtied by this
+ * code. This is especially important in the kernel.
+ * 3) This code never prefetches cachelines past the end
+ * of the source buffer.
+ */
+
+ .text
+ .align 32
+
+ /* The cheetah's flexible spine, oversized liver, enlarged heart,
+ * slender muscular body, and claws make it the swiftest hunter
+ * in Africa and the fastest animal on land. Can reach speeds
+ * of up to 2.4GB per second.
+ */
+
+ .globl U3copy_from_user
+U3copy_from_user: /* %o0=dst, %o1=src, %o2=len */
+#ifndef __KERNEL__
+ /* Save away original 'dst' for memcpy return value. */
+ mov %o0, %g3 ! A0 Group
+#endif
+ /* Anything to copy at all? */
+ cmp %o2, 0 ! A1
+ ble,pn %icc, U3copy_from_user_short_ret! BR
+
+ /* Extremely small copy? */
+ cmp %o2, 31 ! A0 Group
+ ble,pn %icc, U3copy_from_user_short ! BR
+
+ /* Large enough to use unrolled prefetch loops? */
+ cmp %o2, 0x100 ! A1
+ bge,a,pt %icc, U3copy_from_user_enter ! BR Group
+ andcc %o0, 0x3f, %g2 ! A0
+
+ ba,pt %xcc, U3copy_from_user_toosmall ! BR Group
+ andcc %o0, 0x7, %g2 ! A0
+
+ .align 32
+U3copy_from_user_short:
+ /* Copy %o2 bytes from src to dst, one byte at a time. */
+ EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS Group
+ add %o1, 0x1, %o1 ! A0
+ add %o0, 0x1, %o0 ! A1
+ subcc %o2, 1, %o2 ! A0 Group
+
+ bg,pt %icc, U3copy_from_user_short ! BR
+ stb %o3, [%o0 + -1] ! MS Group (1-cycle stall)
+
+U3copy_from_user_short_ret:
+#ifdef __KERNEL__
+ retl ! BR Group (0-4 cycle stall)
+ clr %o0 ! A0
+#else
+ retl ! BR Group (0-4 cycle stall)
+ mov %g3, %o0 ! A0
+#endif
+
+ /* Here len >= (6 * 64) and condition codes reflect execution
+ * of "andcc %o0, 0x7, %g2", done by caller.
+ */
+ .align 64
+U3copy_from_user_enter:
+ /* Is 'dst' already aligned on an 64-byte boundary? */
+ be,pt %xcc, 2f ! BR
+
+ /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number
+ * of bytes to copy to make 'dst' 64-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x40, %g2 ! A0 Group
+ sub %g0, %g2, %g2 ! A0 Group
+ sub %o2, %g2, %o2 ! A0 Group
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ stb %o3, [%o0 + -1] ! MS Group
+
+2: VISEntryHalf ! MS+MS
+ and %o1, 0x7, %g1 ! A1
+ ba,pt %xcc, U3copy_from_user_begin ! BR
+ alignaddr %o1, %g0, %o1 ! MS (Break-after)
+
+ .align 64
+U3copy_from_user_begin:
+ prefetcha [%o1 + 0x000] %asi, #one_read ! MS Group1
+ prefetcha [%o1 + 0x040] %asi, #one_read ! MS Group2
+ andn %o2, (0x40 - 1), %o4 ! A0
+ prefetcha [%o1 + 0x080] %asi, #one_read ! MS Group3
+ cmp %o4, 0x140 ! A0
+ prefetcha [%o1 + 0x0c0] %asi, #one_read ! MS Group4
+ EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8)
+ bge,a,pt %icc, 1f ! BR
+
+ prefetcha [%o1 + 0x100] %asi, #one_read ! MS Group6
+1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9)
+ cmp %o4, 0x180 ! A1
+ bge,a,pt %icc, 1f ! BR
+ prefetcha [%o1 + 0x140] %asi, #one_read ! MS Group7
+1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10)
+ cmp %o4, 0x1c0 ! A1
+ bge,a,pt %icc, 1f ! BR
+
+ prefetcha [%o1 + 0x180] %asi, #one_read ! MS Group8
+1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12)
+ EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12)
+ faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13)
+ EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) ! MS (%f8 results at G13)
+ faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15)
+ EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) ! MS (%f10 results at G15)
+ faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16)
+
+ EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) ! MS (%f12 results at G16)
+ faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18)
+ EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) ! MS (%f14 results at G18)
+ faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19)
+ EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) ! MS (%f0 results at G19)
+
+ /* We only use the first loop if len > (7 * 64). */
+ subcc %o4, 0x1c0, %o4 ! A0 Group17
+ bg,pt %icc, U3copy_from_user_loop1 ! BR
+ add %o1, 0x40, %o1 ! A1
+
+ add %o4, 0x140, %o4 ! A0 Group18
+ ba,pt %xcc, U3copy_from_user_loop2 ! BR
+ srl %o4, 6, %o3 ! A0 Group19
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+
+ /* This loop performs the copy and queues new prefetches.
+ * We drop into the second loop when len <= (5 * 64). Note
+ * that this (5 * 64) factor has been subtracted from len
+ * already.
+ */
+U3copy_from_user_loop1:
+ EX2(ldda [%o1 + 0x008] %asi, %f2) ! MS Group2 (%f2 results at G5)
+ faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5)
+ EX2(ldda [%o1 + 0x010] %asi, %f4) ! MS Group3 (%f4 results at G6)
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7)
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ EX2(ldda [%o1 + 0x018] %asi, %f6) ! AX (%f6 results at G7)
+
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+ EX2(ldda [%o1 + 0x020] %asi, %f8) ! MS (%f8 results at G15)
+ faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16)
+ EX2(ldda [%o1 + 0x028] %asi, %f10) ! MS (%f10 results at G16)
+ faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17)
+ EX2(ldda [%o1 + 0x030] %asi, %f12) ! MS (%f12 results at G17)
+ faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18)
+ EX2(ldda [%o1 + 0x038] %asi, %f14) ! MS (%f14 results at G18)
+
+ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19)
+ EX2(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19)
+ prefetcha [%o1 + 0x180] %asi, #one_read ! MS
+ faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20)
+ subcc %o4, 0x40, %o4 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_from_user_loop1 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+U3copy_from_user_loop2_enter:
+ mov 5, %o3 ! A1
+
+ /* This loop performs on the copy, no new prefetches are
+ * queued. We do things this way so that we do not perform
+ * any spurious prefetches past the end of the src buffer.
+ */
+U3copy_from_user_loop2:
+ EX3(ldda [%o1 + 0x008] %asi, %f2) ! MS
+ faligndata %f12, %f14, %f28 ! FGA Group2
+ EX3(ldda [%o1 + 0x010] %asi, %f4) ! MS
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall)
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ EX3(ldda [%o1 + 0x018] %asi, %f6) ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+
+ EX3(ldda [%o1 + 0x020] %asi, %f8) ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group13
+ EX3(ldda [%o1 + 0x028] %asi, %f10) ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group14
+ EX3(ldda [%o1 + 0x030] %asi, %f12) ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group15
+ EX3(ldda [%o1 + 0x038] %asi, %f14) ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group16
+
+ EX3(ldda [%o1 + 0x040] %asi, %f0) ! AX
+ faligndata %f10, %f12, %f26 ! FGA Group17
+ subcc %o3, 0x01, %o3 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_from_user_loop2 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+ /* Finally we copy the last full 64-byte block. */
+U3copy_from_user_loopfini:
+ EX3(ldda [%o1 + 0x008] %asi, %f2) ! MS
+ faligndata %f12, %f14, %f28 ! FGA
+ EX3(ldda [%o1 + 0x010] %asi, %f4) ! MS Group19
+ faligndata %f14, %f0, %f30 ! FGA
+ stda %f16, [%o0] ASI_BLK_P ! MS Group20
+ EX3(ldda [%o1 + 0x018] %asi, %f6) ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall)
+ EX3(ldda [%o1 + 0x020] %asi, %f8) ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group12
+ EX3(ldda [%o1 + 0x028] %asi, %f10) ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group13
+ EX3(ldda [%o1 + 0x030] %asi, %f12) ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group14
+ EX3(ldda [%o1 + 0x038] %asi, %f14) ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group15
+ cmp %g1, 0 ! A0
+ be,pt %icc, 1f ! BR
+ add %o0, 0x40, %o0 ! A1
+ EX4(ldda [%o1 + 0x040] %asi, %f0) ! MS
+1: faligndata %f10, %f12, %f26 ! FGA Group16
+ faligndata %f12, %f14, %f28 ! FGA Group17
+ faligndata %f14, %f0, %f30 ! FGA Group18
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ add %o0, 0x40, %o0 ! A0
+ add %o1, 0x40, %o1 ! A1
+ membar #Sync ! MS Group26 (7-cycle stall)
+
+ /* Now we copy the (len modulo 64) bytes at the end.
+ * Note how we borrow the %f0 loaded above.
+ *
+ * Also notice how this code is careful not to perform a
+ * load past the end of the src buffer just like similar
+ * code found in U3copy_from_user_toosmall processing.
+ */
+U3copy_from_user_loopend:
+ and %o2, 0x3f, %o2 ! A0 Group
+ andcc %o2, 0x38, %g2 ! A0 Group
+ be,pn %icc, U3copy_from_user_endcruft ! BR
+ subcc %g2, 0x8, %g2 ! A1
+ be,pn %icc, U3copy_from_user_endcruft ! BR Group
+ cmp %g1, 0 ! A0
+
+ be,a,pt %icc, 1f ! BR Group
+ EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) ! MS
+
+1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f0, %f2, %f8 ! FGA Group
+ std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX)
+ be,pn %icc, U3copy_from_user_endcruft ! BR
+ add %o0, 0x8, %o0 ! A0
+ EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA
+ std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX)
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A0 Group
+
+ /* If anything is left, we copy it one byte at a time.
+ * Note that %g1 is (src & 0x3) saved above before the
+ * alignaddr was performed.
+ */
+U3copy_from_user_endcruft:
+ cmp %o2, 0
+ add %o1, %g1, %o1
+ VISExitHalf
+ be,pn %icc, U3copy_from_user_short_ret
+ nop
+ ba,a,pt %xcc, U3copy_from_user_short
+
+ /* If we get here, then 32 <= len < (6 * 64) */
+U3copy_from_user_toosmall:
+
+#ifdef SMALL_COPY_USES_FPU
+
+ /* Is 'dst' already aligned on an 8-byte boundary? */
+ be,pt %xcc, 2f ! BR Group
+
+ /* Compute abs((dst & 7) - 8) into %g2. This is the number
+ * of bytes to copy to make 'dst' 8-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x8, %g2 ! A0
+ sub %g0, %g2, %g2 ! A0 Group (reg-dep)
+ sub %o2, %g2, %o2 ! A0 Group (reg-dep)
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) (%o3 in 3 cycles)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ stb %o3, [%o0 + -1] ! MS Group
+
+2: VISEntryHalf ! MS+MS
+
+ /* Compute (len - (len % 8)) into %g2. This is guarenteed
+ * to be nonzero.
+ */
+ andn %o2, 0x7, %g2 ! A0 Group
+
+ /* You may read this and believe that it allows reading
+ * one 8-byte longword past the end of src. It actually
+ * does not, as %g2 is subtracted as loads are done from
+ * src, so we always stop before running off the end.
+ * Also, we are guarenteed to have at least 0x10 bytes
+ * to move here.
+ */
+ sub %g2, 0x8, %g2 ! A0 Group (reg-dep)
+ alignaddr %o1, %g0, %g1 ! MS (Break-after)
+ EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group (1-cycle stall)
+ add %g1, 0x8, %g1 ! A0
+
+1: EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0) ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+
+ faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall)
+ std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+ be,pn %icc, 2f ! BR
+
+ add %o0, 0x8, %o0 ! A1
+ EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall)
+ std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A1
+
+ /* Nothing left to copy? */
+2: cmp %o2, 0 ! A0 Group
+ VISExitHalf ! A0+MS
+ be,pn %icc, U3copy_from_user_short_ret! BR Group
+ nop ! A0
+ ba,a,pt %xcc, U3copy_from_user_short ! BR Group
+
+#else /* !(SMALL_COPY_USES_FPU) */
+
+ xor %o1, %o0, %g2
+ andcc %g2, 0x7, %g0
+ bne,pn %icc, U3copy_from_user_short
+ andcc %o1, 0x7, %g2
+
+ be,pt %xcc, 2f
+ sub %g2, 0x8, %g2
+ sub %g0, %g2, %g2
+ sub %o2, %g2, %o2
+
+1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+ add %o1, 0x1, %o1
+ add %o0, 0x1, %o0
+ subcc %g2, 0x1, %g2
+ bg,pt %icc, 1b
+ stb %o3, [%o0 + -1]
+
+2: andn %o2, 0x7, %g2
+ sub %o2, %g2, %o2
+
+3: EXNV(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+ add %o1, 0x8, %o1
+ add %o0, 0x8, %o0
+ subcc %g2, 0x8, %g2
+ bg,pt %icc, 3b
+ stx %o3, [%o0 + -8]
+
+ cmp %o2, 0
+ bne,pn %icc, U3copy_from_user_short
+ nop
+ ba,a,pt %xcc, U3copy_from_user_short_ret
+
+#endif /* !(SMALL_COPY_USES_FPU) */
+
+#ifdef __KERNEL__
+ .globl U3cfu_fixup
+U3cfu_fixup:
+ /* Since this is copy_from_user(), zero out the rest of the
+ * kernel buffer.
+ */
+ cmp %o1, 0
+ ble,pn %icc, 2f
+ mov %o1, %g2
+
+1: subcc %g2, 1, %g2
+ stb %g0, [%o0]
+ bne,pt %icc, 1b
+ add %o0, 1, %o0
+
+2: retl
+ mov %o1, %o0
+#endif
--- /dev/null
+/* $Id: U3copy_in_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
+ * U3memcpy.S: UltraSparc-III optimized copy within userspace.
+ *
+ * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#undef SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: retl; \
+ a, b, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXNV2(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: a, b, %o0; \
+ retl; \
+ add %o0, 1, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXNV3(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: a, b, %o0; \
+ retl; \
+ add %o0, 8, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ retl; \
+ a, b, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK1(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ add %o4, 0x1c0, %o1; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o1, %o2, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK2(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ sll %o3, 6, %o3; \
+ and %o2, (0x40 - 1), %o2; \
+ add %o3, 0x80, %o1; \
+ retl; \
+ add %o1, %o2, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK3(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o2, 0x80, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK4(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o2, 0x40, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#else
+#define ASI_AIUS 0x80
+#define ASI_BLK_AIUS 0xf0
+#define FPRS_FEF 0x04
+#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#define SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) x,y;
+#define EXNV2(x,y,a,b) x,y;
+#define EXNV3(x,y,a,b) x,y;
+#define EX(x,y,a,b) x,y;
+#define EXBLK1(x,y) x,y;
+#define EXBLK2(x,y) x,y;
+#define EXBLK3(x,y) x,y;
+#define EXBLK4(x,y) x,y;
+#endif
+
+ /* Special/non-trivial issues of this code:
+ *
+ * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
+ * 2) Only low 32 FPU registers are used so that only the
+ * lower half of the FPU register set is dirtied by this
+ * code. This is especially important in the kernel.
+ * 3) This code never prefetches cachelines past the end
+ * of the source buffer.
+ *
+ * XXX Actually, Cheetah can buffer up to 8 concurrent
+ * XXX prefetches, revisit this...
+ */
+
+ .text
+ .align 32
+
+ /* The cheetah's flexible spine, oversized liver, enlarged heart,
+ * slender muscular body, and claws make it the swiftest hunter
+ * in Africa and the fastest animal on land. Can reach speeds
+ * of up to 2.4GB per second.
+ */
+
+ .globl U3copy_in_user
+U3copy_in_user: /* %o0=dst, %o1=src, %o2=len */
+ /* Writing to %asi is _expensive_ so we hardcode it.
+ * Reading %asi to check for KERNEL_DS is comparatively
+ * cheap.
+ */
+ rd %asi, %g1 ! MS Group (4 cycles)
+ cmp %g1, ASI_AIUS ! A0 Group
+ bne U3memcpy ! BR
+ nop ! A1
+#ifndef __KERNEL__
+ /* Save away original 'dst' for memcpy return value. */
+ mov %o0, %g3 ! A0 Group
+#endif
+ /* Anything to copy at all? */
+ cmp %o2, 0 ! A1
+ ble,pn %icc, U3copy_in_user_short_ret ! BR
+
+ /* Extremely small copy? */
+ cmp %o2, 31 ! A0 Group
+ ble,pn %icc, U3copy_in_user_short ! BR
+
+ /* Large enough to use unrolled prefetch loops? */
+ cmp %o2, 0x100 ! A1
+ bge,a,pt %icc, U3copy_in_user_enter ! BR Group
+ andcc %o0, 0x3f, %g2 ! A0
+
+ ba,pt %xcc, U3copy_in_user_toosmall ! BR Group
+ andcc %o0, 0x7, %g2 ! A0
+
+ .align 32
+U3copy_in_user_short:
+ /* Copy %o2 bytes from src to dst, one byte at a time. */
+ EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS Group
+ add %o1, 0x1, %o1 ! A0
+ add %o0, 0x1, %o0 ! A1
+ subcc %o2, 1, %o2 ! A0 Group
+
+ bg,pt %icc, U3copy_in_user_short ! BR
+ EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1) ! MS Group (1-cycle stall)
+
+U3copy_in_user_short_ret:
+#ifdef __KERNEL__
+ retl ! BR Group (0-4 cycle stall)
+ clr %o0 ! A0
+#else
+ retl ! BR Group (0-4 cycle stall)
+ mov %g3, %o0 ! A0
+#endif
+
+ /* Here len >= (6 * 64) and condition codes reflect execution
+ * of "andcc %o0, 0x7, %g2", done by caller.
+ */
+ .align 64
+U3copy_in_user_enter:
+ /* Is 'dst' already aligned on an 64-byte boundary? */
+ be,pt %xcc, 2f ! BR
+
+ /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number
+ * of bytes to copy to make 'dst' 64-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x40, %g2 ! A0 Group
+ sub %g0, %g2, %g2 ! A0 Group
+ sub %o2, %g2, %o2 ! A0 Group
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group
+
+2: VISEntryHalf ! MS+MS
+ and %o1, 0x7, %g1 ! A1
+ ba,pt %xcc, U3copy_in_user_begin ! BR
+ alignaddr %o1, %g0, %o1 ! MS (Break-after)
+
+ .align 64
+U3copy_in_user_begin:
+ prefetch [%o1 + 0x000], #one_read ! MS Group1
+ prefetch [%o1 + 0x040], #one_read ! MS Group2
+ andn %o2, (0x40 - 1), %o4 ! A0
+ prefetch [%o1 + 0x080], #one_read ! MS Group3
+ cmp %o4, 0x140 ! A0
+ prefetch [%o1 + 0x0c0], #one_read ! MS Group4
+ EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8)
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x100], #one_read ! MS Group6
+1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9)
+ cmp %o4, 0x180 ! A1
+ bge,a,pt %icc, 1f ! BR
+ prefetch [%o1 + 0x140], #one_read ! MS Group7
+1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10)
+ cmp %o4, 0x1c0 ! A1
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x180], #one_read ! MS Group8
+1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12)
+ EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12)
+ faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13)
+ EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) ! MS (%f8 results at G13)
+ faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15)
+ EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) ! MS (%f10 results at G15)
+ faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16)
+
+ EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) ! MS (%f12 results at G16)
+ faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18)
+ EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) ! MS (%f14 results at G18)
+ faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19)
+ EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) ! MS (%f0 results at G19)
+
+ /* We only use the first loop if len > (7 * 64). */
+ subcc %o4, 0x1c0, %o4 ! A0 Group17
+ bg,pt %icc, U3copy_in_user_loop1 ! BR
+ add %o1, 0x40, %o1 ! A1
+
+ add %o4, 0x140, %o4 ! A0 Group18
+ ba,pt %xcc, U3copy_in_user_loop2 ! BR
+ srl %o4, 6, %o3 ! A0 Group19
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+
+ /* This loop performs the copy and queues new prefetches.
+ * We drop into the second loop when len <= (5 * 64). Note
+ * that this (5 * 64) factor has been subtracted from len
+ * already.
+ */
+U3copy_in_user_loop1:
+ EXBLK1(ldda [%o1 + 0x008] %asi, %f2) ! MS Group2 (%f2 results at G5)
+ faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5)
+ EXBLK1(ldda [%o1 + 0x010] %asi, %f4) ! MS Group3 (%f4 results at G6)
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7)
+ EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ EXBLK1(ldda [%o1 + 0x018] %asi, %f6) ! AX (%f6 results at G7)
+
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+ EXBLK1(ldda [%o1 + 0x020] %asi, %f8) ! MS (%f8 results at G15)
+ faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16)
+ EXBLK1(ldda [%o1 + 0x028] %asi, %f10) ! MS (%f10 results at G16)
+ faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17)
+ EXBLK1(ldda [%o1 + 0x030] %asi, %f12) ! MS (%f12 results at G17)
+ faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18)
+ EXBLK1(ldda [%o1 + 0x038] %asi, %f14) ! MS (%f14 results at G18)
+
+ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19)
+ EXBLK1(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19)
+ prefetch [%o1 + 0x180], #one_read ! MS
+ faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20)
+ subcc %o4, 0x40, %o4 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_in_user_loop1 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+U3copy_in_user_loop2_enter:
+ mov 5, %o3 ! A1
+
+ /* This loop performs on the copy, no new prefetches are
+ * queued. We do things this way so that we do not perform
+ * any spurious prefetches past the end of the src buffer.
+ */
+U3copy_in_user_loop2:
+ EXBLK2(ldda [%o1 + 0x008] %asi, %f2) ! MS
+ faligndata %f12, %f14, %f28 ! FGA Group2
+ EXBLK2(ldda [%o1 + 0x010] %asi, %f4) ! MS
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall)
+ EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ EXBLK2(ldda [%o1 + 0x018] %asi, %f6) ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+
+ EXBLK2(ldda [%o1 + 0x020] %asi, %f8) ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group13
+ EXBLK2(ldda [%o1 + 0x028] %asi, %f10) ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group14
+ EXBLK2(ldda [%o1 + 0x030] %asi, %f12) ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group15
+ EXBLK2(ldda [%o1 + 0x038] %asi, %f14) ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group16
+
+ EXBLK2(ldda [%o1 + 0x040] %asi, %f0) ! AX
+ faligndata %f10, %f12, %f26 ! FGA Group17
+ subcc %o3, 0x01, %o3 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_in_user_loop2 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+ /* Finally we copy the last full 64-byte block. */
+U3copy_in_user_loopfini:
+ EXBLK3(ldda [%o1 + 0x008] %asi, %f2) ! MS
+ faligndata %f12, %f14, %f28 ! FGA
+ EXBLK3(ldda [%o1 + 0x010] %asi, %f4) ! MS Group19
+ faligndata %f14, %f0, %f30 ! FGA
+ EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) ! MS Group20
+ EXBLK4(ldda [%o1 + 0x018] %asi, %f6) ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall)
+ EXBLK4(ldda [%o1 + 0x020] %asi, %f8) ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group12
+ EXBLK4(ldda [%o1 + 0x028] %asi, %f10) ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group13
+ EXBLK4(ldda [%o1 + 0x030] %asi, %f12) ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group14
+ EXBLK4(ldda [%o1 + 0x038] %asi, %f14) ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group15
+ cmp %g1, 0 ! A0
+ be,pt %icc, 1f ! BR
+ add %o0, 0x40, %o0 ! A1
+ EXBLK4(ldda [%o1 + 0x040] %asi, %f0) ! MS
+1: faligndata %f10, %f12, %f26 ! FGA Group16
+ faligndata %f12, %f14, %f28 ! FGA Group17
+ faligndata %f14, %f0, %f30 ! FGA Group18
+ EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ add %o0, 0x40, %o0 ! A0
+ add %o1, 0x40, %o1 ! A1
+ membar #Sync ! MS Group26 (7-cycle stall)
+
+ /* Now we copy the (len modulo 64) bytes at the end.
+ * Note how we borrow the %f0 loaded above.
+ *
+ * Also notice how this code is careful not to perform a
+ * load past the end of the src buffer just like similar
+ * code found in U3copy_in_user_toosmall processing.
+ */
+U3copy_in_user_loopend:
+ and %o2, 0x3f, %o2 ! A0 Group
+ andcc %o2, 0x38, %g2 ! A0 Group
+ be,pn %icc, U3copy_in_user_endcruft ! BR
+ subcc %g2, 0x8, %g2 ! A1
+ be,pn %icc, U3copy_in_user_endcruft ! BR Group
+ cmp %g1, 0 ! A0
+
+ be,a,pt %icc, 1f ! BR Group
+ EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) ! MS
+
+1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f0, %f2, %f8 ! FGA Group
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX)
+ be,pn %icc, U3copy_in_user_endcruft ! BR
+ add %o0, 0x8, %o0 ! A0
+ EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX)
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A0 Group
+
+ /* If anything is left, we copy it one byte at a time.
+ * Note that %g1 is (src & 0x3) saved above before the
+ * alignaddr was performed.
+ */
+U3copy_in_user_endcruft:
+ cmp %o2, 0
+ add %o1, %g1, %o1
+ VISExitHalf
+ be,pn %icc, U3copy_in_user_short_ret
+ nop
+ ba,a,pt %xcc, U3copy_in_user_short
+
+ /* If we get here, then 32 <= len < (6 * 64) */
+U3copy_in_user_toosmall:
+
+#ifdef SMALL_COPY_USES_FPU
+
+ /* Is 'dst' already aligned on an 8-byte boundary? */
+ be,pt %xcc, 2f ! BR Group
+
+ /* Compute abs((dst & 7) - 8) into %g2. This is the number
+ * of bytes to copy to make 'dst' 8-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x8, %g2 ! A0
+ sub %g0, %g2, %g2 ! A0 Group (reg-dep)
+ sub %o2, %g2, %o2 ! A0 Group (reg-dep)
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) (%o3 in 3 cycles)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group
+
+2: VISEntryHalf ! MS+MS
+
+ /* Compute (len - (len % 8)) into %g2. This is guarenteed
+ * to be nonzero.
+ */
+ andn %o2, 0x7, %g2 ! A0 Group
+
+ /* You may read this and believe that it allows reading
+ * one 8-byte longword past the end of src. It actually
+ * does not, as %g2 is subtracted as loads are done from
+ * src, so we always stop before running off the end.
+ * Also, we are guarenteed to have at least 0x10 bytes
+ * to move here.
+ */
+ sub %g2, 0x8, %g2 ! A0 Group (reg-dep)
+ alignaddr %o1, %g0, %g1 ! MS (Break-after)
+ EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group (1-cycle stall)
+ add %g1, 0x8, %g1 ! A0
+
+1: EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0) ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+
+ faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall)
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+ be,pn %icc, 2f ! BR
+
+ add %o0, 0x8, %o0 ! A1
+ EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall)
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A1
+
+ /* Nothing left to copy? */
+2: cmp %o2, 0 ! A0 Group
+ VISExitHalf ! A0+MS
+ be,pn %icc, U3copy_in_user_short_ret ! BR Group
+ nop ! A0
+ ba,a,pt %xcc, U3copy_in_user_short ! BR Group
+
+#else /* !(SMALL_COPY_USES_FPU) */
+
+ xor %o1, %o0, %g2
+ andcc %g2, 0x7, %g0
+ bne,pn %icc, U3copy_in_user_short
+ andcc %o1, 0x7, %g2
+
+ be,pt %xcc, 2f
+ sub %g2, 0x8, %g2
+ sub %g0, %g2, %g2
+ sub %o2, %g2, %o2
+
+1: EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+ add %o1, 0x1, %o1
+ add %o0, 0x1, %o0
+ subcc %g2, 0x1, %g2
+ bg,pt %icc, 1b
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)
+
+2: andn %o2, 0x7, %g2
+ sub %o2, %g2, %o2
+
+3: EXNV3(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+ add %o1, 0x8, %o1
+ add %o0, 0x8, %o0
+ subcc %g2, 0x8, %g2
+ bg,pt %icc, 3b
+ EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2)
+
+ cmp %o2, 0
+ bne,pn %icc, U3copy_in_user_short
+ nop
+ ba,a,pt %xcc, U3copy_in_user_short_ret
+
+#endif /* !(SMALL_COPY_USES_FPU) */
--- /dev/null
+/* $Id: U3copy_to_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
+ * U3memcpy.S: UltraSparc-III optimized copy to userspace.
+ *
+ * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#undef SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: retl; \
+ a, b, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXNV2(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: a, b, %o0; \
+ retl; \
+ add %o0, 1, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXNV3(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: a, b, %o0; \
+ retl; \
+ add %o0, 8, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ retl; \
+ a, b, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK1(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ add %o4, 0x1c0, %o1; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o1, %o2, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK2(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ sll %o3, 6, %o3; \
+ and %o2, (0x40 - 1), %o2; \
+ add %o3, 0x80, %o1; \
+ retl; \
+ add %o1, %o2, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK3(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o2, 0x80, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK4(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o2, 0x40, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#else
+#define ASI_AIUS 0x80
+#define ASI_BLK_AIUS 0xf0
+#define FPRS_FEF 0x04
+#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#define SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) x,y;
+#define EXNV2(x,y,a,b) x,y;
+#define EXNV3(x,y,a,b) x,y;
+#define EX(x,y,a,b) x,y;
+#define EXBLK1(x,y) x,y;
+#define EXBLK2(x,y) x,y;
+#define EXBLK3(x,y) x,y;
+#define EXBLK4(x,y) x,y;
+#endif
+
+ /* Special/non-trivial issues of this code:
+ *
+ * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
+ * 2) Only low 32 FPU registers are used so that only the
+ * lower half of the FPU register set is dirtied by this
+ * code. This is especially important in the kernel.
+ * 3) This code never prefetches cachelines past the end
+ * of the source buffer.
+ */
+
+ .text
+ .align 32
+
+ /* The cheetah's flexible spine, oversized liver, enlarged heart,
+ * slender muscular body, and claws make it the swiftest hunter
+ * in Africa and the fastest animal on land. Can reach speeds
+ * of up to 2.4GB per second.
+ */
+
+ .globl U3copy_to_user
+U3copy_to_user: /* %o0=dst, %o1=src, %o2=len */
+ /* Writing to %asi is _expensive_ so we hardcode it.
+ * Reading %asi to check for KERNEL_DS is comparatively
+ * cheap.
+ */
+ rd %asi, %g1 ! MS Group (4 cycles)
+ cmp %g1, ASI_AIUS ! A0 Group
+ bne U3memcpy ! BR
+ nop ! A1
+#ifndef __KERNEL__
+ /* Save away original 'dst' for memcpy return value. */
+ mov %o0, %g3 ! A0 Group
+#endif
+ /* Anything to copy at all? */
+ cmp %o2, 0 ! A1
+ ble,pn %icc, U3copy_to_user_short_ret ! BR
+
+ /* Extremely small copy? */
+ cmp %o2, 31 ! A0 Group
+ ble,pn %icc, U3copy_to_user_short ! BR
+
+ /* Large enough to use unrolled prefetch loops? */
+ cmp %o2, 0x100 ! A1
+ bge,a,pt %icc, U3copy_to_user_enter ! BR Group
+ andcc %o0, 0x3f, %g2 ! A0
+
+ ba,pt %xcc, U3copy_to_user_toosmall ! BR Group
+ andcc %o0, 0x7, %g2 ! A0
+
+ .align 32
+U3copy_to_user_short:
+ /* Copy %o2 bytes from src to dst, one byte at a time. */
+ ldub [%o1 + 0x00], %o3 ! MS Group
+ add %o1, 0x1, %o1 ! A0
+ add %o0, 0x1, %o0 ! A1
+ subcc %o2, 1, %o2 ! A0 Group
+
+ bg,pt %icc, U3copy_to_user_short ! BR
+ EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1) ! MS Group (1-cycle stall)
+
+U3copy_to_user_short_ret:
+#ifdef __KERNEL__
+ retl ! BR Group (0-4 cycle stall)
+ clr %o0 ! A0
+#else
+ retl ! BR Group (0-4 cycle stall)
+ mov %g3, %o0 ! A0
+#endif
+
+ /* Here len >= (6 * 64) and condition codes reflect execution
+ * of "andcc %o0, 0x7, %g2", done by caller.
+ */
+ .align 64
+U3copy_to_user_enter:
+ /* Is 'dst' already aligned on an 64-byte boundary? */
+ be,pt %xcc, 2f ! BR
+
+ /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number
+ * of bytes to copy to make 'dst' 64-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x40, %g2 ! A0 Group
+ sub %g0, %g2, %g2 ! A0 Group
+ sub %o2, %g2, %o2 ! A0 Group
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: ldub [%o1 + 0x00], %o3 ! MS (Group)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group
+
+2: VISEntryHalf ! MS+MS
+ and %o1, 0x7, %g1 ! A1
+ ba,pt %xcc, U3copy_to_user_begin ! BR
+ alignaddr %o1, %g0, %o1 ! MS (Break-after)
+
+ .align 64
+U3copy_to_user_begin:
+ prefetch [%o1 + 0x000], #one_read ! MS Group1
+ prefetch [%o1 + 0x040], #one_read ! MS Group2
+ andn %o2, (0x40 - 1), %o4 ! A0
+ prefetch [%o1 + 0x080], #one_read ! MS Group3
+ cmp %o4, 0x140 ! A0
+ prefetch [%o1 + 0x0c0], #one_read ! MS Group4
+ ldd [%o1 + 0x000], %f0 ! MS Group5 (%f0 results at G8)
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x100], #one_read ! MS Group6
+1: ldd [%o1 + 0x008], %f2 ! AX (%f2 results at G9)
+ cmp %o4, 0x180 ! A1
+ bge,a,pt %icc, 1f ! BR
+ prefetch [%o1 + 0x140], #one_read ! MS Group7
+1: ldd [%o1 + 0x010], %f4 ! AX (%f4 results at G10)
+ cmp %o4, 0x1c0 ! A1
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x180], #one_read ! MS Group8
+1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12)
+ ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G12)
+ faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13)
+ ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G13)
+ faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15)
+ ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G15)
+ faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16)
+
+ ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G16)
+ faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18)
+ ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18)
+ faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19)
+ ldd [%o1 + 0x040], %f0 ! MS (%f0 results at G19)
+
+ /* We only use the first loop if len > (7 * 64). */
+ subcc %o4, 0x1c0, %o4 ! A0 Group17
+ bg,pt %icc, U3copy_to_user_loop1 ! BR
+ add %o1, 0x40, %o1 ! A1
+
+ add %o4, 0x140, %o4 ! A0 Group18
+ ba,pt %xcc, U3copy_to_user_loop2 ! BR
+ srl %o4, 6, %o3 ! A0 Group19
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+
+ /* This loop performs the copy and queues new prefetches.
+ * We drop into the second loop when len <= (5 * 64). Note
+ * that this (5 * 64) factor has been subtracted from len
+ * already.
+ */
+U3copy_to_user_loop1:
+ ldd [%o1 + 0x008], %f2 ! MS Group2 (%f2 results at G5)
+ faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5)
+ ldd [%o1 + 0x010], %f4 ! MS Group3 (%f4 results at G6)
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7)
+ EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G7)
+
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+ ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G15)
+ faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16)
+ ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G16)
+ faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17)
+ ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G17)
+ faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18)
+ ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18)
+
+ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19)
+ ldd [%o1 + 0x040], %f0 ! AX (%f0 results at G19)
+ prefetch [%o1 + 0x180], #one_read ! MS
+ faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20)
+ subcc %o4, 0x40, %o4 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_to_user_loop1 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+U3copy_to_user_loop2_enter:
+ mov 5, %o3 ! A1
+
+ /* This loop performs on the copy, no new prefetches are
+ * queued. We do things this way so that we do not perform
+ * any spurious prefetches past the end of the src buffer.
+ */
+U3copy_to_user_loop2:
+ ldd [%o1 + 0x008], %f2 ! MS
+ faligndata %f12, %f14, %f28 ! FGA Group2
+ ldd [%o1 + 0x010], %f4 ! MS
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall)
+ EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ ldd [%o1 + 0x018], %f6 ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+
+ ldd [%o1 + 0x020], %f8 ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group13
+ ldd [%o1 + 0x028], %f10 ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group14
+ ldd [%o1 + 0x030], %f12 ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group15
+ ldd [%o1 + 0x038], %f14 ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group16
+
+ ldd [%o1 + 0x040], %f0 ! AX
+ faligndata %f10, %f12, %f26 ! FGA Group17
+ subcc %o3, 0x01, %o3 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_to_user_loop2 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+ /* Finally we copy the last full 64-byte block. */
+U3copy_to_user_loopfini:
+ ldd [%o1 + 0x008], %f2 ! MS
+ faligndata %f12, %f14, %f28 ! FGA
+ ldd [%o1 + 0x010], %f4 ! MS Group19
+ faligndata %f14, %f0, %f30 ! FGA
+ EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) ! MS Group20
+ ldd [%o1 + 0x018], %f6 ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall)
+ ldd [%o1 + 0x020], %f8 ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group12
+ ldd [%o1 + 0x028], %f10 ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group13
+ ldd [%o1 + 0x030], %f12 ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group14
+ ldd [%o1 + 0x038], %f14 ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group15
+ cmp %g1, 0 ! A0
+ be,pt %icc, 1f ! BR
+ add %o0, 0x40, %o0 ! A1
+ ldd [%o1 + 0x040], %f0 ! MS
+1: faligndata %f10, %f12, %f26 ! FGA Group16
+ faligndata %f12, %f14, %f28 ! FGA Group17
+ faligndata %f14, %f0, %f30 ! FGA Group18
+ EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ add %o0, 0x40, %o0 ! A0
+ add %o1, 0x40, %o1 ! A1
+ membar #Sync ! MS Group26 (7-cycle stall)
+
+ /* Now we copy the (len modulo 64) bytes at the end.
+ * Note how we borrow the %f0 loaded above.
+ *
+ * Also notice how this code is careful not to perform a
+ * load past the end of the src buffer just like similar
+ * code found in U3copy_to_user_toosmall processing.
+ */
+U3copy_to_user_loopend:
+ and %o2, 0x3f, %o2 ! A0 Group
+ andcc %o2, 0x38, %g2 ! A0 Group
+ be,pn %icc, U3copy_to_user_endcruft ! BR
+ subcc %g2, 0x8, %g2 ! A1
+ be,pn %icc, U3copy_to_user_endcruft ! BR Group
+ cmp %g1, 0 ! A0
+
+ be,a,pt %icc, 1f ! BR Group
+ ldd [%o1 + 0x00], %f0 ! MS
+
+1: ldd [%o1 + 0x08], %f2 ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f0, %f2, %f8 ! FGA Group
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX)
+ be,pn %icc, U3copy_to_user_endcruft ! BR
+ add %o0, 0x8, %o0 ! A0
+ ldd [%o1 + 0x08], %f0 ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX)
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A0 Group
+
+ /* If anything is left, we copy it one byte at a time.
+ * Note that %g1 is (src & 0x3) saved above before the
+ * alignaddr was performed.
+ */
+U3copy_to_user_endcruft:
+ cmp %o2, 0
+ add %o1, %g1, %o1
+ VISExitHalf
+ be,pn %icc, U3copy_to_user_short_ret
+ nop
+ ba,a,pt %xcc, U3copy_to_user_short
+
+ /* If we get here, then 32 <= len < (6 * 64) */
+U3copy_to_user_toosmall:
+
+#ifdef SMALL_COPY_USES_FPU
+
+ /* Is 'dst' already aligned on an 8-byte boundary? */
+ be,pt %xcc, 2f ! BR Group
+
+ /* Compute abs((dst & 7) - 8) into %g2. This is the number
+ * of bytes to copy to make 'dst' 8-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x8, %g2 ! A0
+ sub %g0, %g2, %g2 ! A0 Group (reg-dep)
+ sub %o2, %g2, %o2 ! A0 Group (reg-dep)
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: ldub [%o1 + 0x00], %o3 ! MS (Group) (%o3 in 3 cycles)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group
+
+2: VISEntryHalf ! MS+MS
+
+ /* Compute (len - (len % 8)) into %g2. This is guarenteed
+ * to be nonzero.
+ */
+ andn %o2, 0x7, %g2 ! A0 Group
+
+ /* You may read this and believe that it allows reading
+ * one 8-byte longword past the end of src. It actually
+ * does not, as %g2 is subtracted as loads are done from
+ * src, so we always stop before running off the end.
+ * Also, we are guarenteed to have at least 0x10 bytes
+ * to move here.
+ */
+ sub %g2, 0x8, %g2 ! A0 Group (reg-dep)
+ alignaddr %o1, %g0, %g1 ! MS (Break-after)
+ ldd [%g1 + 0x00], %f0 ! MS Group (1-cycle stall)
+ add %g1, 0x8, %g1 ! A0
+
+1: ldd [%g1 + 0x00], %f2 ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+
+ faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall)
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+ be,pn %icc, 2f ! BR
+
+ add %o0, 0x8, %o0 ! A1
+ ldd [%g1 + 0x00], %f0 ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall)
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A1
+
+ /* Nothing left to copy? */
+2: cmp %o2, 0 ! A0 Group
+ VISExitHalf ! A0+MS
+ be,pn %icc, U3copy_to_user_short_ret ! BR Group
+ nop ! A0
+ ba,a,pt %xcc, U3copy_to_user_short ! BR Group
+
+#else /* !(SMALL_COPY_USES_FPU) */
+
+ xor %o1, %o0, %g2
+ andcc %g2, 0x7, %g0
+ bne,pn %icc, U3copy_to_user_short
+ andcc %o1, 0x7, %g2
+
+ be,pt %xcc, 2f
+ sub %g2, 0x8, %g2
+ sub %g0, %g2, %g2
+ sub %o2, %g2, %o2
+
+1: ldub [%o1 + 0x00], %o3
+ add %o1, 0x1, %o1
+ add %o0, 0x1, %o0
+ subcc %g2, 0x1, %g2
+ bg,pt %icc, 1b
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)
+
+2: andn %o2, 0x7, %g2
+ sub %o2, %g2, %o2
+
+3: ldx [%o1 + 0x00], %o3
+ add %o1, 0x8, %o1
+ add %o0, 0x8, %o0
+ subcc %g2, 0x8, %g2
+ bg,pt %icc, 3b
+ EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2)
+
+ cmp %o2, 0
+ bne,pn %icc, U3copy_to_user_short
+ nop
+ ba,a,pt %xcc, U3copy_to_user_short_ret
+
+#endif /* !(SMALL_COPY_USES_FPU) */
--- /dev/null
+/* $Id: U3memcpy.S,v 1.2 2000/11/01 09:29:19 davem Exp $
+ * U3memcpy.S: UltraSparc-III optimized memcpy.
+ *
+ * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#undef SMALL_COPY_USES_FPU
+#else
+#define ASI_BLK_P 0xf0
+#define FPRS_FEF 0x04
+#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#define SMALL_COPY_USES_FPU
+#endif
+
+ /* Special/non-trivial issues of this code:
+ *
+ * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
+ * 2) Only low 32 FPU registers are used so that only the
+ * lower half of the FPU register set is dirtied by this
+ * code. This is especially important in the kernel.
+ * 3) This code never prefetches cachelines past the end
+ * of the source buffer.
+ */
+
+ .text
+ .align 32
+
+ /* The cheetah's flexible spine, oversized liver, enlarged heart,
+ * slender muscular body, and claws make it the swiftest hunter
+ * in Africa and the fastest animal on land. Can reach speeds
+ * of up to 2.4GB per second.
+ */
+
+ .globl U3memcpy
+U3memcpy: /* %o0=dst, %o1=src, %o2=len */
+#ifndef __KERNEL__
+ /* Save away original 'dst' for memcpy return value. */
+ mov %o0, %g3 ! A0 Group
+#endif
+ /* Anything to copy at all? */
+ cmp %o2, 0 ! A1
+ ble,pn %icc, U3memcpy_short_ret ! BR
+
+ /* Extremely small copy? */
+ cmp %o2, 31 ! A0 Group
+ ble,pn %icc, U3memcpy_short ! BR
+
+ /* Large enough to use unrolled prefetch loops? */
+ cmp %o2, 0x100 ! A1
+ bge,a,pt %icc, U3memcpy_enter ! BR Group
+ andcc %o0, 0x3f, %g2 ! A0
+
+ ba,pt %xcc, U3memcpy_toosmall ! BR Group
+ andcc %o0, 0x7, %g2 ! A0
+
+ .align 32
+U3memcpy_short:
+ /* Copy %o2 bytes from src to dst, one byte at a time. */
+ ldub [%o1 + 0x00], %o3 ! MS Group
+ add %o1, 0x1, %o1 ! A0
+ add %o0, 0x1, %o0 ! A1
+ subcc %o2, 1, %o2 ! A0 Group
+
+ bg,pt %icc, U3memcpy_short ! BR
+ stb %o3, [%o0 + -1] ! MS Group (1-cycle stall)
+
+U3memcpy_short_ret:
+#ifdef __KERNEL__
+ retl ! BR Group (0-4 cycle stall)
+ clr %o0 ! A0
+#else
+ retl ! BR Group (0-4 cycle stall)
+ mov %g3, %o0 ! A0
+#endif
+
+ /* Here len >= (6 * 64) and condition codes reflect execution
+ * of "andcc %o0, 0x7, %g2", done by caller.
+ */
+ .align 64
+U3memcpy_enter:
+ /* Is 'dst' already aligned on an 64-byte boundary? */
+ be,pt %xcc, 2f ! BR
+
+ /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number
+ * of bytes to copy to make 'dst' 64-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x40, %g2 ! A0 Group
+ sub %g0, %g2, %g2 ! A0 Group
+ sub %o2, %g2, %o2 ! A0 Group
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: ldub [%o1 + 0x00], %o3 ! MS (Group)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ stb %o3, [%o0 + -1] ! MS Group
+
+2: VISEntryHalf ! MS+MS
+ and %o1, 0x7, %g1 ! A1
+ ba,pt %xcc, U3memcpy_begin ! BR
+ alignaddr %o1, %g0, %o1 ! MS (Break-after)
+
+ .align 64
+U3memcpy_begin:
+ prefetch [%o1 + 0x000], #one_read ! MS Group1
+ prefetch [%o1 + 0x040], #one_read ! MS Group2
+ andn %o2, (0x40 - 1), %o4 ! A0
+ prefetch [%o1 + 0x080], #one_read ! MS Group3
+ cmp %o4, 0x140 ! A0
+ prefetch [%o1 + 0x0c0], #one_read ! MS Group4
+ ldd [%o1 + 0x000], %f0 ! MS Group5 (%f0 results at G8)
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x100], #one_read ! MS Group6
+1: ldd [%o1 + 0x008], %f2 ! AX (%f2 results at G9)
+ cmp %o4, 0x180 ! A1
+ bge,a,pt %icc, 1f ! BR
+ prefetch [%o1 + 0x140], #one_read ! MS Group7
+1: ldd [%o1 + 0x010], %f4 ! AX (%f4 results at G10)
+ cmp %o4, 0x1c0 ! A1
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x180], #one_read ! MS Group8
+1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12)
+ ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G12)
+ faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13)
+ ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G13)
+ faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15)
+ ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G15)
+ faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16)
+
+ ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G16)
+ faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18)
+ ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18)
+ faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19)
+ ldd [%o1 + 0x040], %f0 ! MS (%f0 results at G19)
+
+ /* We only use the first loop if len > (7 * 64). */
+ subcc %o4, 0x1c0, %o4 ! A0 Group17
+ bg,pt %icc, U3memcpy_loop1 ! BR
+ add %o1, 0x40, %o1 ! A1
+
+ add %o4, 0x140, %o4 ! A0 Group18
+ ba,pt %xcc, U3memcpy_loop2 ! BR
+ srl %o4, 6, %o3 ! A0 Group19
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+
+ /* This loop performs the copy and queues new prefetches.
+ * We drop into the second loop when len <= (5 * 64). Note
+ * that this (5 * 64) factor has been subtracted from len
+ * already.
+ */
+U3memcpy_loop1:
+ ldd [%o1 + 0x008], %f2 ! MS Group2 (%f2 results at G5)
+ faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5)
+ ldd [%o1 + 0x010], %f4 ! MS Group3 (%f4 results at G6)
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7)
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G7)
+
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+ ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G15)
+ faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16)
+ ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G16)
+ faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17)
+ ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G17)
+ faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18)
+ ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18)
+
+ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19)
+ ldd [%o1 + 0x040], %f0 ! AX (%f0 results at G19)
+ prefetch [%o1 + 0x180], #one_read ! MS
+ faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20)
+ subcc %o4, 0x40, %o4 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3memcpy_loop1 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+U3memcpy_loop2_enter:
+ mov 5, %o3 ! A1
+
+ /* This loop performs on the copy, no new prefetches are
+ * queued. We do things this way so that we do not perform
+ * any spurious prefetches past the end of the src buffer.
+ */
+U3memcpy_loop2:
+ ldd [%o1 + 0x008], %f2 ! MS
+ faligndata %f12, %f14, %f28 ! FGA Group2
+ ldd [%o1 + 0x010], %f4 ! MS
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall)
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ ldd [%o1 + 0x018], %f6 ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+
+ ldd [%o1 + 0x020], %f8 ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group13
+ ldd [%o1 + 0x028], %f10 ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group14
+ ldd [%o1 + 0x030], %f12 ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group15
+ ldd [%o1 + 0x038], %f14 ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group16
+
+ ldd [%o1 + 0x040], %f0 ! AX
+ faligndata %f10, %f12, %f26 ! FGA Group17
+ subcc %o3, 0x01, %o3 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3memcpy_loop2 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+ /* Finally we copy the last full 64-byte block. */
+U3memcpy_loopfini:
+ ldd [%o1 + 0x008], %f2 ! MS
+ faligndata %f12, %f14, %f28 ! FGA
+ ldd [%o1 + 0x010], %f4 ! MS Group19
+ faligndata %f14, %f0, %f30 ! FGA
+ stda %f16, [%o0] ASI_BLK_P ! MS Group20
+ ldd [%o1 + 0x018], %f6 ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall)
+ ldd [%o1 + 0x020], %f8 ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group12
+ ldd [%o1 + 0x028], %f10 ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group13
+ ldd [%o1 + 0x030], %f12 ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group14
+ ldd [%o1 + 0x038], %f14 ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group15
+ cmp %g1, 0 ! A0
+ be,pt %icc, 1f ! BR
+ add %o0, 0x40, %o0 ! A1
+ ldd [%o1 + 0x040], %f0 ! MS
+1: faligndata %f10, %f12, %f26 ! FGA Group16
+ faligndata %f12, %f14, %f28 ! FGA Group17
+ faligndata %f14, %f0, %f30 ! FGA Group18
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ add %o0, 0x40, %o0 ! A0
+ add %o1, 0x40, %o1 ! A1
+ membar #Sync ! MS Group26 (7-cycle stall)
+
+ /* Now we copy the (len modulo 64) bytes at the end.
+ * Note how we borrow the %f0 loaded above.
+ *
+ * Also notice how this code is careful not to perform a
+ * load past the end of the src buffer just like similar
+ * code found in U3memcpy_toosmall processing.
+ */
+U3memcpy_loopend:
+ and %o2, 0x3f, %o2 ! A0 Group
+ andcc %o2, 0x38, %g2 ! A0 Group
+ be,pn %icc, U3memcpy_endcruft ! BR
+ subcc %g2, 0x8, %g2 ! A1
+ be,pn %icc, U3memcpy_endcruft ! BR Group
+ cmp %g1, 0 ! A0
+
+ be,a,pt %icc, 1f ! BR Group
+ ldd [%o1 + 0x00], %f0 ! MS
+
+1: ldd [%o1 + 0x08], %f2 ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f0, %f2, %f8 ! FGA Group
+ std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX)
+ be,pn %icc, U3memcpy_endcruft ! BR
+ add %o0, 0x8, %o0 ! A0
+ ldd [%o1 + 0x08], %f0 ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA
+ std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX)
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A0 Group
+
+ /* If anything is left, we copy it one byte at a time.
+ * Note that %g1 is (src & 0x3) saved above before the
+ * alignaddr was performed.
+ */
+U3memcpy_endcruft:
+ cmp %o2, 0
+ add %o1, %g1, %o1
+ VISExitHalf
+ be,pn %icc, U3memcpy_short_ret
+ nop
+ ba,a,pt %xcc, U3memcpy_short
+
+ /* If we get here, then 32 <= len < (6 * 64) */
+U3memcpy_toosmall:
+
+#ifdef SMALL_COPY_USES_FPU
+
+ /* Is 'dst' already aligned on an 8-byte boundary? */
+ be,pt %xcc, 2f ! BR Group
+
+ /* Compute abs((dst & 7) - 8) into %g2. This is the number
+ * of bytes to copy to make 'dst' 8-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x8, %g2 ! A0
+ sub %g0, %g2, %g2 ! A0 Group (reg-dep)
+ sub %o2, %g2, %o2 ! A0 Group (reg-dep)
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: ldub [%o1 + 0x00], %o3 ! MS (Group) (%o3 in 3 cycles)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ stb %o3, [%o0 + -1] ! MS Group
+
+2: VISEntryHalf ! MS+MS
+
+ /* Compute (len - (len % 8)) into %g2. This is guarenteed
+ * to be nonzero.
+ */
+ andn %o2, 0x7, %g2 ! A0 Group
+
+ /* You may read this and believe that it allows reading
+ * one 8-byte longword past the end of src. It actually
+ * does not, as %g2 is subtracted as loads are done from
+ * src, so we always stop before running off the end.
+ * Also, we are guarenteed to have at least 0x10 bytes
+ * to move here.
+ */
+ sub %g2, 0x8, %g2 ! A0 Group (reg-dep)
+ alignaddr %o1, %g0, %g1 ! MS (Break-after)
+ ldd [%g1 + 0x00], %f0 ! MS Group (1-cycle stall)
+ add %g1, 0x8, %g1 ! A0
+
+1: ldd [%g1 + 0x00], %f2 ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+
+ faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall)
+ std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+ be,pn %icc, 2f ! BR
+
+ add %o0, 0x8, %o0 ! A1
+ ldd [%g1 + 0x00], %f0 ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall)
+ std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A1
+
+ /* Nothing left to copy? */
+2: cmp %o2, 0 ! A0 Group
+ VISExitHalf ! A0+MS
+ be,pn %icc, U3memcpy_short_ret ! BR Group
+ nop ! A0
+ ba,a,pt %xcc, U3memcpy_short ! BR Group
+
+#else /* !(SMALL_COPY_USES_FPU) */
+
+ xor %o1, %o0, %g2
+ andcc %g2, 0x7, %g0
+ bne,pn %icc, U3memcpy_short
+ andcc %o1, 0x7, %g2
+
+ be,pt %xcc, 2f
+ sub %g2, 0x8, %g2
+ sub %g0, %g2, %g2
+ sub %o2, %g2, %o2
+
+1: ldub [%o1 + 0x00], %o3
+ add %o1, 0x1, %o1
+ add %o0, 0x1, %o0
+ subcc %g2, 0x1, %g2
+ bg,pt %icc, 1b
+ stb %o3, [%o0 + -1]
+
+2: andn %o2, 0x7, %g2
+ sub %o2, %g2, %o2
+
+3: ldx [%o1 + 0x00], %o3
+ add %o1, 0x8, %o1
+ add %o0, 0x8, %o0
+ subcc %g2, 0x8, %g2
+ bg,pt %icc, 3b
+ stx %o3, [%o0 + -8]
+
+ cmp %o2, 0
+ bne,pn %icc, U3memcpy_short
+ nop
+ ba,a,pt %xcc, U3memcpy_short_ret
+
+#endif /* !(SMALL_COPY_USES_FPU) */
-/* $Id: VIScopy.S,v 1.23 2000/03/26 09:13:49 davem Exp $
+/* $Id: VIScopy.S,v 1.25 2000/11/01 09:29:19 davem Exp $
* VIScopy.S: High speed copy operations utilizing the UltraSparc
* Visual Instruction Set.
*
clr %o0 ! IEU0
+#ifdef __KERNEL__
+#define BRANCH_ALWAYS 0x10680000
+#define NOP 0x01000000
+#define ULTRA3_DO_PATCH(OLD, NEW) \
+ sethi %hi(NEW), %g1; \
+ or %g1, %lo(NEW), %g1; \
+ sethi %hi(OLD), %g2; \
+ or %g2, %lo(OLD), %g2; \
+ sub %g1, %g2, %g1; \
+ sethi %hi(BRANCH_ALWAYS), %g3; \
+ srl %g1, 2, %g1; \
+ or %g3, %lo(BRANCH_ALWAYS), %g3; \
+ or %g3, %g1, %g3; \
+ stw %g3, [%g2]; \
+ sethi %hi(NOP), %g3; \
+ or %g3, %lo(NOP), %g3; \
+ stw %g3, [%g2 + 0x4]; \
+ flush %g2;
+
+ .globl cheetah_patch_copyops
+cheetah_patch_copyops:
+ ULTRA3_DO_PATCH(memcpy, U3memcpy)
+ ULTRA3_DO_PATCH(__copy_from_user, U3copy_from_user)
+ ULTRA3_DO_PATCH(__copy_to_user, U3copy_to_user)
+ ULTRA3_DO_PATCH(__copy_in_user, U3copy_in_user)
+ retl
+ nop
+#undef BRANCH_ALWAYS
+#undef NOP
+#undef ULTRA3_DO_PATCH
+#endif /* __KERNEL__ */
+
.align 32
#ifdef __KERNEL__
__memcpy_384plus:
-/* $Id: init.c,v 1.157 2000/10/19 00:49:52 davem Exp $
+/* $Id: init.c,v 1.159 2000/11/06 06:59:04 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
return freed;
}
+extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+ struct page *page = pte_page(pte);
+
+ if (VALID_PAGE(page) && page->mapping &&
+ test_bit(PG_dcache_dirty, &page->flags)) {
+ __flush_dcache_page(page->virtual, 1);
+ clear_bit(PG_dcache_dirty, &page->flags);
+ }
+ __update_mmu_cache(vma, address, pte);
+}
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
-/* $Id: ultra.S,v 1.46 2000/08/05 13:30:33 davem Exp $
+/* $Id: ultra.S,v 1.48 2000/11/06 06:59:04 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
.align 64
.globl __flush_dcache_page
-__flush_dcache_page:
+__flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */
sub %o0, %g4, %o0
- clr %o1
+ clr %o4
srlx %o0, 11, %o0
sethi %hi(1 << 14), %o2
-1: ldxa [%o1] ASI_DCACHE_TAG, %o3
- andn %o3, 0x3, %o3
- cmp %o0, %o3
- bne,pt %xcc, 2f
- nop
- stxa %g0, [%o1] ASI_DCACHE_TAG
- membar #Sync
-2: add %o1, (1 << 5), %o1
- cmp %o1, %o2
- bne,pt %xcc, 1b
- nop
+1: ldxa [%o4] ASI_DCACHE_TAG, %o3 ! LSU Group
+ add %o4, (1 << 5), %o4 ! IEU0
+ ldxa [%o4] ASI_DCACHE_TAG, %g1 ! LSU Group
+ add %o4, (1 << 5), %o4 ! IEU0
+ ldxa [%o4] ASI_DCACHE_TAG, %g2 ! LSU Group o3 available
+ add %o4, (1 << 5), %o4 ! IEU0
+ andn %o3, 0x3, %o3 ! IEU1
+ ldxa [%o4] ASI_DCACHE_TAG, %g3 ! LSU Group
+ add %o4, (1 << 5), %o4 ! IEU0
+ andn %g1, 0x3, %g1 ! IEU1
+ cmp %o0, %o3 ! IEU1 Group
+ be,a,pn %xcc, dflush1 ! CTI
+ sub %o4, (4 << 5), %o4 ! IEU0 (Group)
+ cmp %o0, %g1 ! IEU1 Group
+ andn %g2, 0x3, %g2 ! IEU0
+ be,a,pn %xcc, dflush2 ! CTI
+ sub %o4, (3 << 5), %o4 ! IEU0 (Group)
+ cmp %o0, %g2 ! IEU1 Group
+ andn %g3, 0x3, %g3 ! IEU0
+ be,a,pn %xcc, dflush3 ! CTI
+ sub %o4, (2 << 5), %o4 ! IEU0 (Group)
+ cmp %o0, %g3 ! IEU1 Group
+ be,a,pn %xcc, dflush4 ! CTI
+ sub %o4, (1 << 5), %o4 ! IEU0
+2: cmp %o4, %o2 ! IEU1 Group
+ bne,pt %xcc, 1b ! CTI
+ nop ! IEU0
+
/* The I-cache does not snoop local stores so we
- * better flush that too.
+ * better flush that too when necessary.
*/
- ba,pt %xcc, __flush_icache_page
+ brnz,pt %o1, __flush_icache_page
sllx %o0, 11, %o0
+ retl
+ nop
+
+dflush1:stxa %g0, [%o4] ASI_DCACHE_TAG
+ add %o4, (1 << 5), %o4
+dflush2:stxa %g0, [%o4] ASI_DCACHE_TAG
+ add %o4, (1 << 5), %o4
+dflush3:stxa %g0, [%o4] ASI_DCACHE_TAG
+ add %o4, (1 << 5), %o4
+dflush4:stxa %g0, [%o4] ASI_DCACHE_TAG
+ add %o4, (1 << 5), %o4
+ membar #Sync
+ ba,pt %xcc, 2b
+ nop
.align 32
__prefill_dtlb:
retl
wrpr %g7, %pstate
- .globl update_mmu_cache
-update_mmu_cache: /* %o0=vma, %o1=address, %o2=pte */
+ .globl __update_mmu_cache
+__update_mmu_cache: /* %o0=vma, %o1=address, %o2=pte */
ldub [%g6 + AOFF_task_thread + AOFF_thread_fault_code], %o3
srlx %o1, 13, %o1
ldx [%o0 + 0x0], %o4 /* XXX vma->vm_mm */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
__kstrtab : { *(.kstrtab) }
+ __start___kallsyms = .; /* All kernel symbols */
+ __kallsyms : { *(__kallsyms) }
+ __stop___kallsyms = .;
. = ALIGN(8192);
__init_begin = .;
.text.init : { *(.text.init) }
/*
* initialize
*/
- exit_files(current);
+
daemonize();
strcpy(current->comm, "acpi");
if (size > count)
size = count;
- kaddr = (char*)kmap(page);
+ kaddr = kmap(page);
if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) {
size = 0;
printk(KERN_ERR "loop: transfer error block %ld\n",
* 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Added devfs support
*
*/
-static void rd_request(request_queue_t * q)
+static int rd_make_request(request_queue_t * q, int rw, struct buffer_head *sbh)
{
unsigned int minor;
unsigned long offset, len;
struct buffer_head *rbh;
- struct buffer_head *sbh;
-repeat:
- INIT_REQUEST;
- minor = MINOR(CURRENT->rq_dev);
+ minor = MINOR(sbh->b_rdev);
+
+ if (minor >= NUM_RAMDISKS)
+ goto fail;
- if (minor >= NUM_RAMDISKS) {
- end_request(0);
- goto repeat;
- }
- offset = CURRENT->sector << 9;
- len = CURRENT->current_nr_sectors << 9;
+ offset = sbh->b_rsector << 9;
+ len = sbh->b_size;
- if ((offset + len) > rd_length[minor]) {
- end_request(0);
- goto repeat;
- }
+ if ((offset + len) > rd_length[minor])
+ goto fail;
- if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) {
- printk(KERN_INFO "RAMDISK: bad command: %d\n", CURRENT->cmd);
- end_request(0);
- goto repeat;
+ if (rw==READA)
+ rw=READ;
+ if ((rw != READ) && (rw != WRITE)) {
+ printk(KERN_INFO "RAMDISK: bad command: %d\n", rw);
+ goto fail;
}
- sbh = CURRENT->bh;
- rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
- if (CURRENT->cmd == READ) {
+ rbh = getblk(sbh->b_rdev, sbh->b_rsector/(sbh->b_size>>9), sbh->b_size);
+ if (rw == READ) {
if (sbh != rbh)
- memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size);
+ memcpy(sbh->b_data, rbh->b_data, rbh->b_size);
} else
if (sbh != rbh)
- memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
+ memcpy(rbh->b_data, sbh->b_data, rbh->b_size);
mark_buffer_protected(rbh);
brelse(rbh);
- end_request(1);
- goto repeat;
+ sbh->b_end_io(sbh,1);
+ return 0;
+ fail:
+ sbh->b_end_io(sbh,0);
+ return 0;
}
static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
devfs_unregister (devfs_handle);
unregister_blkdev( MAJOR_NR, "ramdisk" );
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
hardsect_size[MAJOR_NR] = NULL;
blksize_size[MAJOR_NR] = NULL;
blk_size[MAJOR_NR] = NULL;
return -EIO;
}
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &rd_request);
+ blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), &rd_make_request);
for (i = 0; i < NUM_RAMDISKS; i++) {
/* rd_size is given in kB */
int i;
lock_kernel();
- exit_files(current);
daemonize();
unlock_kernel();
while(1)
{
+#warning "RACE"
interruptible_sleep_on(&i2ob_evt_wait);
if(signal_pending(current)) {
evt_running = 0;
int flags;
lock_kernel();
- exit_files(current);
daemonize();
unlock_kernel();
char name[16];
lock_kernel();
- exit_files(current);
daemonize();
unlock_kernel();
ide-obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o
ide-obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o
ide-obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o
-ide-obj-$(CONFIG_BLK_DEV_HD) += hd.o
+obj-$(CONFIG_BLK_DEV_HD) += hd.o
ide-obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
ide-obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
ide-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
return count;
}
-static void
-act2000_putmsg(act2000_card *card, char c)
-{
- ulong flags;
-
- save_flags(flags);
- cli();
- *card->status_buf_write++ = c;
- if (card->status_buf_write == card->status_buf_read) {
- if (++card->status_buf_read > card->status_buf_end)
- card->status_buf_read = card->status_buf;
- }
- if (card->status_buf_write > card->status_buf_end)
- card->status_buf_write = card->status_buf;
- restore_flags(flags);
-}
-
-static void
-act2000_logstat(struct act2000_card *card, char *str)
-{
- char *p = str;
- isdn_ctrl c;
-
- while (*p)
- act2000_putmsg(card, *p++);
- c.command = ISDN_STAT_STAVAIL;
- c.driver = card->myid;
- c.arg = strlen(str);
- card->interface.statcallb(&c);
-}
-
/*
* Find card with given driverId
*/
#include "isdnl1.h"
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
extern const char *CardType[];
#endif /* CONFIG_PCI */
-__initfunc(int
- setup_hfcpci(struct IsdnCard *card))
+int __init setup_hfcpci(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
- unsigned short cmd;
char tmp[64];
int i;
struct pci_dev *tmp_hfcpci = NULL;
#endif
strcpy(tmp, hfcpci_revision);
printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
cs->hw.hfcpci.int_s1 = 0;
cs->dc.hfcpci.ph_state = 0;
cs->hw.hfcpci.fifo = 255;
if (cs->typ == ISDN_CTYPE_HFC_PCI) {
- if (!pci_present()) {
- printk(KERN_ERR "HFC-PCI: no PCI bus present\n");
- return (0);
- }
i = 0;
while (id_list[i].vendor_id) {
tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
return (0);
}
-#ifdef notdef
- if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
- printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n");
- pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_COMMAND,
- 0x0103); /* set SERR */
- pcibios_read_config_word(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_COMMAND,
- &cmd);
- pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_COMMAND,
- cmd & ~2);
- (int) cs->hw.hfcpci.pci_io &= ~(PAGE_SIZE - 1);
- pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_BASE_ADDRESS_1,
- (int) cs->hw.hfcpci.pci_io);
- pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_COMMAND,
- cmd);
- pcibios_read_config_dword(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_BASE_ADDRESS_1,
- (void *) &cs->hw.hfcpci.pci_io);
- if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
- printk(KERN_WARNING "HFC-PCI unable to align address %x\n", (unsigned) cs->hw.hfcpci.pci_io);
- return (0);
- }
- dev_hfcpci->resource[1].start = (int) cs->hw.hfcpci.pci_io;
- }
-#endif
if (!cs->hw.hfcpci.pci_io) {
printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
return (0);
dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
if (!dev->b1) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
return -ENOMEM;
}
if (!dev->b2) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
kfree(dev->b1);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
return -ENOMEM;
}
{
kfree(dev->b1);
kfree(dev->b2);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
dev_pcbit[board] = NULL;
return -EIO;
}
free_irq(irq, dev);
kfree(dev->b1);
kfree(dev->b2);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
dev_pcbit[board] = NULL;
return -EIO;
}
free_irq(irq, dev);
kfree(dev->b1);
kfree(dev->b2);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
dev_pcbit[board] = NULL;
return -EIO;
}
del_timer(&dev->b2->fsm_timer);
kfree(dev->b1);
kfree(dev->b2);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
}
}
#endif
*/
#include <linux/kernel.h>
-#define NULL 0x0
-
-#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
-#define FREE_IRQ(a,b) free_irq(a,b)
-
inline char *strcpy(char *, const char *);
int dbg_level = 0;
*i = *j;
i++; j++;
}
- *(++i) = NULL;
+ *(++i) = 0;
return dest;
}
{
int l, le, l_new, p, size;
ulong lv_status_save;
- char *lv_tmp, *lv_buf;
+ char *lv_tmp, *lv_buf = NULL;
lv_block_exception_t *lvbe = lv->lv_block_exception;
vg_t *vg_ptr = vg[VG_CHR(minor)];
lv_t *lv_ptr = NULL;
mdk_thread_t *thread = arg;
md_lock_kernel();
- exit_mm(current);
- exit_files(current);
- exit_fs(current);
/*
* Detach thread
*/
+
daemonize();
+
sprintf(current->comm, thread->name);
md_init_signals();
md_flush_signals();
{
struct buffer_head *bh = r1_bh->master_bh;
- io_request_done(bh->b_blocknr*(bh->b_size>>9), mddev_to_conf(r1_bh->mddev),
+ io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev),
test_bit(R1BH_SyncPhase, &r1_bh->state));
bh->b_end_io(bh, uptodate);
Jean-Jacques Michel - bug fix
- Tobias - Rx interrupt status checking suggestion
+ Tobias Ringström - Rx interrupt status checking suggestion
Submitting bug reports:
#define DE4X5_PKT_BIN_SZ 128 /* Should be >=100 unless you
increase DE4X5_PKT_STAT_SZ */
+struct pkt_stats {
+ u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
+ u_int unicast;
+ u_int multicast;
+ u_int broadcast;
+ u_int excessive_collisions;
+ u_int tx_underruns;
+ u_int excessive_underruns;
+ u_int rx_runt_frames;
+ u_int rx_collision;
+ u_int rx_dribble;
+ u_int rx_overflow;
+};
+
struct de4x5_private {
char adapter_name[80]; /* Adapter name */
u_long interrupt; /* Aligned ISR flag */
char frame[64]; /* Min sized packet for loopback*/
spinlock_t lock; /* Adapter specific spinlock */
struct net_device_stats stats; /* Public stats */
- struct {
- u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
- u_int unicast;
- u_int multicast;
- u_int broadcast;
- u_int excessive_collisions;
- u_int tx_underruns;
- u_int excessive_underruns;
- u_int rx_runt_frames;
- u_int rx_collision;
- u_int rx_dribble;
- u_int rx_overflow;
- } pktStats;
+ struct pkt_stats pktStats; /* Private stats counters */
char rxRingSize;
char txRingSize;
int bus; /* EISA or PCI */
break;
case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
printk("%s: Boo!\n", dev->name);
break;
break;
case DE4X5_GET_STATS: /* Get the driver statistics */
- ioc->len = sizeof(lp->pktStats);
+ {
+ struct pkt_stats statbuf;
+ ioc->len = sizeof(statbuf);
spin_lock_irqsave(&lp->lock, flags);
- if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) return -EFAULT;
+ memcpy(&statbuf, &lp->pktStats, ioc->len);
spin_unlock_irqrestore(&lp->lock, flags);
+ if (copy_to_user(ioc->data, &statbuf, ioc->len))
+ return -EFAULT;
break;
-
+ }
case DE4X5_CLR_STATS: /* Zero out the driver statistics */
if (!capable(CAP_NET_ADMIN)) return -EPERM;
spin_lock_irqsave(&lp->lock, flags);
sprintf(fi->name, "fc%d", count);
host = scsi_register(tmpt, sizeof(struct iph5526_hostdata));
+ if(host==NULL)
+ return no_of_hosts;
+
hostdata = (struct iph5526_hostdata *)host->hostdata;
memset(hostdata, 0 , sizeof(struct iph5526_hostdata));
for (j = 0; j < MAX_SCSI_TARGETS; j++)
rrpriv = (struct rr_private *)dev->priv;
- spin_lock(&rrpriv->lock);
switch(cmd){
case SIOCRRGFW:
goto out;
}
- if (rrpriv->fw_running){
- printk("%s: Firmware already running\n", dev->name);
- error = -EPERM;
- goto out;
- }
-
image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
if (!image){
printk(KERN_ERR "%s: Unable to allocate memory "
error = -ENOMEM;
goto out;
}
+
+ spin_lock(&rrpriv->lock);
+
+ if (rrpriv->fw_running){
+ printk("%s: Firmware already running\n", dev->name);
+ kfree(image);
+ error = -EPERM;
+ goto out_spin;
+ }
+
i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
if (i != EEPROM_BYTES){
kfree(image);
printk(KERN_ERR "%s: Error reading EEPROM\n",
dev->name);
error = -EFAULT;
- goto out;
+ goto out_spin;
}
+ spin_unlock(&rrpriv->lock);
error = copy_to_user(rq->ifr_data, image, EEPROM_BYTES);
if (error)
error = -EFAULT;
kfree(image);
- break;
+ return error;
+
case SIOCRRPFW:
if (!capable(CAP_SYS_RAWIO)){
- error = -EPERM;
- goto out;
- }
-
- if (rrpriv->fw_running){
- printk("%s: Firmware already running\n", dev->name);
- error = -EPERM;
- goto out;
+ return -EPERM;
}
image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
if (!image){
printk(KERN_ERR "%s: Unable to allocate memory "
"for EEPROM image\n", dev->name);
- error = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
if (!oldimage){
printk(KERN_ERR "%s: Unable to allocate memory "
"for old EEPROM image\n", dev->name);
- error = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
error = copy_from_user(image, rq->ifr_data, EEPROM_BYTES);
if (error)
error = -EFAULT;
+ spin_lock(&rrpriv->lock);
+ if (rrpriv->fw_running){
+ kfree(image);
+ kfree(oldimage);
+ printk("%s: Firmware already running\n", dev->name);
+ error = -EPERM;
+ goto out_spin;
+ }
+
printk("%s: Updating EEPROM firmware\n", dev->name);
error = write_eeprom(rrpriv, 0, image, EEPROM_BYTES);
printk(KERN_ERR "%s: Error reading back EEPROM "
"image\n", dev->name);
+ spin_unlock(&rrpriv->lock);
error = memcmp(image, oldimage, EEPROM_BYTES);
if (error){
printk(KERN_ERR "%s: Error verifying EEPROM image\n",
}
kfree(image);
kfree(oldimage);
- break;
+ return error;
+
case SIOCRRID:
- error = put_user(0x52523032, (int *)(&rq->ifr_data[0]));
- if (error)
- error = -EFAULT;
- break;
+ return put_user(0x52523032, (int *)(&rq->ifr_data[0]));
default:
+ return error;
}
- out:
+ out_spin:
spin_unlock(&rrpriv->lock);
return error;
}
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Copyright 1999 Silicon Integrated System Corporation
- Revision: 1.07.04 Sep. 6 2000
+ Revision: 1.07.06 Nov. 7 2000
Modified from the driver which is originally written by Donald Becker.
preliminary Rev. 1.0 Jan. 18, 1998
http://www.sis.com.tw/support/databook.htm
+ Rev 1.07.06 Nov. 7 2000 Jeff Garzik <jgarzik@mandrakesoft.com> some bug fix and cleaning
+ Rev 1.07.05 Nov. 6 2000 metapirat<metapirat@gmx.de> contribute media type select by ifconfig
Rev 1.07.04 Sep. 6 2000 Lei-Chun Chang added ICS1893 PHY support
Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaroung rule
Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1
#include "sis900.h"
static const char *version =
-"sis900.c: v1.07.04 09/06/2000\n";
+"sis900.c: v1.07.06 11/07/2000\n";
static int max_interrupt_work = 20;
static int multicast_filter_limit = 128;
static void set_rx_mode(struct net_device *net_dev);
static void sis900_reset(struct net_device *net_dev);
static void sis630e_set_eq(struct net_device *net_dev);
+static int sis900_set_config(struct net_device *dev, struct ifmap *map);
/* older SiS900 and friends, use EEPROM to store MAC address */
static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
net_dev->hard_start_xmit = &sis900_start_xmit;
net_dev->stop = &sis900_close;
net_dev->get_stats = &sis900_get_stats;
+ net_dev->set_config = &sis900_set_config;
net_dev->set_multicast_list = &set_rx_mode;
net_dev->do_ioctl = &mii_ioctl;
net_dev->tx_timeout = sis900_tx_timeout;
return &sis_priv->stats;
}
+/* Support for media type changes via net_device->set_config */
+static int sis900_set_config(struct net_device *dev, struct ifmap *map)
+{
+ struct sis900_private *sis_priv = (struct sis900_private *)dev->priv;
+ struct mii_phy *mii_phy = sis_priv->mii;
+
+ u16 status;
+
+ /* we support only port changes. All other runtime configuration
+ changes will be ignored (io base and interrupt changes for example)*/
+ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+ /* we switch on the ifmap->port field. I couldn't find anything
+ like a definition or standard for the values of that field.
+ I think the meaning of those values is device specific. But
+ since I would like to change the media type via the ifconfig
+ command I use the definition from linux/netdevice.h
+ (which seems to be different from the ifport(pcmcia) definition)
+ */
+ switch(map->port){
+ case IF_PORT_UNKNOWN: /* use auto here */
+ dev->if_port = map->port;
+ /* we are going to change the media type, so the Link will
+ be temporary down and we need to reflect that here. When
+ the Link comes up again, it will be sensed by the sis_timer
+ procedure, which also does all the rest for us */
+ sis_priv->LinkOn=FALSE;
+
+ /* read current state */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+
+ /* enable auto negotiation and reset the negotioation
+ (I dont really know what the auto negatiotiation reset
+ really means, but it sounds for me right to do one here)*/
+ mdio_write(dev, mii_phy->phy_addr,
+ MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
+
+ break;
+
+ case IF_PORT_10BASET: /* 10BaseT */
+ dev->if_port = map->port;
+
+ /* we are going to change the media type, so the Link will
+ be temporary down and we need to reflect that here. When
+ the Link comes up again, it will be sensed by the sis_timer
+ procedure, which also does all the rest for us */
+ sis_priv->LinkOn=FALSE;
+
+ /* set Speed to 10Mbps */
+ /* read current state */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+
+ /* disable auto negotiation and force 10MBit mode*/
+ mdio_write(dev, mii_phy->phy_addr,
+ MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO));
+ break;
+
+ case IF_PORT_100BASET: /* 100BaseT */
+ case IF_PORT_100BASETX: /* 100BaseTx */
+ dev->if_port = map->port;
+
+ /* we are going to change the media type, so the Link will
+ be temporary down and we need to reflect that here. When
+ the Link comes up again, it will be sensed by the sis_timer
+ procedure, which also does all the rest for us */
+ sis_priv->LinkOn=FALSE;
+
+ /* set Speed to 100Mbps */
+ /* disable auto negotiation and enable 100MBit Mode */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+ mdio_write(dev, mii_phy->phy_addr,
+ MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED);
+
+ break;
+
+ case IF_PORT_10BASE2: /* 10Base2 */
+ case IF_PORT_AUI: /* AUI */
+ case IF_PORT_100BASEFX: /* 100BaseFx */
+ /* These Modes are not supported (are they?)*/
+ printk(KERN_INFO "Not supported");
+ return -EOPNOTSUPP;
+ break;
+
+ default:
+ printk(KERN_INFO "Invalid");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
/* SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast hash table, which makes
this function a little bit different from other drivers */
static u16 sis900_compute_hashtable_index(u8 *addr)
module_init(sis900_init_module);
module_exit(sis900_cleanup_module);
+
* http://www.sis.com.tw/support/databook.htm
*/
-/* MAC operation registers of SiS 7016 and SiS 900 ethernet controller */
+/*
+ * SiS 7016 and SiS 900 ethernet controller registers
+ */
+
/* The I/O extent, SiS 900 needs 256 bytes of io address */
#define SIS900_TOTAL_SIZE 0x100
#define PCI_DEVICE_ID_SI_900 0x900
#define PCI_DEVICE_ID_SI_7016 0x7016
-/* ioctl for accessing MII transveiver */
+/* ioctl for accessing MII transceiver */
#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */
#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */
#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register */
dev = &s->cb_config[i].dev;
pci_writeb(dev, PCI_COMMAND, PCI_COMMAND_MASTER |
PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
- pci_writeb(dev, PCI_CACHE_LINE_SIZE, 8);
+ pci_writeb(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
}
if (s->irq.AssignedIRQ) {
-/* $Id: aurora.c,v 1.7 1999/09/21 14:37:46 davem Exp $
+/* $Id: aurora.c,v 1.9 2000/11/08 05:33:03 davem Exp $
* linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
*
* Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
#endif
}
-#ifndef MODULE
/*
* Called at boot time.
*
}
}
-int __init aurora_init(void)
-#else
-int aurora_init(void)
-#endif
+static int __init aurora_real_init(void)
{
int found;
int i;
return 0;
}
-#ifdef MODULE
int irq = 0;
int irq1 = 0;
int irq2 = 0;
MODULE_PARM(irq2, "i");
MODULE_PARM(irq3, "i");
-int init_module(void)
+static int __init aurora_init(void)
{
if (irq ) irqs[0]=irq ;
if (irq1) irqs[1]=irq1;
if (irq2) irqs[2]=irq2;
if (irq3) irqs[3]=irq3;
- return aurora_init();
+ return aurora_real_init();
}
-void cleanup_module(void)
+static void __exit aurora_cleanup(void)
{
int i;
aurora_release_io_range(&aurora_board[i]);
}
}
-#endif /* MODULE */
+
+module_init(aurora_init);
+module_exit(aurora_cleanup);
static devfs_handle_t devfs_handle;
-#ifdef MODULE
-int init_module(void)
-#else
-int __init bpp_init(void)
-#endif
+static int __init bpp_init(void)
{
int rc;
unsigned idx;
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit bpp_cleanup(void)
{
unsigned idx;
freeLptPort(idx);
}
}
-#endif
+
+module_init(bpp_init);
+module_exit(bpp_cleanup);
-/* $Id: display7seg.c,v 1.3 2000/08/29 07:01:55 davem Exp $
+/* $Id: display7seg.c,v 1.4 2000/11/08 05:08:23 davem Exp $
*
* display7seg - Driver implementation for the 7-segment display
* present on Sun Microsystems CP1400 and CP1500
static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
-#ifdef MODULE
-int init_module(void)
-#else
-int __init d7s_init(void)
-#endif
+static int __init d7s_init(void)
{
struct linux_ebus *ebus = NULL;
struct linux_ebus_device *edev = NULL;
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit d7s_cleanup(void)
{
int regs = readb(d7s_regs);
misc_deregister(&d7s_miscdev);
d7s_free();
}
-#endif
+
+module_init(d7s_init);
+module_exit(d7s_cleanup);
-/* $Id: envctrl.c,v 1.18 2000/10/17 16:20:35 davem Exp $
+/* $Id: envctrl.c,v 1.19 2000/11/03 00:37:40 davem Exp $
* envctrl.c: Temperature and Fan monitoring on Machines providing it.
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* http://www-eu2.semiconductors.com/pip/PCF8584P
* http://www-eu2.semiconductors.com/pip/PCF8574AP
* http://www-eu2.semiconductors.com/pip/PCF8591P
- *
+ *
+ * EB - Added support for CP1500 Global Address and PS/Voltage monitoring.
+ * Eric Brower <ebrower@usa.net>
*/
#include <linux/config.h>
* Firmware definitions.
*/
#define PCF8584_MAX_CHANNELS 8
+#define PCF8584_GLOBALADDR_TYPE 6 /* global address monitor */
#define PCF8584_FANSTAT_TYPE 3 /* fan status monitor */
#define PCF8584_VOLTAGE_TYPE 2 /* voltage monitor */
-#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/
+#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/
/* Monitor type of i2c child device.
* Driver definitions.
*/
-#define ENVCTRL_NOMON 0
-#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */
+#define ENVCTRL_NOMON 0
+#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */
#define ENVCTRL_CPUVOLTAGE_MON 2 /* voltage monitor */
#define ENVCTRL_FANSTAT_MON 3 /* fan status monitor */
#define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperarture */
#define ENVCTRL_VOLTAGESTAT_MON 5 /* voltage status monitor */
#define ENVCTRL_MTHRBDTEMP_MON 6 /* motherboard temperature */
#define ENVCTRL_SCSITEMP_MON 7 /* scsi temperarture */
+#define ENVCTRL_GLOBALADDR_MON 8 /* global address */
/* Child device type.
* Driver definitions.
#define ENVCTRL_MAX_CPU 4
#define CHANNEL_DESC_SZ 256
+/* Mask values for combined GlobalAddress/PowerStatus node */
+#define ENVCTRL_GLOBALADDR_ADDR_MASK 0x1F
+#define ENVCTRL_GLOBALADDR_PSTAT_MASK 0x60
+
+/* Node 0x70 ignored on CompactPCI CP1400/1500 platforms
+ * (see envctrl_init_i2c_child)
+ */
+#define ENVCTRL_CPCI_IGNORED_NODE 0x70
+
struct pcf8584_reg {
unsigned char data;
unsigned char csr;
/* Do a single byte read and send stop. */
rd = envctrl_i2c_read_data();
envctrl_i2c_stop();
-
return rd;
}
return 1;
}
-/* Function Description: Read voltage and power supply status.
+/* Function Description: Read global addressing line.
+ * Return : Always 1 byte. Status stored in bufdata.
+ */
+static int envctrl_i2c_globaladdr(struct i2c_child_t *pchild,
+ unsigned char data,
+ char *bufdata)
+{
+ /* Translatation table is not necessary, as global
+ * addr is the integer value of the GA# bits.
+ *
+ * NOTE: MSB is documented as zero, but I see it as '1' always....
+ *
+ * -----------------------------------------------
+ * | 0 | FAL | DEG | GA4 | GA3 | GA2 | GA1 | GA0 |
+ * -----------------------------------------------
+ * GA0 - GA4 integer value of Global Address (backplane slot#)
+ * DEG 0 = cPCI Power supply output is starting to degrade
+ * 1 = cPCI Power supply output is OK
+ * FAL 0 = cPCI Power supply has failed
+ * 1 = cPCI Power supply output is OK
+ */
+ bufdata[0] = (data & ENVCTRL_GLOBALADDR_ADDR_MASK);
+ return 1;
+}
+
+/* Function Description: Read standard voltage and power supply status.
* Return : Always 1 byte. Status stored in bufdata.
*/
static unsigned char envctrl_i2c_voltage_status(struct i2c_child_t *pchild,
ret = envctrl_i2c_fan_status(pchild,data[0], data);
copy_to_user((unsigned char *)buf, data, ret);
break;
+
+ case ENVCTRL_RD_GLOBALADDRESS:
+ if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+ return 0;
+ data[0] = envctrl_i2c_read_8574(pchild->addr);
+ ret = envctrl_i2c_globaladdr(pchild, data[0], data);
+ copy_to_user((unsigned char *)buf, data, ret);
+ break;
case ENVCTRL_RD_VOLTAGE_STATUS:
if (!(pchild = envctrl_get_i2c_child(ENVCTRL_VOLTAGESTAT_MON)))
- return 0;
+ /* If voltage monitor not present, check for CPCI equivalent */
+ if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+ return 0;
data[0] = envctrl_i2c_read_8574(pchild->addr);
ret = envctrl_i2c_voltage_status(pchild, data[0], data);
copy_to_user((unsigned char *)buf, data, ret);
case ENVCTRL_RD_VOLTAGE_STATUS:
case ENVCTRL_RD_ETHERNET_TEMPERATURE:
case ENVCTRL_RD_SCSI_TEMPERATURE:
+ case ENVCTRL_RD_GLOBALADDRESS:
file->private_data = (void *)(long)cmd;
break;
if (!(strcmp(chnl_desc,"temp,ethernet")))
pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
-
- if (!(strcmp(chnl_desc,"temp,ethernet")))
- pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
}
/* Function Description: Initialize monitor channel with channel desc,
pchild->mon_type[0] = ENVCTRL_FANSTAT_MON;
}
+/* Function Description: Initialize child device for global addressing line.
+ * Return: None.
+ */
+static void envctrl_init_globaladdr(struct i2c_child_t *pchild)
+{
+ int i;
+
+ /* Voltage/PowerSupply monitoring is piggybacked
+ * with Global Address on CompactPCI. See comments
+ * within envctrl_i2c_globaladdr for bit assignments.
+ *
+ * The mask is created here by assigning mask bits to each
+ * bit position that represents PCF8584_VOLTAGE_TYPE data.
+ * Channel numbers are not consecutive within the globaladdr
+ * node (why?), so we use the actual counter value as chnls_mask
+ * index instead of the chnl_array[x].chnl_no value.
+ *
+ * NOTE: This loop could be replaced with a constant representing
+ * a mask of bits 5&6 (ENVCTRL_GLOBALADDR_PSTAT_MASK).
+ */
+ for (i = 0; i < pchild->total_chnls; i++) {
+ if (PCF8584_VOLTAGE_TYPE == pchild->chnl_array[i].type) {
+ pchild->voltage_mask |= chnls_mask[i];
+ }
+ }
+
+ /* We only need to know if this child has global addressing
+ * line monitored. We dont care which channels since we know
+ * the mask already (ENVCTRL_GLOBALADDR_ADDR_MASK).
+ */
+ pchild->mon_type[0] = ENVCTRL_GLOBALADDR_MON;
+}
+
/* Initialize child device monitoring voltage status. */
static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
{
}
}
+ /* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
+ * sections 2.5, 3.5, 4.5 state node 0x70 for CP1400/1500 is
+ * "For Factory Use Only."
+ *
+ * We ignore the node on these platforms by assigning the
+ * 'NULL' monitor type.
+ */
+ if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
+ int len;
+ char prop[56];
+
+ len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
+ if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len)))
+ {
+ for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
+ pchild->mon_type[len] = ENVCTRL_NOMON;
+ }
+ return;
+ }
+ }
+
/* Get the monitor channels. */
len = prom_getproperty(node, "channels-in-use",
(char *) pchild->chnl_array,
envctrl_init_adc(pchild, node);
break;
+ case PCF8584_GLOBALADDR_TYPE:
+ envctrl_init_globaladdr(pchild);
+ i = pchild->total_chnls;
+ break;
+
case PCF8584_FANSTAT_TYPE:
envctrl_init_fanstat(pchild);
i = pchild->total_chnls;
for (i = 0; i < ENVCTRL_MAX_CPU*2; i++) {
for (j = 0; j < PCF8584_MAX_CHANNELS; j++) {
if (i2c_childlist[i].mon_type[j] == mon_type) {
- return (struct i2c_child_t*)(&(i2c_childlist[i]));
+ return (struct i2c_child_t *)(&(i2c_childlist[i]));
}
}
}
* child devices.
*/
printk("envctrl: initialized ");
- for(--i; i >= 0; --i)
- {
+ for (--i; i >= 0; --i) {
printk("[%s 0x%lx]%s",
(I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") :
((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")),
-/* $Id: flash.c,v 1.19 2000/07/13 08:06:40 davem Exp $
+/* $Id: flash.c,v 1.20 2000/11/08 04:57:49 davem Exp $
* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
EXPORT_NO_SYMBOLS;
-#ifdef MODULE
-int init_module(void)
-#else
-int __init flash_init(void)
-#endif
+static int __init flash_init(void)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev = 0;
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit flash_cleanup(void)
{
misc_deregister(&flash_dev);
}
-#endif
+
+module_init(flash_init);
+module_exit(flash_cleanup);
EXPORT_NO_SYMBOLS;
-#ifdef MODULE
-int init_module(void)
-#else
-int __init openprom_init(void)
-#endif
+static int __init openprom_init(void)
{
unsigned long flags;
int error;
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit openprom_cleanup(void)
{
misc_deregister(&openprom_dev);
}
-#endif
+
+module_init(openprom_init);
+module_exit(openprom_cleanup);
-/* $Id: uctrl.c,v 1.8 2000/06/19 06:24:47 davem Exp $
+/* $Id: uctrl.c,v 1.9 2000/11/08 05:04:06 davem Exp $
* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
*
* Copyright 1999 Derrick J Brashear (shadow@dementia.org)
}
-#ifdef MODULE
-int init_module(void)
-#else
-int __init ts102_uctrl_init(void)
-#endif
+static int __init ts102_uctrl_init(void)
{
struct uctrl_driver *driver = &drv;
int len, i;
return 0;
}
-
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit ts102_uctrl_cleanup(void)
{
struct uctrl_driver *driver = &drv;
if (driver->regs)
driver->regs = 0;
}
-#endif
+
+module_init(ts102_uctrl_init);
+module_exit(ts102_uctrl_cleanup);
-/* $Id: sbus.c,v 1.86 2000/03/16 09:23:57 jj Exp $
+/* $Id: sbus.c,v 1.91 2000/11/08 05:04:06 davem Exp $
* sbus.c: SBus support routines.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus);
void sun4_init(void);
-#ifdef CONFIG_SUN_OPENPROMIO
-extern int openprom_init(void);
-#endif
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
-#ifdef CONFIG_OBP_FLASH
-extern int flash_init(void);
-#endif
-#ifdef CONFIG_SUN_AURORA
-extern int aurora_init(void);
-#endif
-#ifdef CONFIG_TADPOLE_TS102_UCTRL
-extern int ts102_uctrl_init(void);
-#endif
static void __init sbus_do_child_siblings(int start_node,
struct sbus_dev *child,
firetruck_init();
}
#endif
-#ifdef CONFIG_SUN_OPENPROMIO
- openprom_init();
-#endif
-#ifdef CONFIG_SUN_BPP
- bpp_init();
-#endif
#ifdef CONFIG_SUN_AUXIO
if (sparc_cpu_model == sun4u)
auxio_probe ();
#endif
-#ifdef CONFIG_OBP_FLASH
- flash_init();
-#endif
-#ifdef CONFIG_SUN_AURORA
- aurora_init();
-#endif
-#ifdef CONFIG_TADPOLE_TS102_UCTRL
- ts102_uctrl_init();
-#endif
#ifdef __sparc_v9__
if (sparc_cpu_model == sun4u) {
extern void clock_probe(void);
/* Register the card with the kernel SCSI layer */
host = scsi_register(tw_host, sizeof(TW_Device_Extension));
-
- /* FIXME - check for NULL */
+ if( host == NULL)
+ {
+ release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+ tw_free_device_extension(tw_dev);
+ kfree(tw_dev);
+ continue;
+ }
status_reg_value = inl(tw_dev->registers.status_reg_addr);
* STCNT to trigger ENSWRAP interrupt, instead of
* polling for DFIFOFULL
*/
- the_time=jiffies + 1000;
+ the_time=jiffies + 10*HZ;
while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
barrier();
CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
}
- the_time=jiffies+1000;
+ the_time=jiffies+10*HZ;
while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
barrier();
-/* $Id: esp.c,v 1.97 2000/09/19 01:29:27 davem Exp $
+/* $Id: esp.c,v 1.98 2000/11/02 22:34:16 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
*
* struct scsi_cmnd:
*
- * We keep track of the syncronous capabilities of a target
+ * We keep track of the synchronous capabilities of a target
* in the device member, using sync_min_period and
* sync_max_offset. These are the values we directly write
* into the ESP registers while running a command. If offset
* on HME broken adapters because we skip the HME fifo
* workaround code in esp_handle() if we are doing data
* phase things. We don't want to fuck directly with
- * the fifo like that, especially if doing syncronous
+ * the fifo like that, especially if doing synchronous
* transfers! Also, will need to double the count on
* HME if we are doing wide transfers, as the HME fifo
* will move and count 16-bit quantities during wide data.
/* Allocate memory for the CCBs */
ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA);
+ if(ha->scbs == NULL)
+ return 0;
memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t));
pciDev,
pdev->slot_name);
- /*
- * Dont crash on boot with AMI cards configured for I2O.
- * (our I2O code will find them then they will fail oddly until
- * we figure why they upset our I2O code). This driver will die
- * if it tries to boot an I2O mode board and we dont stop it now.
- * - Alan Cox , Red Hat Software, Jan 2000
- */
-
- if((pdev->class >> 8) == PCI_CLASS_INTELLIGENT_I2O)
- {
- printk( KERN_INFO "megaraid: Board configured for I2O, ignoring this card. Reconfigure the card\n"
- KERN_INFO "megaraid: in the BIOS for \"mass storage\" to use it with this driver.\n");
- continue;
- }
-
/* Read the base port and IRQ from PCI */
megaBase = pci_resource_start (pdev, 0);
megaIrq = pdev->irq;
/* Initialize SCSI Host structure */
host = scsi_register (pHostTmpl, sizeof (mega_host_config));
+ if(host == NULL)
+ continue;
megaCfg = (mega_host_config *) host->hostdata;
memset (megaCfg, 0, sizeof (mega_host_config));
megaCtlrs[numCtlrs++] = megaCfg;
if (flag != BOARD_QUARTZ) {
/* Request our IO Range */
- if (check_region (megaBase, 16)) {
+ if (request_region (megaBase, 16, "megaraid")) {
printk (KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);
scsi_unregister (host);
continue;
}
- request_region (megaBase, 16, "megaraid");
}
/* Request our IRQ */
* Flush resources
*/
- exit_files(current);
- current->files = init_task.files;
- atomic_inc(¤t->files->count);
daemonize();
/*
* crashing, all scsi_done() calls during sync resets are ignored.
*/
printk("scsi%d: device driver called scsi_done() "
- "for a syncronous reset.\n", SCpnt->host->host_no);
+ "for a synchronous reset.\n", SCpnt->host->host_no);
return;
}
if (SCpnt->flags & WAS_SENSE) {
/* ----------------------------------------------------------------------- */
/* this is called by the generic cdrom driver. arg is a _kernel_ pointer, */
-/* becauce the generic cdrom driver does the user access stuff for us. */
+/* because the generic cdrom driver does the user access stuff for us. */
/* only cdromreadtochdr and cdromreadtocentry are left - for use with the */
/* sr_disk_status interface for the generic cdrom driver. */
* Analog Devices (A major AC97 codec maker)
* Intel Corp (you've probably heard of them already)
*
+ * AC97 clues and assistance provided by
+ * Analog Devices
+ * Zach 'Fufu' Brown
+ * Jeff Garzik
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
#endif
static int ftsodell=0;
-static int clocking=48000;
+static unsigned int clocking=48000;
#define ADC_RUNNING 1
static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
- u16 dacp, rp;
+ u32 dacp;
struct ac97_codec *codec=state->card->ac97_codec[0];
if(!(state->card->ac97_features&0x0001))
if(rate < 8000)
rate = 8000;
- /* Power down the DAC */
- dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200);
-
- /* Load the rate and read the effective rate */
- i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate);
- rp=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
-
-// printk("DAC rate set to %d Returned %d\n",
-// rate, (int)rp);
-
- rate=(rp * 48000) / clocking;
-
- /* Power it back up */
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
-
+ if(rate != i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE))
+ {
+ /* Power down the DAC */
+ dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200);
+ /* Load the rate and read the effective rate */
+ i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate);
+ rate=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
+ /* Power it back up */
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+ }
+ rate=(rate * 48000) / clocking;
dmabuf->rate = rate;
#ifdef DEBUG
printk("i810_audio: called i810_set_dac_rate : rate = %d\n", rate);
static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
- u16 dacp, rp;
+ u32 dacp;
struct ac97_codec *codec=state->card->ac97_codec[0];
if(!(state->card->ac97_features&0x0001))
if(rate < 8000)
rate = 8000;
-
- /* Power down the ADC */
- dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
-
- /* Load the rate and read the effective rate */
- i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate);
- rp=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
-
-// printk("ADC rate set to %d Returned %d\n",
-// rate, (int)rp);
-
- rate = (rp * 48000) / clocking;
-
- /* Power it back up */
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
-
+ if(rate != i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE))
+ {
+ /* Power down the ADC */
+ dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
+ /* Load the rate and read the effective rate */
+ i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate);
+ rate=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
+ /* Power it back up */
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+ }
+ rate = (rate * 48000) / clocking;
dmabuf->rate = rate;
#ifdef DEBUG
printk("i810_audio: called i810_set_adc_rate : rate = %d\n", rate);
#endif
-
return rate;
-
}
/* prepare channel attributes for playback */
int ready_2nd = 0;
struct ac97_codec *codec;
u16 eid;
+ int i=0;
+ u32 reg;
- outl(0, card->iobase + GLOB_CNT);
- udelay(500);
- outl(1<<1, card->iobase + GLOB_CNT);
+ reg = inl(card->iobase + GLOB_CNT);
+
+ if((reg&2)==0) /* Cold required */
+ reg|=2;
+ else
+ reg|=4; /* Warm */
+
+ reg&=~8; /* ACLink on */
+ outl(reg , card->iobase + GLOB_CNT);
+
+ while(i<10)
+ {
+ if((inl(card->iobase+GLOB_CNT)&4)==0)
+ break;
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/20);
+ i++;
+ }
+ if(i==10)
+ {
+ printk(KERN_ERR "i810_audio: AC'97 reset failed.\n");
+ return 0;
+ }
+
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/5);
+
+ inw(card->ac97base);
for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
* This thread doesn't need any user-level access,
* so get rid of all our resources
*/
- exit_files(current); /* daemonize doesn't do exit_files */
- current->files = init_task.files;
- atomic_inc(¤t->files->count);
+
daemonize();
/* Setup a nice name */
/*****************************************************************************/
/*
- * plusb.c -- prolific pl-2302 driver.
+ * plusb.c -- prolific pl-2301/pl-2302 driver.
*
* Copyright (C) 2000 Deti Fliegl (deti@fliegl.de)
+ * Copyright (C) 2000 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2000 Eric Z. Ayers (eric@compgen.com)
*
* 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
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
+ * This driver creates a network interface (plusb0, plusb1, ...) that will
+ * send messages over a USB host-host cable based on the Prolific ASIC.
+ * It works a lot like plip or PP over an RS-232C null modem cable.
+ *
+ * Expect speeds of around 330Kbytes/second over a UHCI host controller.
+ * OHCI should be faster. Increase the MTU for faster transfers of large
+ * files. (16384 is a good size)
*
* $Id: plusb.c,v 1.18 2000/02/14 10:38:58 fliegl Exp $
*
+ * Changelog:
+ *
+ * v0.1 deti
+ * Original Version of driver.
+ * v0.2 15 Sep 2000 pavel
+ * Patches to decrease latency by rescheduling the bottom half of
+ * interrupt code.
+ * v0.3 10 Oct 2000 eric
+ * Patches to work in v2.2 backport (v2.4 changes the way net_dev.name
+ * is allocated)
+ * v0.4 19 Oct 2000 eric
+ * Some more performance fixes. Lock re-submitting urbs.
+ * Lower the number of sk_buff's to queue.
+ * v0.5 25 Oct 2000 eric
+ * Removed use of usb_bulk_msg() all together. This caused
+ * the driver to block in an interrupt context.
+ * Consolidate read urb submission into read_urb_submit().
+ * Performance is the same as v0.4.
+ * v0.5.1 27 Oct 2000 eric
+ * Extra debugging messages to help diagnose problem with uchi.o stack.
+ * v0.5.2 27 Oct 2000 eric
+ * Set the 'start' flag for the network device in plusb_net_start()
+ * and plusb_net_stop() (doesn't help)
+ * v0.5.3 27 Oct 2000 pavel
+ * Commented out handlers when -EPIPE is received,
+ * (remove calls to usb_clear_halt()) Since the callback is in
+ * an interrupt context, it doesn't help, it just panics
+ * the kernel. (what do we do?)
+ * Under high load, dev_alloc_skb() fails, the read URB must
+ * be re-submitted.
+ * Added plusb_change_mtu() and increased the size of _BULK_DATA_LEN
+ * v0.5.4 31 Oct 2000 eric
+ * Fix race between plusb_net_xmit() and plusb_bulk_write_complete()
+ * v0.5.5 1 Nov 2000 eric
+ * Remove dev->start field, otherwise, it won't compile in 2.4
+ * Use dev_kfree_skb_any(). (important in 2.4 kernel)
+ * v0.5.6 2 Nov 2000 pavel,eric
+ * Add calls to netif_stop_queue() and netif_start_queue()
+ * Drop packets that come in while the free list is empty.
+ * (This version is being submitted after the release of 2.4-test10)
+ * v0.5.7 6 Nov 2000
+ * Fix to not re-submit the urb on error to help when cables
+ * are yanked (not tested)
+ *
+ *
+ * KNOWN PROBLEMS: (Any suggestions greatfully accepted!)
+ *
+ * 2 Nov 2000
+ * - The shutdown for this may not be entirely clean. Sometimes, the
+ * kernel will Oops when the cable is unplugged, or
+ * if the plusb module is removed.
+ * - If you ifdown a device and then ifup it again, the link will not
+ * always work. You have to 'rmmod plusb ; modprobe plusb' on
+ * both machines to get it to work again. Something must be wrong with
+ * plusb_net_open() and plusb_net_start() ? Maybe
+ * the 'suspend' and 'resume' entry points need to be
+ * implemented?
+ * - Needs to handle -EPIPE correctly in bulk complete handlers.
+ * (replace usb_clear_halt() function with async urbs?)
+ * - I think this code relies too much on one spinlock and does
+ * too much in the interrupt handler. The net1080 code is
+ * much more elegant, and should work for this chip. Its
+ * only drawback is that it is going to be tough to backport
+ * it to v2.2.
+ * - Occasionally the device will hang under the 'uhci.o'
+ * driver. The workaround is to ifdown the device and
+ * remove the modules, then re-insert them. You may have
+ * better luck with the 'usb-uhci.o' driver.
+ * - After using ifconfig down ; ifconfig up, sometimes packets
+ * continue to be received, but there is a framing problem.
+ *
+ * FUTURE DIRECTIONS:
+ *
+ * - Fix the known problems.
+ * - There isn't much functional difference between the net1080
+ * driver and this one. It would be neat if the same driver
+ * could handle both types of chips. Or if both drivers
+ * could handle both types of chips - this one is easier to
+ * backport to the 2.2 kernel.
+ * - Get rid of plusb_add_buf_tail and the single spinlock.
+ * Use a separate spinlock for the 2 lists, and use atomic
+ * operators for writeurb_submitted and readurb_submitted members.
+ *
+ *
*/
/*****************************************************************************/
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-//#define DEBUG
+//#define DEBUG 1
#include <linux/usb.h>
-#include "plusb.h"
+/* Definitions formerly in plusb.h relocated. No need to export them -EZA */
+
+#define _PLUSB_INTPIPE 0x1
+#define _PLUSB_BULKOUTPIPE 0x2
+#define _PLUSB_BULKINPIPE 0x3
+
+#define _SKB_NUM 32
+
+/* increase size of BULK_DATA_LEN so we can use bigger MTU's*/
+#define _BULK_DATA_LEN 32768
+
+
+typedef struct
+{
+ int connected; /* indicates if this structure is active */
+ struct usb_device *usbdev;
+ /* keep track of USB structure */
+ int status; /* Prolific status byte returned from interrupt */
+ int in_bh; /* flag to indicate that we are in the bulk handler */
+ int opened; /* flag to indicate that network dev is open */
+
+ spinlock_t lock; /* Lock for the buffer list. re-used for
+ locking around submitting the readurb member.
+ */
+ urb_t *inturb; /* Read buffer for the interrupt callback */
+ unsigned char * interrupt_in_buffer;
+ /* holds data for the inturb*/
+ urb_t *readurb; /* Read buffer for the bulk data callback */
+ unsigned char * bulk_in_buffer;
+ /* kmalloc'ed data for the readurb */
+ int readurb_submitted;
+ /* Flag to indicate that readurb already sent */
+ urb_t *writeurb; /* Write buffer for the bulk data callback */
+ int writeurb_submitted;
+ /* Flag to indicate that writeurb already sent */
+
+ struct list_head tx_skb_list;
+ /* sk_buff's read from net device */
+ struct list_head free_skb_list;
+ /* free sk_buff list */
+ struct net_device net_dev;
+ /* handle to linux network device */
+ struct net_device_stats net_stats;
+ /* stats to return for ifconfig output */
+} plusb_t,*pplusb_t;
+
+/*
+ * skb_list - queue of packets from the network driver to be delivered to USB
+ */
+typedef struct
+{
+ struct list_head skb_list;
+ struct sk_buff *skb;
+ int state;
+ plusb_t *s;
+} skb_list_t,*pskb_list_t;
+
/* --------------------------------------------------------------------- */
#define NRPLUSB 4
+/*
+ * Interrupt endpoint status byte, from Prolific PL-2301 docs
+ * Check the 'download' link at www.prolifictech.com
+ */
+#define _PL_INT_RES1 0x80 /* reserved */
+#define _PL_INT_RES2 0x40 /* reserved */
+#define _PL_INT_RXD _PL_INT_RES2 /* Read data ready - Not documented by Prolific, but seems to work! */
+#define _PL_INT_TX_RDY 0x20 /* OK to transmit data */
+#define _PL_INT_RESET_O 0x10 /* reset output pipe */
+#define _PL_INT_RESET_I 0x08 /* reset input pipe */
+#define _PL_INT_TX_C 0x04 /* transmission complete */
+#define _PL_INT_TX_REQ 0x02 /* transmission received */
+#define _PL_INT_PEER_E 0x01 /* peer exists */
+
/*-------------------------------------------------------------------*/
static plusb_t plusb[NRPLUSB];
+static void plusb_write_bulk_complete(urb_t *purb);
+static void plusb_read_bulk_complete(urb_t *purb);
+static void plusb_int_complete(urb_t *purb);
+
/* --------------------------------------------------------------------- */
+
+/*
+ * plusb_add_buf_tail - Take the head of the src list and append it to
+ * the tail of the dest list
+ */
static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_head *src)
{
- unsigned long flags;
+ unsigned long flags = 0;
struct list_head *tmp;
int ret = 0;
}
/*-------------------------------------------------------------------*/
-static int plusb_my_bulk(plusb_t *s, int pipe, void *data, int size, int *actual_length)
+/*
+ * dequeue_next_skb - submit the first thing on the tx_skb_list to the
+ * USB stack. This function should be called each time we get a new
+ * message to send to the other host, or each time a message is sucessfully
+ * sent.
+ */
+static void dequeue_next_skb(char * func, plusb_t * s)
{
- int ret;
+ skb_list_t * skb_list;
+ unsigned long flags = 0;
- dbg("plusb_my_bulk: len:%d",size);
+ if (!s->connected)
+ return;
+
+ spin_lock_irqsave (&s->lock, flags);
+
+ if (!list_empty (&s->tx_skb_list) && !s->writeurb_submitted) {
+ int submit_ret;
+ skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list);
- ret=usb_bulk_msg(s->usbdev, pipe, data, size, actual_length, 500);
- if(ret<0) {
- err("plusb: usb_bulk_msg failed(%d)",ret);
+ if (skb_list->skb) {
+ s->writeurb_submitted = 1;
+
+ /* Use the buffer inside the sk_buff directly. why copy? */
+ FILL_BULK_URB_TO(s->writeurb, s->usbdev,
+ usb_sndbulkpipe(s->usbdev, _PLUSB_BULKOUTPIPE),
+ skb_list->skb->data, skb_list->skb->len,
+ plusb_write_bulk_complete, skb_list, 500);
+
+ dbg ("%s: %s: submitting urb. skb_list %p", s->net_dev.name, func, skb_list);
+
+ submit_ret = usb_submit_urb(s->writeurb);
+ if (submit_ret) {
+ s->writeurb_submitted = 0;
+ printk (KERN_CRIT "%s: %s: can't submit writeurb: %d\n",
+ s->net_dev.name, func, submit_ret);
+ }
+ } /* end if the skb value has been filled in */
}
- if( ret == -EPIPE ) {
- warn("CLEAR_FEATURE request to remove STALL condition.");
- if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
- err("request failed");
- }
-
- dbg("plusb_my_bulk: finished act: %d", *actual_length);
- return ret;
+ spin_unlock_irqrestore (&s->lock, flags);
}
-/* --------------------------------------------------------------------- */
-
-static void plusb_bh(void *context)
+/*
+ * submit_read_urb - re-submit the read URB to the stack
+ */
+void submit_read_urb(char * func, plusb_t * s)
{
- plusb_t *s=context;
- struct net_device_stats *stats=&s->net_stats;
- int ret=0;
- int actual_length;
- skb_list_t *skb_list;
- struct sk_buff *skb;
-
- dbg("plusb_bh: i:%d",in_interrupt());
-
- while(!list_empty(&s->tx_skb_list)) {
+ unsigned long flags=0;
- if(!(s->status&_PLUSB_TXOK))
- break;
-
- skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list);
- if(!skb_list->state) {
- dbg("plusb_bh: not yet ready");
- schedule();
- continue;
- }
-
- skb=skb_list->skb;
- ret=plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
- skb->data, skb->len, &actual_length);
+ if (!s->connected)
+ return;
- if(ret || skb->len != actual_length ||!(skb->len%64)) {
- plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
- NULL, 0, &actual_length);
- }
-
- if(!ret) {
- stats->tx_packets++;
- stats->tx_bytes+=skb->len;
- }
- else {
- stats->tx_errors++;
- stats->tx_aborted_errors++;
+ spin_lock_irqsave (&s->lock, flags);
+
+ if (!s->readurb_submitted) {
+ int ret;
+ s->readurb_submitted=1;
+ s->readurb->dev=s->usbdev;
+ ret = usb_submit_urb(s->readurb);
+ if (ret) {
+ printk (KERN_CRIT "%s: %s: error %d submitting read URB\n",
+ s->net_dev.name, func, ret);
+ s->readurb_submitted=0;
}
-
- dbg("plusb_bh: dev_kfree_skb");
-
- dev_kfree_skb(skb);
- skb_list->state=0;
- plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list);
}
- dbg("plusb_bh: finished");
- s->in_bh=0;
+ spin_unlock_irqrestore (&s->lock, flags);
+
}
-
/* --------------------------------------------------------------------- */
+/*
+ * plusb_net_xmit - callback from the network device driver for outgoing data
+ *
+ * Data has arrived to the network device from the local machine and needs
+ * to be sent over the USB cable. This is in an interrupt, so we don't
+ * want to spend too much time in this function.
+ *
+ */
static int plusb_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
plusb_t *s=dev->priv;
skb_list_t *skb_list;
- int ret=NET_XMIT_SUCCESS;
+ unsigned int flags;
dbg("plusb_net_xmit: len:%d i:%d",skb->len,in_interrupt());
- if(!s->connected || list_empty(&s->free_skb_list)) {
- ret=NET_XMIT_CN;
- goto lab;
- }
+ if(!s->connected || !s->opened) {
+ /*
+ NOTE: If we get to this point, you'll return the error
+ kernel: virtual device plusb0 asks to queue packet
+
+ Other things we could do:
+ 1) just drop this packet
+ 2) drop other packets in the queue
+ */
+ return 1;
+ }
- plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list);
+ spin_lock_irqsave (&s->lock, flags);
+
+ if (list_empty(&s->free_skb_list)
+ || plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list)) {
+ /* The buffers on this side are full. DROP the packet
+ I think that this shouldn't happen with the correct
+ use of the netif_XXX functions -EZA
+ */
+ dbg ("plusb: Free list is empty.");
+ kfree_skb(skb);
+ s->net_stats.tx_dropped++;
+ spin_unlock_irqrestore (&s->lock, flags);
+ return 0;
+ }
+
skb_list = list_entry (s->tx_skb_list.prev, skb_list_t, skb_list);
skb_list->skb=skb;
skb_list->state=1;
+ skb_list->s=s;
+
+ if (list_empty(&s->free_skb_list)) {
+ /* apply "backpressure". Tell the net layer to stop sending
+ the driver packets.
+ */
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irqrestore (&s->lock, flags);
+
+ /* If there is no write urb outstanding, pull the first thing
+ off of the list and submit it to the USB stack
+ */
+ dequeue_next_skb("plusb_net_xmit", s);
+
+ return 0;
+}
-lab:
- if(s->in_bh)
- return ret;
+/* --------------------------------------------------------------------- */
- dbg("plusb_net_xmit: queue_task");
+/*
+ * plusb_write_bulk_complete () - callback after the data has been
+ * sent to the USB device, or a timeout occured.
+ */
+static void plusb_write_bulk_complete(urb_t *purb)
+{
+ skb_list_t * skb_list=purb->context;
+ plusb_t *s=skb_list->s;
- s->in_bh=1;
- queue_task(&s->bh, &tq_scheduler);
+ dbg ("%s: plusb_write_bulk_complete: status:%d skb_list:%p\n",
+ s->net_dev.name, purb->status, skb_list);
- dbg("plusb_net_xmit: finished");
- return ret;
+ skb_list->state=0;
-}
+ if( purb->status == -EPIPE ) {
+
+ printk(KERN_CRIT "%s: plusb_write_bulk_complete: got -EPIPE and don't know what to do!\n",
+ s->net_dev.name);
+ }
+
+ if(!purb->status) {
+ s->net_stats.tx_packets++;
+ s->net_stats.tx_bytes+=skb_list->skb->len;
+ }
+ else {
+ err ("%s: plusb_write_bulk_complete: returned ERROR status:%d\n",
+ s->net_dev.name, purb->status);
-/* --------------------------------------------------------------------- */
+ s->net_stats.tx_errors++;
+ s->net_stats.tx_aborted_errors++;
+ }
+
+ dbg("plusb_bh: dev_kfree_skb");
+
+
+#if (LINUX_VERSION_CODE < 0x020300)
+ dev_kfree_skb(skb_list->skb);
+#else
+ /* NOTE: In 2.4 it's a problem to call dev_kfree_skb() in a hard IRQ:
+ Oct 28 23:42:14 bug kernel: Warning: kfree_skb on hard IRQ c023329a
+ */
+ dev_kfree_skb_any(skb_list->skb);
+#endif
+
+ skb_list->skb = NULL;
+ if (plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list)) {
+ err ("plusb: tx list empty. This shouldn't happen.");
+ }
+
+ purb->status = 0;
+ s->writeurb_submitted = 0;
+
+ netif_wake_queue((&s->net_dev));
+
+ dequeue_next_skb("plusb_write_bulk_complete", s);
+
+
+}
-static void plusb_bulk_complete(urb_t *purb)
+/*
+ * plusb_read_bulk_complete - Callback for data arriving from the USB device
+ *
+ * This gets called back when a full 'urb' is received from the remote system.
+ * This urb was allocated by this driver and is kept in the member: s->readurb
+ *
+ */
+static void plusb_read_bulk_complete(urb_t *purb)
{
+
plusb_t *s=purb->context;
- dbg("plusb_bulk_complete: status:%d length:%d",purb->status,purb->actual_length);
+ dbg("plusb_read_bulk_complete: status:%d length:%d", purb->status,purb->actual_length);
+
if(!s->connected)
return;
- if( !purb->status) {
+ if( purb->status == -EPIPE ) {
+
+ printk(KERN_CRIT "%s: plusb_read_bulk_complete: got -EPIPE and I don't know what to do!\n",
+ s->net_dev.name);
+
+ } else if (!purb->status) {
struct sk_buff *skb;
unsigned char *dst;
int len=purb->transfer_buffer_length;
skb=dev_alloc_skb(len);
if(!skb) {
- err("plusb_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame",len);
+ printk (KERN_CRIT "%s: plusb_read_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame\n", s->net_dev.name, len);
stats->rx_dropped++;
- return;
+ } else {
+ dst=(char *)skb_put(skb, len);
+ memcpy( dst, purb->transfer_buffer, len);
+
+ skb->dev=&s->net_dev;
+ skb->protocol=eth_type_trans(skb, skb->dev);
+ stats->rx_packets++;
+ stats->rx_bytes+=len;
+ netif_rx(skb);
}
+
+ }
+
+ s->readurb_submitted = 0;
+
+ if (purb->status) {
+ /* Give the system a chance to "catch its breath". Shortcut
+ re-submitting the read URB> It will be re-submitted if
+ another interrupt comes back. The problem scenario is that
+ the plub is pulled and the read returns an error.
+ You don't want to resumbit in this case.
+ */
+ err ("%s: plusb_read_bulk_complete: returned status %d\n",
+ s->net_dev.name, purb->status);
+ return;
+ }
- dst=(char *)skb_put(skb, len);
- memcpy( dst, purb->transfer_buffer, len);
- skb->dev=&s->net_dev;
- skb->protocol=eth_type_trans(skb, skb->dev);
- stats->rx_packets++;
- stats->rx_bytes+=len;
- netif_rx(skb);
- }
- else
- purb->status=0;
+ purb->status=0;
+
+ /* Keep it coming! resubmit the URB for reading.. Make sure
+ we aren't in contention with the interrupt callback.
+ */
+ submit_read_urb("plusb_read_bulk_complete", s);
}
/* --------------------------------------------------------------------- */
-
+/*
+ * plusb_int_complete - USB driver callback for interrupt msg from the device
+ *
+ * Interrupts are scheduled to go off on a periodic basis (see FILL_INT_URB)
+ * For the prolific device, this is basically just returning a register
+ * filled with bits. See the macro definitions for _PL_INT_XXX above.
+ * Most of these bits are for implementing a machine-machine protocol
+ * and can be set with a special message (described as the "Quicklink"
+ * feature in the prolific documentation.)
+ *
+ * I don't think we need any of that to work as a network device. If a
+ * message is lost, big deal - that's what UNIX networking expects from
+ * the physical layer.
+ *
+ */
static void plusb_int_complete(urb_t *purb)
{
plusb_t *s=purb->context;
s->status=((unsigned char*)purb->transfer_buffer)[0]&255;
+
#if 0
+ /* This isn't right because 0x20 is TX_RDY and
+ sometimes will not be set
+ */
if((s->status&0x3f)!=0x20) {
warn("invalid device status %02X", s->status);
return;
if(!s->connected)
return;
- if(s->status&_PLUSB_RXD) {
- int ret;
-
- if(s->bulkurb->status) {
- err("plusb_int_complete: URB still in use");
- return;
- }
-
- s->bulkurb->dev = s->usbdev;
- ret=usb_submit_urb(s->bulkurb);
- if(ret && ret!=-EBUSY) {
- err("plusb_int_complete: usb_submit_urb failed");
- }
- }
-
- if(purb->status || s->status!=160)
- dbg("status: %p %d buf: %02X", purb->dev, purb->status, s->status);
+ /* Don't turn this on unless you want to see the log flooded. */
+#if 0
+ printk("plusb_int_complete: PEER_E:%d TX_REQ:%d TX_C:%d RESET_IN:%d RESET_O: %d TX_RDY:%d RES1:%d RES2:%d\n",
+ s->status & _PL_INT_PEER_E ? 1 : 0,
+ s->status & _PL_INT_TX_REQ ? 1 : 0,
+ s->status & _PL_INT_TX_C ? 1 : 0,
+ s->status & _PL_INT_RESET_I ? 1 : 0,
+ s->status & _PL_INT_RESET_O ? 1 : 0,
+ s->status & _PL_INT_TX_RDY ? 1 : 0,
+ s->status & _PL_INT_RES1 ? 1 : 0,
+ s->status & _PL_INT_RES2 ? 1 : 0);
+#endif
+
+#if 1
+ /* At first glance, this logic appears to not really be needed, but
+ it can help recover from intermittent problems where the
+ usb_submit_urb() fails in the read callback. -EZA
+ */
+
+ /* Try to submit the read URB again. Make sure
+ we aren't in contention with the bulk read callback
+ */
+ submit_read_urb ("plusb_int_complete", s);
+
+ /* While we are at it, why not check to see if the
+ write urb should be re-submitted?
+ */
+ dequeue_next_skb("plusb_int_complete", s);
+
+#endif
+
}
/* --------------------------------------------------------------------- */
-
+/*
+ * plusb_free_all - deallocate all memory kept for an instance of the device.
+ */
static void plusb_free_all(plusb_t *s)
{
struct list_head *skb;
skb_list_t *skb_list;
dbg("plusb_free_all");
+
+ /* set a flag to tell all callbacks to cease and desist */
+ s->connected = 0;
+
+ /* If the interrupt handler is about to fire, let it finish up */
run_task_queue(&tq_immediate);
if(s->inturb) {
dbg("unlink inturb");
usb_unlink_urb(s->inturb);
- }
-
- if(s->inturb && s->inturb->transfer_buffer) {
- dbg("kfree inturb->transfer_buffer");
- kfree(s->inturb->transfer_buffer);
- s->inturb->transfer_buffer=NULL;
- }
-
- if(s->inturb) {
dbg("free_urb inturb");
usb_free_urb(s->inturb);
s->inturb=NULL;
}
+
+ if(s->interrupt_in_buffer) {
+ dbg("kfree s->interrupt_in_buffer");
+ kfree(s->interrupt_in_buffer);
+ s->interrupt_in_buffer=NULL;
+ }
- if(s->bulkurb) {
- dbg("unlink bulkurb");
- usb_unlink_urb(s->bulkurb);
+ if(s->readurb) {
+ dbg("unlink readurb");
+ usb_unlink_urb(s->readurb);
+ dbg("free_urb readurb:");
+ usb_free_urb(s->readurb);
+ s->readurb=NULL;
}
-
- if(s->bulkurb && s->bulkurb->transfer_buffer) {
- dbg("kfree bulkurb->transfer_buffer");
- kfree(s->bulkurb->transfer_buffer);
- s->bulkurb->transfer_buffer=NULL;
+
+ if(s->bulk_in_buffer) {
+ dbg("kfree s->bulk_in_buffer");
+ kfree(s->bulk_in_buffer);
+ s->bulk_in_buffer=NULL;
}
- if(s->bulkurb) {
- dbg("free_urb bulkurb");
- usb_free_urb(s->bulkurb);
- s->bulkurb=NULL;
+
+ s->readurb_submitted = 0;
+
+ if(s->writeurb) {
+ dbg("unlink writeurb");
+ usb_unlink_urb(s->writeurb);
+ dbg("free_urb writeurb:");
+ usb_free_urb(s->writeurb);
+ s->writeurb=NULL;
}
+
+ s->writeurb_submitted = 0;
while(!list_empty(&s->free_skb_list)) {
skb=s->free_skb_list.next;
skb=s->tx_skb_list.next;
list_del(skb);
skb_list = list_entry (skb, skb_list_t, skb_list);
- kfree(skb_list);
+ if (skb_list->skb) {
+ dbg ("Freeing SKB in queue");
+#if (LINUX_VERSION_CODE < 0x020300)
+ dev_kfree_skb(skb_list->skb);
+#else
+ dev_kfree_skb_any(skb_list->skb);
+#endif
+ skb_list->skb = NULL;
+ }
+ kfree(skb_list);
}
+
+ s->in_bh=0;
+
dbg("plusb_free_all: finished");
}
/*-------------------------------------------------------------------*/
-
+/*
+ * plusb_alloc - allocate memory associated with one instance of the device
+ */
static int plusb_alloc(plusb_t *s)
{
int i;
skb_list_t *skb;
dbg("plusb_alloc");
-
+
for(i=0 ; i < _SKB_NUM ; i++) {
skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL);
if(!skb) {
goto reject;
}
- dbg("bulkurb allocation:");
- s->bulkurb=usb_alloc_urb(0);
- if(!s->bulkurb) {
+ dbg("bulk read urb allocation:");
+ s->readurb=usb_alloc_urb(0);
+ if(!s->readurb) {
err("alloc_urb failed");
goto reject;
}
- dbg("bulkurb/inturb init:");
- s->inturb->dev=s->usbdev;
- s->inturb->pipe=usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE);
- s->inturb->transfer_buffer=kmalloc(64, GFP_KERNEL);
- if(!s->inturb->transfer_buffer) {
- err("kmalloc failed");
+ dbg("bulk write urb allocation:");
+ s->writeurb=usb_alloc_urb(0);
+ if(!s->writeurb) {
+ err("alloc_urb for writeurb failed");
goto reject;
}
- s->inturb->transfer_buffer_length=1;
- s->inturb->complete=plusb_int_complete;
- s->inturb->context=s;
- s->inturb->interval=10;
+ dbg("readurb/inturb init:");
+ s->interrupt_in_buffer=kmalloc(64, GFP_KERNEL);
+ if(!s->interrupt_in_buffer) {
+ err("kmalloc failed");
+ goto reject;
+ }
+
+ /* The original value of '10' makes this interrupt fire off a LOT.
+ It was set so low because the callback determined when to
+ sumbit the buld read URB. I've lowered it to 100 - the driver
+ doesn't depend on that logic anymore. -EZA
+ */
+ FILL_INT_URB(s->inturb, s->usbdev,
+ usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE),
+ s->interrupt_in_buffer, 1,
+ plusb_int_complete, s, HZ);
dbg("inturb submission:");
if(usb_submit_urb(s->inturb)<0) {
err("usb_submit_urb failed");
goto reject;
}
-
- dbg("bulkurb init:");
- s->bulkurb->dev=s->usbdev;
- s->bulkurb->pipe=usb_rcvbulkpipe (s->usbdev, _PLUSB_BULKINPIPE);
- s->bulkurb->transfer_buffer=kmalloc(_BULK_DATA_LEN, GFP_KERNEL);
- if(!s->bulkurb->transfer_buffer) {
- err("kmalloc failed");
- goto reject;
- }
-
- s->bulkurb->transfer_buffer_length=_BULK_DATA_LEN;
- s->bulkurb->complete=plusb_bulk_complete;
- s->bulkurb->context=s;
- dbg("plusb_alloc: finished");
+ dbg("readurb init:");
+ s->bulk_in_buffer = kmalloc(_BULK_DATA_LEN, GFP_KERNEL);
+ if (!s->bulk_in_buffer) {
+ err("kmalloc %d bytes for bulk in buffer failed", _BULK_DATA_LEN);
+ }
+
+ FILL_BULK_URB(s->readurb, s->usbdev,
+ usb_rcvbulkpipe(s->usbdev, _PLUSB_BULKINPIPE),
+ s->bulk_in_buffer, _BULK_DATA_LEN,
+ plusb_read_bulk_complete, s);
+
+ /* The write urb will be initialized inside the network
+ interrupt.
+ */
+
+ /* get the bulk read going */
+ submit_read_urb("plusb_alloc", s);
+
+ dbg ("plusb_alloc: finished. readurb=%p writeurb=%p inturb=%p",
+ s->readurb, s->writeurb, s->inturb);
return 0;
return -ENOMEM;
s->opened=1;
- MOD_INC_USE_COUNT;
+ MOD_INC_USE_COUNT;
+
+ netif_start_queue(dev);
+
dbg("plusb_net_open: success");
return 0;
static int plusb_net_stop(struct net_device *dev)
{
plusb_t *s=dev->priv;
+
+ netif_stop_queue(dev);
dbg("plusb_net_stop");
- plusb_free_all(s);
s->opened=0;
+ plusb_free_all(s);
+
MOD_DEC_USE_COUNT;
dbg("plusb_net_stop:finished");
return 0;
plusb_t *s = ptr;
dbg("plusb_disconnect");
- s->connected = 0;
plusb_free_all(s);
dbg("unregistering netdev: %s",s->net_dev.name);
unregister_netdev(&s->net_dev);
s->net_dev.name[0] = '\0';
+#if (LINUX_VERSION_CODE < 0x020300)
+ dbg("plusb_disconnect: About to free name");
+ kfree (s->net_dev.name);
+ s->net_dev.name = NULL;
+#endif
}
dbg("plusb_disconnect: finished");
/* --------------------------------------------------------------------- */
+static int plusb_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > _BULK_DATA_LEN))
+ return -EINVAL;
+
+ printk("plusb: changing mtu to %d\n", new_mtu);
+ dev->mtu = new_mtu;
+
+ /* NOTE: Could we change the size of the READ URB here dynamically
+ to save kernel memory?
+ */
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
int plusb_net_init(struct net_device *dev)
{
dbg("plusb_net_init");
dev->hard_start_xmit=plusb_net_xmit;
dev->get_stats = plusb_net_get_stats;
ether_setup(dev);
- dev->tx_queue_len = 0;
+ dev->change_mtu = plusb_change_mtu;
+ /* Setting the default MTU to 16K gives good performance for
+ me, and keeps the ping latency low too. Setting it up
+ to 32K made performance go down. -EZA
+ Pavel says it would be best not to do this...
+ */
+ /*dev->mtu=16384; */
+ dev->tx_queue_len = 0;
dev->flags = IFF_POINTOPOINT|IFF_NOARP;
return NULL;
}
+#if (LINUX_VERSION_CODE < 0x020300)
+ {
+ int i;
+
+ /* For Kernel version 2.2, the driver is responsible for
+ allocating this memory. For version 2.4, the rules
+ have apparently changed, but there is a nifty function
+ 'init_netdev' that might make this easier... It's in
+ ../net/net_init.c - but can we get there from here? (no)
+ -EZA
+ */
+
+ /* Find the device number... we seem to have lost it... -EZA */
+ for (i=0; i<NRPLUSB; i++) {
+ if (&plusb[i] == s)
+ break;
+ }
+
+ if(!s->net_dev.name) {
+ s->net_dev.name = kmalloc(strlen("plusbXXXX"), GFP_KERNEL);
+ sprintf (s->net_dev.name, "plusb%d", i);
+ s->net_dev.init=plusb_net_init;
+ s->net_dev.priv=s;
+
+ printk ("plusb_probe: Registering Device\n");
+ if(!register_netdev(&s->net_dev))
+ info("registered: %s", s->net_dev.name);
+ else {
+ err("register_netdev failed");
+ s->net_dev.name[0] = '\0';
+ }
+ dbg ("plusb_probe: Connected!");
+ }
+ }
+#else
+ /* Kernel version 2.3+ works a little bit differently than 2.2 */
if(!s->net_dev.name[0]) {
strcpy(s->net_dev.name, "plusb%d");
s->net_dev.init=plusb_net_init;
s->net_dev.name[0] = '\0';
}
}
-
+#endif
+
s->connected = 1;
if(s->opened) {
for (u = 0; u < NRPLUSB; u++) {
plusb_t *s = &plusb[u];
memset (s, 0, sizeof (plusb_t));
- s->bh.routine = (void (*)(void *))plusb_bh;
- s->bh.data = s;
INIT_LIST_HEAD (&s->tx_skb_list);
INIT_LIST_HEAD (&s->free_skb_list);
spin_lock_init (&s->lock);
dbg("plusb_cleanup");
for (u = 0; u < NRPLUSB; u++) {
plusb_t *s = &plusb[u];
+#if (LINUX_VERSION_CODE < 0x020300)
+ if(s->net_dev.name) {
+ dbg("unregistering netdev: %s",s->net_dev.name);
+ unregister_netdev(&s->net_dev);
+ s->net_dev.name[0] = '\0';
+ kfree (s->net_dev.name);
+ s->net_dev.name = NULL;
+ }
+#else
if(s->net_dev.name[0]) {
dbg("unregistering netdev: %s",s->net_dev.name);
unregister_netdev(&s->net_dev);
+ s->net_dev.name[0] = '\0';
}
+#endif
}
usb_deregister (&plusb_driver);
dbg("plusb_cleanup: finished");
+++ /dev/null
-#define _PLUSB_INTPIPE 0x1
-#define _PLUSB_BULKOUTPIPE 0x2
-#define _PLUSB_BULKINPIPE 0x3
-
-#define _SKB_NUM 1000
-// 7 6 5 4 3 2 1 0
-// tx rx 1 0
-// 1110 0000 rxdata
-// 1010 0000 idle
-// 0010 0000 tx over
-// 0110 tx over + rxd
-
-#define _PLUSB_RXD 0x40
-#define _PLUSB_TXOK 0x80
-
-#ifdef __KERNEL__
-#define _BULK_DATA_LEN 16384
-
-typedef struct
-{
- struct list_head skb_list;
- struct sk_buff *skb;
- int state;
-} skb_list_t,*pskb_list_t;
-
-typedef struct
-{
- struct usb_device *usbdev;
-
- int status;
- int connected;
- int in_bh;
- int opened;
-
- spinlock_t lock;
-
- urb_t *inturb;
- urb_t *bulkurb;
-
- struct list_head tx_skb_list;
- struct list_head free_skb_list;
- struct tq_struct bh;
-
- struct net_device net_dev;
- struct net_device_stats net_stats;
-} plusb_t,*pplusb_t;
-
-#endif
}
/*-------------------------------------------------------------------*/
+/* usb_control_msg() - builds control urb, and waits for completion */
+/* Synchronous behavior - don't use this function from within an */
+/* interrupt context, (like a bottom half handler.) In this case, */
+/* use usb_submit_urb() directly instead. */
+
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
{
}
/*-------------------------------------------------------------------*/
-/* compatibility wrapper, builds bulk urb, and waits for completion */
-/* synchronous behavior */
+/* usb_bulk_msg() Builds a bulk urb, and waits for completion. */
+/* Synchronous behavior - don't use this function from within an */
+/* interrupt context, (like a bottom half handler.) In this case, */
+/* use usb_submit_urb() directly instead. */
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
-obj-$(CONFIG_FB_SIS) += sisfb.o
ifeq ($(CONFIG_FB_MATROX),y)
SUB_DIRS += matrox
endif
endif
+ifeq ($(CONFIG_FB_SIS),y)
+SUB_DIRS += sis
+obj-y += sis/sisfb.o
+else
+ ifeq ($(CONFIG_FB_SIS),m)
+ MOD_SUB_DIRS += sis
+ endif
+endif
+
+
obj-$(CONFIG_FB_SUN3) += sun3fb.o
obj-$(CONFIG_FB_BWTWO) += bwtwofb.o
obj-$(CONFIG_FB_HGA) += hgafb.o
--- /dev/null
+#
+# Makefile for the SiS framebuffer device driver
+#
+
+O_TARGET := sisfb.o
+O_OBJS := sis_main.o sis_300.o sis_301.o
+#O_OBJS := sis_300.o
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+
--- /dev/null
+#include "sis.h"
+
+#define PRIMARY_VGA 1 //1: SiS is primary vga 0:SiS is secondary vga
+#define ModeInfoFlag 0x07
+#define MemoryInfoFlag 0x1E0
+#define MemorySizeShift 0x05
+#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 CRT1Len 17
+#define DoubleScanMode 0x8000
+#define ADR_CRT2PtrData 0x20E //address of CRT2PtrData in ROM image
+#define offset_Zurac 0x210
+#define ADR_LVDSDesPtrData 0x212
+#define ADR_LVDSCRT1DataPtr 0x214
+
+#define SoftDRAMType 0x80 //5/19/2000,Mars,for soft setting dram type
+#define SoftSettingAddr 0x52
+#define ModeSettingAddr 0x53
+
+#define InterlaceMode 0x80
+#define HalfDCLK 0x1000
+#define DACInfoFlag 0x18
+#define LineCompareOff 0x400
+#define ActivePAL 0x20
+#define ActivePALShift 5
+
+
+#define SelectCRT2Rate 0x4
+#define ProgrammingCRT2 0x1
+#define CRT2DisplayFlag 0x2000
+#define SetCRT2ToRAMDAC 0x0040
+#define Charx8Dot 0x0200
+#define LCDDataLen 8
+#define SetCRT2ToLCD 0x0020
+#define SetCRT2ToHiVisionTV 0x0080
+#define HiTVDataLen 12
+#define TVDataLen 16
+#define SetPALTV 0x0100
+#define SetInSlaveMode 0x0200
+#define SetCRT2ToTV 0x009C
+#define SetNotSimuTVMode 0x0400
+#define SetSimuScanMode 0x0001
+#define DriverMode 0x4000
+#define CRT2Mode 0x0800
+//#define ReIndexEnhLCD 4
+#define HalfDCLK 0x1000
+//#define HiVisionTVHT 2100
+//#define HiVisionTVVT 2100
+#define NTSCHT 1716
+#define NTSCVT 525
+#define PALHT 1728
+#define PALVT 625
+
+#define VCLKStartFreq 25
+//Freq of first item in VCLKTable
+
+#define SoftDramType 0x80
+#define VCLK65 0x09
+#define VCLK108_2 0x14
+//#define LCDIs1280x1024Panel 0x04
+//#define HiVisionVCLK 0x22
+#define TVSimuMode 0x02
+#define SetCRT2ToSVIDEO 0x08
+//#define LCDRGB18Bit 0x20
+#define LCDRGB18Bit 0x01
+#define Panel1280x1024 0x03
+#define Panel1024x768 0x02
+#define Panel800x600 0x01
+#define RPLLDIV2XO 0x04
+#define LoadDACFlag 0x1000
+#define AfterLockCRT2 0x4000
+#define SupportRAMDAC2 0x0040
+#define SupportLCD 0x0020
+//#define Support1024x768LCD 0x0020
+//#define Support1280x1024LCD 0x0040
+#define SetCRT2ToAVIDEO 0x0004
+#define SetCRT2ToSCART 0x0010
+//#define NoSupportSimuTV 0x0100
+#define NoSupportSimuTV 0x2000
+#define Ext2StructSize 5
+#define SupportTV 0x0008
+//#define TVVCLKDIV2 0x020
+//#define TVVCLK 0x021
+#define TVVCLKDIV2 0x021
+#define TVVCLK 0x022
+#define SwitchToCRT2 0x0002
+#define LCDVESATiming 0x08
+#define SetSCARTOutput 0x01
+#define SCARTSense 0x04
+#define Monitor1Sense 0x20
+#define Monitor2Sense 0x10
+#define SVIDEOSense 0x02
+#define AVIDEOSense 0x01
+#define LCDSense 0x08
+#define BoardTVType 0x02
+#define HotPlugFunction 0x08
+#define StStructSize 0x06
+
+#define ExtChip301 0x02
+#define ExtChipLVDS 0x04
+#define ExtChipTrumpion 0x06
+#define LCDNonExpanding 0x10
+#define LCDNonExpandingShift 4
+#define LVDSDataLen 6
+#define EnableLVDSDDA 0x10
+#define LCDSync 0x20
+#define SyncPP 0x0000
+#define LCDSyncBit 0xE0
+#define LVDSDesDataLen 3
+#define LVDSCRT1Len 15
+#define ActiveNonExpanding 0x40
+#define ActiveNonExpandingShift 6
+#define ModeSwitchStatus 0x0F
+#define SoftTVType 0x40
+
+#define PanelType00 0x00
+#define PanelType01 0x08
+#define PanelType02 0x10
+#define PanelType03 0x18
+#define PanelType04 0x20
+#define PanelType05 0x28
+#define PanelType06 0x30
+#define PanelType07 0x38
+#define PanelType08 0x40
+#define PanelType09 0x48
+#define PanelType0A 0x50
+#define PanelType0B 0x58
+#define PanelType0C 0x60
+#define PanelType0D 0x68
+#define PanelType0E 0x70
+#define PanelType0F 0x78
+
--- /dev/null
+#ifndef _SISFB_LOCAL
+#define _SISFB_LOCAL
+#include <linux/types.h>
+
+#undef NOBIOS
+#undef CONFIG_FB_SIS_LINUXBIOS
+
+#ifdef NOBIOS
+#undef CONFIG_FB_SIS_LINUXBIOS
+#endif
+
+#define TRUE 1
+#define FALSE 0
+#define NO_ERROR 0
+
+/* Data type conversion */
+#define UCHAR unsigned char
+#define USHORT unsigned short
+#define ULONG unsigned long
+#define SHORT short
+#define BOOLEAN int
+#define VOID void
+
+#define IND_SIS_CRT2_PORT_04 0x04 - 0x30
+#define IND_SIS_CRT2_PORT_10 0x10 - 0x30
+#define IND_SIS_CRT2_PORT_12 0x12 - 0x30
+#define IND_SIS_CRT2_PORT_14 0x14 - 0x30
+
+#define ClearALLBuffer(x) ClearBuffer(x)
+
+/* Data struct for setmode codes */
+typedef enum _CHIP_TYPE {
+ SIS_GENERIC = 0,
+ SIS_Glamour, //300
+ SIS_Trojan, //630
+ SIS_Spartan, //540
+ SIS_730,
+ MAX_SIS_CHIP
+} CHIP_TYPE;
+
+typedef enum _LCD_TYPE {
+ LCD1024 = 1,
+ LCD1280,
+ LCD2048,
+ LCD1920,
+ LCD1600,
+ LCD800,
+ LCD640
+} LCD_TYPE;
+
+
+typedef struct _HW_DEVICE_EXTENSION
+{
+ unsigned long VirtualRomBase;
+ char *VirtualVideoMemoryAddress;
+ unsigned short IOAddress;
+ CHIP_TYPE jChipID;
+ int bIntegratedMMEnabled;
+ LCD_TYPE usLCDType;
+ u8 revision_id;
+ u8 uVBChipID;
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+#endif
--- /dev/null
+/* Recently Update by v1.09.50 */
+#include "sis_300.h"
+
+#if defined(ALLOC_PRAGMA)
+#pragma alloc_text(PAGE,SiSSetMode)
+#pragma alloc_text(PAGE,SiSInit300)
+#endif
+
+
+#ifdef NOBIOS
+BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase;
+ ULONG FBAddr = (ULONG)HwDeviceExtension->VirtualVideoMemoryAddress;
+ USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress;
+ UCHAR i,temp,AGP;
+ ULONG j,k,ulTemp;
+ UCHAR SR07,SR11,SR19,SR1A,SR1F,SR21,SR22,SR23,SR24,SR25,SR32;
+ UCHAR SR14;
+ ULONG Temp;
+
+ if(ROMAddr==0) return (FALSE);
+ if(FBAddr==0) return (FALSE);
+ if(BaseAddr==0) return (FALSE);
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ if(!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE);
+
+ P3c4=BaseAddr+0x14;
+ P3d4=BaseAddr+0x24;
+ P3c0=BaseAddr+0x10;
+ P3ce=BaseAddr+0x1e;
+ P3c2=BaseAddr+0x12;
+ P3ca=BaseAddr+0x1a;
+ P3c6=BaseAddr+0x16;
+ P3c7=BaseAddr+0x17;
+ P3c8=BaseAddr+0x18;
+ P3c9=BaseAddr+0x19;
+ P3da=BaseAddr+0x2A;
+ Set_LVDS_TRUMPION();
+
+ SetReg1(P3c4,0x05,0x86); // 1.Openkey
+ SR14 = (UCHAR)GetReg1(P3c4,0x14);
+ SR19 = (UCHAR)GetReg1(P3c4,0x19);
+ SR1A = (UCHAR)GetReg1(P3c4,0x1A);
+ for(i=0x06;i< 0x20;i++) SetReg1(P3c4,i,0); // 2.Reset Extended register
+ for(i=0x21;i<=0x27;i++) SetReg1(P3c4,i,0); // Reset Extended register
+ for(i=0x31;i<=0x3D;i++) SetReg1(P3c4,i,0);
+ for(i=0x30;i<=0x37;i++) SetReg1(P3d4,i,0);
+
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ temp=(UCHAR)SR1A; // 3.Set Define Extended register
+ else
+ {
+ temp=*((UCHAR *)(ROMAddr+SoftSettingAddr));
+ if((temp&SoftDRAMType)==0){
+ temp=(UCHAR)GetReg1(P3c4,0x3A); // 3.Set Define Extended register
+ }
+ }
+ RAMType=temp&0x07;
+ SetMemoryClock(ROMAddr);
+ for(k=0; k<5; k++)
+ {
+ for(j=0; j<0xffff; j++)
+ {
+ ulTemp = (ULONG)GetReg1(P3c4, 0x05);
+ }
+ }
+ Temp = (ULONG)GetReg1(P3c4, 0x3C);
+ Temp = Temp | 0x01;
+ SetReg1(P3c4, 0x3C, (USHORT)Temp);
+ for(k=0; k<5; k++)
+ {
+ for(j=0; j<0xffff; j++)
+ {
+ Temp = (ULONG)GetReg1(P3c4, 0x05);
+ }
+ }
+ Temp = (ULONG)GetReg1(P3c4, 0x3C);
+ Temp = Temp & 0xFE;
+ SetReg1(P3c4, 0x3C, (USHORT)Temp);
+ for(k=0; k<5; k++)
+ {
+ for(j=0; j<0xffff; j++)
+ {
+ Temp = (ULONG)GetReg1(P3c4, 0x05);
+ }
+ }
+
+ SR07=*((UCHAR *)(ROMAddr+0xA4));
+ SetReg1(P3c4,0x07,SR07);
+ if (HwDeviceExtension->jChipID == SIS_Glamour )
+ {
+ for(i=0x15;i<=0x1C;i++)
+ {
+ temp=*((UCHAR *)(ROMAddr+0xA5+((i-0x15)*8)+RAMType));
+ SetReg1(P3c4,i,temp);
+ }
+ }
+
+ SR1F=*((UCHAR *)(ROMAddr+0xE5));
+ SetReg1(P3c4,0x1F,SR1F);
+
+ AGP=1; // Get AGP
+ temp=(UCHAR)GetReg1(P3c4,0x3A);
+ temp=temp&0x30;
+ if(temp==0x30) AGP=0; // PCI
+
+ SR21=*((UCHAR *)(ROMAddr+0xE6));
+ if(AGP==0) SR21=SR21&0xEF; // PCI
+ SetReg1(P3c4,0x21,SR21);
+
+ SR22=*((UCHAR *)(ROMAddr+0xE7));
+ if(AGP==1) SR22=SR22&0x20; // AGP
+ SetReg1(P3c4,0x22,SR22);
+
+ SR23=*((UCHAR *)(ROMAddr+0xE8));
+ SetReg1(P3c4,0x23,SR23);
+
+ SR24=*((UCHAR *)(ROMAddr+0xE9));
+ SetReg1(P3c4,0x24,SR24);
+
+ SR25=*((UCHAR *)(ROMAddr+0xEA));
+ SetReg1(P3c4,0x25,SR25);
+
+ SR32=*((UCHAR *)(ROMAddr+0xEB));
+ SetReg1(P3c4,0x32,SR32);
+
+ SR11=0x0F;
+ SetReg1(P3c4,0x11,SR11);
+
+ if(IF_DEF_LVDS==1){ //LVDS
+ temp=ExtChipLVDS;
+ }else if(IF_DEF_TRUMPION==1){ //Trumpion
+ temp=ExtChipTrumpion;
+ }else{ //301
+ temp=ExtChip301;
+ }
+ SetReg1(P3d4,0x37,temp);
+
+ //For SiS 630/540 Chip
+ //Restore SR14, SR19 and SR1A
+ SetReg1(P3c4,0x14,SR14);
+ SetReg1(P3c4,0x19,SR19);
+ SetReg1(P3c4,0x1A,SR1A);
+
+ SetReg3(P3c6,0xff); // Reset register
+ ClearDAC(P3c8); // Reset register
+ DetectMonitor(HwDeviceExtension); //sense CRT1
+ GetSenseStatus(HwDeviceExtension,BaseAddr,ROMAddr);//sense CRT2
+
+ return(TRUE);
+}
+
+VOID Set_LVDS_TRUMPION(VOID)
+{
+ IF_DEF_LVDS=0;
+ IF_DEF_TRUMPION=0;
+}
+
+VOID SetMemoryClock(ULONG ROMAddr)
+{
+ UCHAR data,i;
+
+ MCLKData=*((USHORT *)(ROMAddr+0x20C)); // MCLKData Table
+ MCLKData=MCLKData+RAMType*5;
+ ECLKData=MCLKData+0x28;
+
+ for(i=0x28;i<=0x2A;i++) { // Set MCLK
+ data=*((UCHAR *)(ROMAddr+MCLKData));
+ SetReg1(P3c4,i,data);
+ MCLKData++;
+ }
+
+ for(i=0x2E;i<=0x30;i++) { // Set ECLK
+ data=*((UCHAR *)(ROMAddr+ECLKData));
+ SetReg1(P3c4,i,data);
+ ECLKData++;
+ }
+}
+#endif /* NOBIOS */
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ ULONG ROMAddr = 0;
+ USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress;
+ UCHAR i,temp,AGP;
+ ULONG j,k,ulTemp;
+ UCHAR SR07,SR11,SR19,SR1A,SR1F,SR21,SR22,SR23,SR24,SR25,SR32;
+ UCHAR SR14;
+ ULONG Temp;
+
+ if(BaseAddr==0) return (FALSE);
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ if(!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE);
+
+ P3c4=BaseAddr+0x14;
+ P3d4=BaseAddr+0x24;
+ P3c0=BaseAddr+0x10;
+ P3ce=BaseAddr+0x1e;
+ P3c2=BaseAddr+0x12;
+ P3ca=BaseAddr+0x1a;
+ P3c6=BaseAddr+0x16;
+ P3c7=BaseAddr+0x17;
+ P3c8=BaseAddr+0x18;
+ P3c9=BaseAddr+0x19;
+ P3da=BaseAddr+0x2A;
+
+ SetReg1(P3c4,0x05,0x86); // 1.Openkey
+
+ SR14 = (UCHAR)GetReg1(P3c4,0x14);
+ SR19 = (UCHAR)GetReg1(P3c4,0x19);
+ SR1A = (UCHAR)GetReg1(P3c4,0x1A);
+
+ for(i=0x06;i< 0x20;i++) SetReg1(P3c4,i,0); // 2.Reset Extended register
+ for(i=0x21;i<=0x27;i++) SetReg1(P3c4,i,0); // Reset Extended register
+ for(i=0x31;i<=0x3D;i++) SetReg1(P3c4,i,0);
+ for(i=0x30;i<=0x37;i++) SetReg1(P3d4,i,0);
+
+ temp=(UCHAR)SR1A; // 3.Set Define Extended register
+
+ RAMType=temp&0x07;
+ SetMemoryClock(ROMAddr);
+ for(k=0; k<5; k++)
+ for(j=0; j<0xffff; j++)
+ ulTemp = (ULONG)GetReg1(P3c4, 0x05);
+
+ Temp = (ULONG)GetReg1(P3c4, 0x3C);
+ Temp = Temp | 0x01;
+ SetReg1(P3c4, 0x3C, (USHORT)Temp);
+
+ for(k=0; k<5; k++)
+ for(j=0; j<0xffff; j++)
+ Temp = (ULONG)GetReg1(P3c4, 0x05);
+
+ Temp = (ULONG)GetReg1(P3c4, 0x3C);
+ Temp = Temp & 0xFE;
+ SetReg1(P3c4, 0x3C, (USHORT)Temp);
+
+ for(k=0; k<5; k++)
+ for(j=0; j<0xffff; j++)
+ Temp = (ULONG)GetReg1(P3c4, 0x05);
+
+ SR07=SRegsInit[0x07];
+ SetReg1(P3c4,0x07,SR07);
+
+ SR1F=SRegsInit[0x1F];
+ SetReg1(P3c4,0x1F,SR1F);
+
+ AGP=1; // Get AGP
+ temp=(UCHAR)GetReg1(P3c4,0x3A);
+ temp=temp&0x30;
+ if(temp==0x30) AGP=0; // PCI
+
+ SR21=SRegsInit[0x21];
+ if(AGP==0) SR21=SR21&0xEF; // PCI
+ SetReg1(P3c4,0x21,SR21);
+
+ SR22=SRegsInit[0x22];
+ if(AGP==1) SR22=SR22&0x20; // AGP
+ SetReg1(P3c4,0x22,SR22);
+
+ SR23=SRegsInit[0x23];
+ SetReg1(P3c4,0x23,SR23);
+
+ SR24=SRegsInit[0x24];
+ SetReg1(P3c4,0x24,SR24);
+
+ SR25=SRegsInit[0x25];
+ SetReg1(P3c4,0x25,SR25);
+
+ SR32=SRegsInit[0x32];
+ SetReg1(P3c4,0x32,SR32);
+
+ SR11=0x0F;
+ SetReg1(P3c4,0x11,SR11);
+
+ temp=ExtChip301;
+ SetReg1(P3d4,0x37,temp);
+
+ SetReg1(P3c4,0x14,SR14);
+ SetReg1(P3c4,0x19,SR19);
+ SetReg1(P3c4,0x1A,SR1A);
+
+ SetReg3(P3c6,0xff); // Reset register
+ ClearDAC(P3c8); // Reset register
+ DetectMonitor(HwDeviceExtension); //sense CRT1
+
+ return(TRUE);
+}
+
+VOID SetMemoryClock(ULONG ROMAddr)
+{
+ UCHAR i;
+ USHORT idx;
+
+ u8 MCLK[] = {
+ 0x5A, 0x64, 0x80, 0x66, 0x00, // SDRAM
+ 0xB3, 0x45, 0x80, 0x83, 0x00, // SGRAM
+ 0x37, 0x61, 0x80, 0x00, 0x01, // ESDRAM
+ 0x37, 0x22, 0x80, 0x33, 0x01,
+ 0x37, 0x61, 0x80, 0x00, 0x01,
+ 0x37, 0x61, 0x80, 0x00, 0x01,
+ 0x37, 0x61, 0x80, 0x00, 0x01,
+ 0x37, 0x61, 0x80, 0x00, 0x01
+ };
+
+ u8 ECLK[] = {
+ 0x54, 0x43, 0x80, 0x00, 0x01,
+ 0x53, 0x43, 0x80, 0x00, 0x01,
+ 0x55, 0x43, 0x80, 0x00, 0x01,
+ 0x52, 0x43, 0x80, 0x00, 0x01,
+ 0x3f, 0x42, 0x80, 0x00, 0x01,
+ 0x54, 0x43, 0x80, 0x00, 0x01,
+ 0x54, 0x43, 0x80, 0x00, 0x01,
+ 0x54, 0x43, 0x80, 0x00, 0x01
+ };
+
+ idx = RAMType * 5;
+
+ for (i = 0x28; i <= 0x2A; i++) { // Set MCLK
+ SetReg1(P3c4, i, MCLK[idx]);
+ idx++;
+ }
+
+ idx = RAMType * 5;
+ for (i = 0x2E; i <= 0x30; i++) { // Set ECLK
+ SetReg1(P3c4, i, ECLK[idx]);
+ idx++;
+ }
+
+}
+
+#endif /* CONFIG_FB_SIS_LINUXBIOS */
+
+// =========================================
+// ======== SiS SetMode Function ==========
+// =========================================
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo)
+{
+ ULONG i;
+ USHORT cr30flag,cr31flag;
+ ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase;
+ USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress;
+
+ P3c4=BaseAddr+0x14;
+ P3d4=BaseAddr+0x24;
+ P3c0=BaseAddr+0x10;
+ P3ce=BaseAddr+0x1e;
+ P3c2=BaseAddr+0x12;
+ P3ca=BaseAddr+0x1a;
+ P3c6=BaseAddr+0x16;
+ P3c7=BaseAddr+0x17;
+ P3c8=BaseAddr+0x18;
+ P3c9=BaseAddr+0x19;
+ P3da=BaseAddr+0x2A;
+
+ cr30flag=(UCHAR)GetReg1(P3d4,0x30);
+
+ if(((cr30flag&0x01)==1)||((cr30flag&0x02)==0)){
+ SetReg1(P3d4,0x34,ModeNo);
+ //SetSeqRegs(ROMAddr);
+ {
+ UCHAR SRdata;
+ SRdata = SRegs[0x01] | 0x20;
+ SetReg1(P3c4, 0x01, SRdata);
+
+ for (i = 02; i <= 04; i++)
+ SetReg1(P3c4, i, SRegs[i]);
+ }
+
+ //SetMiscRegs(ROMAddr);
+ {
+ SetReg3(P3c2, 0x23);
+ }
+
+ //SetCRTCRegs(ROMAddr);
+ {
+ UCHAR CRTCdata;
+
+ CRTCdata = (UCHAR) GetReg1(P3d4, 0x11);
+ SetReg1(P3d4, 0x11, CRTCdata);
+
+ for (i = 0; i <= 0x18; i++)
+ SetReg1(P3d4, i, CRegs[i]);
+ }
+
+ //SetATTRegs(ROMAddr);
+ {
+ for (i = 0; i <= 0x13; i++) {
+ GetReg2(P3da);
+ SetReg3(P3c0, i);
+ SetReg3(P3c0, ARegs[i]);
+ }
+ GetReg2(P3da);
+ SetReg3(P3c0, 0x14);
+ SetReg3(P3c0, 0x00);
+ GetReg2(P3da);
+ SetReg3(P3c0, 0x20);
+ }
+
+ //SetGRCRegs(ROMAddr);
+ {
+ for (i = 0; i <= 0x08; i++)
+ SetReg1(P3ce, i, GRegs[i]);
+ }
+
+ //ClearExt1Regs();
+ {
+ for (i = 0x0A; i <= 0x0E; i++)
+ SetReg1(P3c4, i, 0x00);
+ }
+
+
+ //SetSync(ROMAddr);
+ {
+ SetReg3(P3c2, MReg);
+ }
+
+ //SetCRT1CRTC(ROMAddr);
+ {
+ UCHAR data;
+
+ data = (UCHAR) GetReg1(P3d4, 0x11);
+ data = data & 0x7F;
+ SetReg1(P3d4, 0x11, data);
+
+ for (i = 0; i <= 0x07; i++)
+ SetReg1(P3d4, i, CRegs[i]);
+ for (i = 0x10; i <= 0x12; i++)
+ SetReg1(P3d4, i, CRegs[i]);
+ for (i = 0x15; i <= 0x16; i++)
+ SetReg1(P3d4, i, CRegs[i]);
+ for (i = 0x0A; i <= 0x0C; i++)
+ SetReg1(P3c4, i, SRegs[i]);
+
+ data = SRegs[0x0E] & 0xE0;
+ SetReg1(P3c4, 0x0E, data);
+
+ SetReg1(P3d4, 0x09, CRegs[0x09]);
+ }
+
+ //SetCRT1Offset(ROMAddr);
+ {
+ SetReg1(P3c4, 0x0E, SRegs[0x0E]);
+ SetReg1(P3c4, 0x10, SRegs[0x10]);
+ }
+
+ //SetCRT1VCLK(HwDeviceExtension, ROMAddr);
+ {
+ SetReg1(P3c4, 0x31, 0);
+
+ for (i = 0x2B; i <= 0x2C; i++)
+ SetReg1(P3c4, i, SRegs[i]);
+ SetReg1(P3c4, 0x2D, 0x80);
+ }
+
+ //SetVCLKState(HwDeviceExtension, ROMAddr, ModeNo);
+ {
+ SetReg1(P3c4, 0x32, SRegs[0x32]);
+ SetReg1(P3c4, 0x07, SRegs[0x07]);
+ }
+
+ //SetCRT1FIFO2(ROMAddr);
+ {
+ SetReg1(P3c4, 0x15, SRegs[0x15]);
+
+ SetReg4(0xcf8, 0x80000050);
+ SetReg4(0xcfc, 0xc5041e04);
+
+ SetReg1(P3c4, 0x08, SRegs[0x08]);
+ SetReg1(P3c4, 0x0F, SRegs[0x0F]);
+ SetReg1(P3c4, 0x3b, 0x00);
+ SetReg1(P3c4, 0x09, SRegs[0x09]);
+ }
+
+ //SetCRT1ModeRegs(ROMAddr, ModeNo);
+ {
+ SetReg1(P3c4, 0x06, SRegs[0x06]);
+ SetReg1(P3c4, 0x01, SRegs[0x01]);
+ SetReg1(P3c4, 0x0F, SRegs[0x0F]);
+ SetReg1(P3c4, 0x21, SRegs[0x21]);
+ }
+
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ {
+ //SetInterlace(ROMAddr,ModeNo);
+ SetReg1(P3d4, 0x19, CRegs[0x19]);
+ SetReg1(P3d4, 0x1A, CRegs[0x1A]);
+ }
+
+ LoadDAC(ROMAddr);
+
+ ClearBuffer(HwDeviceExtension);
+ }
+
+ cr31flag=(UCHAR)GetReg1(P3d4,0x31);
+ DisplayOn(); // 16.DisplayOn
+ return(NO_ERROR);
+}
+
+VOID LoadDAC(ULONG ROMAddr)
+{
+ USHORT data,data2;
+ USHORT time,i,j,k;
+ USHORT m,n,o;
+ USHORT si,di,bx,dl;
+ USHORT al,ah,dh;
+ USHORT *table=VGA_DAC;
+
+ time=256;
+ table=VGA_DAC;
+ j=16;
+
+ SetReg3(P3c6,0xFF);
+ SetReg3(P3c8,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=data2+0x15;
+ SetReg3(P3c9,data2);
+ data=data>>2;
+ }
+ }
+
+ if(time==256) {
+ for(i=16;i<32;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) SetReg3(P3c9,data);
+ }
+ si=32;
+ for(m=0;m<9;m++) {
+ di=si;
+ bx=si+0x04;
+ dl=0;
+ for(n=0;n<3;n++) {
+ for(o=0;o<5;o++) {
+ dh=table[si];
+ ah=table[di];
+ al=table[bx];
+ si++;
+ WriteDAC(dl,ah,al,dh);
+ }
+ si=si-2;
+ for(o=0;o<3;o++) {
+ dh=table[bx];
+ ah=table[di];
+ al=table[si];
+ si--;
+ WriteDAC(dl,ah,al,dh);
+ }
+ dl++;
+ }
+ si=si+5;
+ }
+ }
+}
+
+VOID WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh)
+{
+ USHORT temp;
+ USHORT bh,bl;
+
+ bh=ah;
+ bl=al;
+ if(dl!=0) {
+ temp=bh;
+ bh=dh;
+ dh=temp;
+ if(dl==1) {
+ temp=bl;
+ bl=dh;
+ dh=temp;
+ }
+ else {
+ temp=bl;
+ bl=bh;
+ bh=temp;
+ }
+ }
+ SetReg3(P3c9,(USHORT)dh);
+ SetReg3(P3c9,(USHORT)bh);
+ SetReg3(P3c9,(USHORT)bl);
+}
+
+
+VOID DisplayOn()
+{
+ USHORT data;
+
+ data=GetReg1(P3c4,0x01);
+ data=data&0xDF;
+ SetReg1(P3c4,0x01,data);
+}
+
+
+#else
+BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo)
+{
+ ULONG temp;
+ USHORT cr30flag,cr31flag;
+ ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase;
+ USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress;
+
+ P3c4=BaseAddr+0x14;
+ P3d4=BaseAddr+0x24;
+ P3c0=BaseAddr+0x10;
+ P3ce=BaseAddr+0x1e;
+ P3c2=BaseAddr+0x12;
+ P3ca=BaseAddr+0x1a;
+ P3c6=BaseAddr+0x16;
+ P3c7=BaseAddr+0x17;
+ P3c8=BaseAddr+0x18;
+ P3c9=BaseAddr+0x19;
+ P3da=BaseAddr+0x2A;
+ if(ModeNo&0x80){
+ ModeNo=ModeNo&0x7F;
+ flag_clearbuffer=0;
+ }else{
+ flag_clearbuffer=1;
+ }
+
+ PresetScratchregister(P3d4,HwDeviceExtension); //add for CRT2
+
+ SetReg1(P3c4,0x05,0x86); // 1.Openkey
+ temp=SearchModeID(ROMAddr,ModeNo); // 2.Get ModeID Table
+ if(temp==0) return(0);
+
+ SetTVSystem(HwDeviceExtension,ROMAddr); //add for CRT2
+ GetLCDDDCInfo(HwDeviceExtension); //add for CRT2
+ GetVBInfo(BaseAddr,ROMAddr); //add for CRT2
+ GetLCDResInfo(ROMAddr,P3d4); //add for CRT2
+
+ temp=CheckMemorySize(ROMAddr); // 3.Check memory size
+ if(temp==0) return(0);
+ cr30flag=(UCHAR)GetReg1(P3d4,0x30);
+ if(((cr30flag&0x01)==1)||((cr30flag&0x02)==0)){
+ // if cr30 d[0]=1 or d[1]=0 set crt1
+ SetReg1(P3d4,0x34,ModeNo);
+ // set CR34->CRT1 ModeNofor CRT2 FIFO
+ GetModePtr(ROMAddr,ModeNo); // 4.GetModePtr
+ SetSeqRegs(ROMAddr); // 5.SetSeqRegs
+ SetMiscRegs(ROMAddr); // 6.SetMiscRegs
+ SetCRTCRegs(ROMAddr); // 7.SetCRTCRegs
+ SetATTRegs(ROMAddr); // 8.SetATTRegs
+ SetGRCRegs(ROMAddr); // 9.SetGRCRegs
+ ClearExt1Regs(); // 10.Clear Ext1Regs
+ temp=GetRatePtr(ROMAddr,ModeNo); // 11.GetRatePtr
+ if(temp) {
+ SetSync(ROMAddr); // 12.SetSync
+ SetCRT1CRTC(ROMAddr); // 13.SetCRT1CRTC
+ SetCRT1Offset(ROMAddr); // 14.SetCRT1Offset
+ SetCRT1VCLK(HwDeviceExtension, ROMAddr); // 15.SetCRT1VCLK
+ SetVCLKState(HwDeviceExtension, ROMAddr, ModeNo);
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ SetCRT1FIFO2(ROMAddr);
+ else
+ SetCRT1FIFO(ROMAddr);
+ }
+ SetCRT1ModeRegs(ROMAddr, ModeNo);
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ SetInterlace(ROMAddr,ModeNo);
+ LoadDAC(ROMAddr);
+ if(flag_clearbuffer) ClearBuffer(HwDeviceExtension);
+ }
+
+ cr31flag=(UCHAR)GetReg1(P3d4,0x31);
+ if(((cr30flag&0x01)==1)||((cr30flag&0x03)==0x02)
+ ||(((cr30flag&0x03)==0x00)&&((cr31flag&0x20)==0x20))){
+ //if CR30 d[0]=1 or d[1:0]=10, set CRT2 or cr30 cr31== 0x00 0x20
+ SetCRT2Group(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); //CRT2
+ }
+ DisplayOn(); // 16.DisplayOn
+ return(NO_ERROR);
+}
+
+BOOLEAN SearchModeID(ULONG ROMAddr, USHORT ModeNo)
+{
+ UCHAR ModeID;
+ USHORT usIDLength;
+
+ ModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable
+ ModeID=*((UCHAR *)(ROMAddr+ModeIDOffset)); // Offset 0x20A
+ usIDLength = GetModeIDLength(ROMAddr, ModeNo);
+ while(ModeID!=0xff && ModeID!=ModeNo) {
+ ModeIDOffset=ModeIDOffset+usIDLength;
+ ModeID=*((UCHAR *)(ROMAddr+ModeIDOffset));
+ }
+ if(ModeID==0xff) return(FALSE);
+ else return(TRUE);
+}
+
+BOOLEAN CheckMemorySize(ULONG ROMAddr)
+{
+ USHORT memorysize;
+ USHORT modeflag;
+ USHORT temp;
+
+ modeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ ModeType=modeflag&ModeInfoFlag; // Get mode type
+
+ memorysize=modeflag&MemoryInfoFlag;
+ memorysize=memorysize>MemorySizeShift;
+ memorysize++; // Get memory size
+
+ temp=GetReg1(P3c4,0x14); // Get DRAM Size
+ temp=temp&0x3F;
+ temp++;
+
+ if(temp<memorysize) return(FALSE);
+ else return(TRUE);
+}
+
+VOID GetModePtr(ULONG ROMAddr, USHORT ModeNo)
+{
+ UCHAR index;
+
+ StandTable=*((USHORT *)(ROMAddr+0x202)); // Get First 0x202
+ // StandTable Offset
+ if(ModeNo<=13) {
+ index=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+St_ModeFlag
+ }
+ else {
+ if(ModeType <= 0x02) index=0x1B; // 02 -> ModeEGA
+ else index=0x0F;
+ }
+
+ StandTable=StandTable+64*index; // Get ModeNo StandTable
+
+}
+
+VOID SetSeqRegs(ULONG ROMAddr)
+{
+ UCHAR SRdata;
+ USHORT i;
+
+ SetReg1(P3c4,0x00,0x03); // Set SR0
+ StandTable=StandTable+0x05;
+ SRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get SR01 from file
+ if(IF_DEF_LVDS==1){
+ if(VBInfo&SetCRT2ToLCD){
+ if(VBInfo&SetInSlaveMode){
+ if(LCDInfo&LCDNonExpanding){
+ SRdata=SRdata|0x01;
+ }
+ }
+ }
+ }
+
+ SRdata=SRdata|0x20;
+ SetReg1(P3c4,0x01,SRdata); // Set SR1
+ for(i=02;i<=04;i++) {
+ StandTable++;
+ SRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get SR2,3,4 from file
+ SetReg1(P3c4,i,SRdata); // Set SR2 3 4
+ }
+}
+
+VOID SetMiscRegs(ULONG ROMAddr)
+{
+ UCHAR Miscdata;
+
+ StandTable++;
+ Miscdata=*((UCHAR *)(ROMAddr+StandTable)); // Get Misc from file
+ SetReg3(P3c2,Miscdata); // Set Misc(3c2)
+}
+
+VOID SetCRTCRegs(ULONG ROMAddr)
+{
+ UCHAR CRTCdata;
+ USHORT i;
+
+ CRTCdata=(UCHAR)GetReg1(P3d4,0x11);
+ CRTCdata=CRTCdata&0x7f;
+ SetReg1(P3d4,0x11,CRTCdata); // Unlock CRTC
+
+ for(i=0;i<=0x18;i++) {
+ StandTable++;
+ CRTCdata=*((UCHAR *)(ROMAddr+StandTable)); // Get CRTC from file
+ SetReg1(P3d4,i,CRTCdata); // Set CRTC(3d4)
+ }
+}
+
+VOID SetATTRegs(ULONG ROMAddr)
+{
+ UCHAR ARdata;
+ USHORT i;
+
+ for(i=0;i<=0x13;i++) {
+ StandTable++;
+ ARdata=*((UCHAR *)(ROMAddr+StandTable)); // Get AR for file
+ if(IF_DEF_LVDS==1){ //for LVDS
+ if(VBInfo&SetCRT2ToLCD){
+ if(VBInfo&SetInSlaveMode){
+ if(LCDInfo&LCDNonExpanding){
+ if(i==0x13){
+ ARdata=0;
+ }
+ }
+ }
+ }
+ }
+ GetReg2(P3da); // reset 3da
+ SetReg3(P3c0,i); // set index
+ SetReg3(P3c0,ARdata); // set data
+ }
+ if(IF_DEF_LVDS==1){ //for LVDS
+ if(VBInfo&SetCRT2ToLCD){
+ if(VBInfo&SetInSlaveMode){
+ if(LCDInfo&LCDNonExpanding){
+
+ }
+ }
+ }
+ }
+ GetReg2(P3da); // reset 3da
+ SetReg3(P3c0,0x14); // set index
+ SetReg3(P3c0,0x00); // set data
+
+ GetReg2(P3da); // Enable Attribute
+ SetReg3(P3c0,0x20);
+}
+
+VOID SetGRCRegs(ULONG ROMAddr)
+{
+ UCHAR GRdata;
+ USHORT i;
+
+ for(i=0;i<=0x08;i++) {
+ StandTable++;
+ GRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get GR from file
+ SetReg1(P3ce,i,GRdata); // Set GR(3ce)
+ }
+ if(ModeType>ModeVGA){
+ GRdata=(UCHAR)GetReg1(P3ce,0x05);
+ GRdata=GRdata&0xBF;
+ SetReg1(P3ce,0x05,GRdata);
+ }
+}
+
+VOID ClearExt1Regs()
+{
+ USHORT i;
+
+ for(i=0x0A;i<=0x0E;i++) SetReg1(P3c4,i,0x00); // Clear SR0A-SR0E
+}
+
+
+BOOLEAN GetRatePtr(ULONG ROMAddr, USHORT ModeNo)
+{
+ SHORT index;
+ USHORT temp;
+ USHORT ulRefIndexLength;
+
+ if(ModeNo<0x14) return(FALSE); // Mode No <= 13h then return
+
+ index=GetReg1(P3d4,0x33); // Get 3d4 CRTC33
+ index=index&0x0F; // Frame rate index
+ if(index!=0) index--;
+ REFIndex=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point
+
+ ulRefIndexLength = GetRefindexLength(ROMAddr, ModeNo);
+ do {
+ temp=*((USHORT *)(ROMAddr+REFIndex)); // di => REFIndex
+ if(temp==0xFFFF) break;
+ temp=temp&ModeInfoFlag;
+ if(temp<ModeType) break;
+
+ REFIndex=REFIndex+ulRefIndexLength; // rate size
+ index--;
+ } while(index>=0);
+
+ REFIndex=REFIndex-ulRefIndexLength; // rate size
+ return(TRUE);
+}
+
+VOID SetSync(ULONG ROMAddr)
+{
+ USHORT sync;
+ USHORT temp;
+
+ sync=*((USHORT *)(ROMAddr+REFIndex)); // di+0x00
+ sync=sync&0xC0;
+ temp=0x2F;
+ temp=temp|sync;
+ SetReg3(P3c2,temp); // Set Misc(3c2)
+}
+
+VOID SetCRT1CRTC(ULONG ROMAddr)
+{
+ UCHAR index;
+ UCHAR data;
+ USHORT i;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x02)); // Get index
+ index=index&0x03F;
+ CRT1Table=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table
+ CRT1Table=CRT1Table+index*CRT1Len;
+
+ data=(UCHAR)GetReg1(P3d4,0x11);
+ data=data&0x7F;
+ SetReg1(P3d4,0x11,data); // Unlock CRTC
+
+ CRT1Table--;
+ for(i=0;i<=0x05;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3d4,i,data);
+ }
+ for(i=0x06;i<=0x07;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3d4,i,data);
+ }
+ for(i=0x10;i<=0x12;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3d4,i,data);
+ }
+ for(i=0x15;i<=0x16;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3d4,i,data);
+ }
+ for(i=0x0A;i<=0x0C;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3c4,i,data);
+ }
+
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ data=data&0xE0;
+ SetReg1(P3c4,0x0E,data);
+
+ data=(UCHAR)GetReg1(P3d4,0x09);
+ data=data&0xDF;
+ i=*((UCHAR *)(ROMAddr+CRT1Table));
+ i=i&0x01;
+ i=i<<5;
+ data=data|i;
+ i=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ i=i&DoubleScanMode;
+ if(i) data=data|0x80;
+ SetReg1(P3d4,0x09,data);
+
+ if(ModeType>0x03) SetReg1(P3d4,0x14,0x4F);
+}
+
+VOID SetCRT1Offset(ULONG ROMAddr)
+{
+ USHORT temp,ah,al;
+ USHORT temp2,i;
+ USHORT DisplayUnit;
+
+ temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+Ext_ModeInfo
+ temp=temp>>4; // index
+ ScreenOffset=*((USHORT *)(ROMAddr+0x206)); // ScreenOffset
+ temp=*((UCHAR *)(ROMAddr+ScreenOffset+temp)); // data
+
+ temp2=*((USHORT *)(ROMAddr+REFIndex+0x00));
+ temp2=temp2&InterlaceMode;
+ if(temp2) temp=temp<<1;
+ temp2=ModeType-ModeEGA;
+ switch (temp2) {
+ case 0 : temp2=1; break;
+ case 1 : temp2=2; break;
+ case 2 : temp2=4; break;
+ case 3 : temp2=4; break;
+ case 4 : temp2=6; break;
+ case 5 : temp2=8; break;
+ }
+ temp=temp*temp2;
+ DisplayUnit=temp;
+
+ temp2=temp;
+ temp=temp>>8;
+ temp=temp&0x0F;
+ i=GetReg1(P3c4,0x0E);
+ i=i&0xF0;
+ i=i|temp;
+ SetReg1(P3c4,0x0E,i);
+
+ temp=(UCHAR)temp2;
+ temp=temp&0xFF;
+ SetReg1(P3d4,0x13,temp);
+
+ temp2=*((USHORT *)(ROMAddr+REFIndex+0x00));
+ temp2=temp2&InterlaceMode;
+ if(temp2) DisplayUnit>>=1;
+
+ DisplayUnit=DisplayUnit<<5;
+ ah=(DisplayUnit&0xff00)>>8;
+ al=DisplayUnit&0x00ff;
+ if(al==0) ah=ah+1;
+ else ah=ah+2;
+ SetReg1(P3c4,0x10,ah);
+}
+
+
+VOID SetCRT1VCLK(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr)
+{
+ USHORT i;
+ UCHAR index,data;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x03));
+ index=index&0x03F;
+ CRT1VCLKLen=GetVCLKLen(ROMAddr);
+ data=index*CRT1VCLKLen;
+ VCLKData=*((USHORT *)(ROMAddr+0x208));
+ VCLKData=VCLKData+data;
+
+ SetReg1(P3c4,0x31,0);
+ for(i=0x2B;i<=0x2C;i++) {
+ data=*((UCHAR *)(ROMAddr+VCLKData));
+ SetReg1(P3c4,i,data);
+ VCLKData++;
+ }
+ SetReg1(P3c4,0x2D,0x80);
+}
+
+
+VOID SetCRT1ModeRegs(ULONG ROMAddr, USHORT ModeNo)
+{
+
+ USHORT data,data2,data3;
+
+ if(ModeNo>0x13) data=*((USHORT *)(ROMAddr+REFIndex+0x00));
+ else data=0;
+
+ data2=0;
+ if(ModeNo>0x13)
+ if(ModeType>0x02) {
+ data2=data2|0x02;
+ data3=ModeType-ModeVGA;
+ data3=data3<<2;
+ data2=data2|data3;
+ }
+
+ data=data&InterlaceMode;
+ if(data) data2=data2|0x20;
+ SetReg1(P3c4,0x06,data2);
+
+ data=GetReg1(P3c4,0x01);
+ data=data&0xF7;
+ data2=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ data2=data2&HalfDCLK;
+ if(data2) data=data|0x08;
+ SetReg1(P3c4,0x01,data);
+
+ data=GetReg1(P3c4,0x0F);
+ data=data&0xF7;
+ data2=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ data2=data2&LineCompareOff;
+ if(data2) data=data|0x08;
+ SetReg1(P3c4,0x0F,data);
+
+ data=GetReg1(P3c4,0x21);
+ data=data&0x1F;
+ if(ModeType==0x00) data=data|0x60; // Text Mode
+ else if(ModeType<=0x02) data=data|0x00; // EGA Mode
+ else data=data|0xA0; // VGA Mode
+ SetReg1(P3c4,0x21,data);
+}
+
+VOID SetVCLKState(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr, USHORT ModeNo)
+{
+ USHORT data,data2;
+ USHORT VCLK;
+ UCHAR index;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x03));
+ index=index&0x03F;
+ CRT1VCLKLen=GetVCLKLen(ROMAddr);
+ data=index*CRT1VCLKLen;
+ VCLKData=*((USHORT *)(ROMAddr+0x208));
+ VCLKData=VCLKData+data+(CRT1VCLKLen-2);
+ VCLK=*((USHORT *)(ROMAddr+VCLKData));
+ if(ModeNo<=0x13) VCLK=0;
+
+ data=GetReg1(P3c4,0x07);
+ data=data&0x7B;
+ if(VCLK>=150) data=data|0x80; // VCLK > 150
+ SetReg1(P3c4,0x07,data);
+
+ data=GetReg1(P3c4,0x32);
+ data=data&0xD7;
+ if(VCLK>=150) data=data|0x08; // VCLK > 150
+ SetReg1(P3c4,0x32,data);
+
+ data2=0x03;
+ if(VCLK>135) data2=0x02;
+ if(VCLK>160) data2=0x01;
+ if(VCLK>260) data2=0x00;
+ data=GetReg1(P3c4,0x07);
+ data=data&0xFC;
+ data=data|data2;
+ SetReg1(P3c4,0x07,data);
+}
+
+VOID LoadDAC(ULONG ROMAddr)
+{
+ USHORT data,data2;
+ USHORT time,i,j,k;
+ USHORT m,n,o;
+ USHORT si,di,bx,dl;
+ USHORT al,ah,dh;
+ USHORT *table=VGA_DAC;
+
+ data=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ data=data&DACInfoFlag;
+ time=64;
+ if(data==0x00) table=MDA_DAC;
+ if(data==0x08) table=CGA_DAC;
+ if(data==0x10) table=EGA_DAC;
+ if(data==0x18) {
+ time=256;
+ table=VGA_DAC;
+ }
+ if(time==256) j=16;
+ else j=time;
+
+ SetReg3(P3c6,0xFF);
+ SetReg3(P3c8,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=data2+0x15;
+ SetReg3(P3c9,data2);
+ data=data>>2;
+ }
+ }
+
+ if(time==256) {
+ for(i=16;i<32;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) SetReg3(P3c9,data);
+ }
+ si=32;
+ for(m=0;m<9;m++) {
+ di=si;
+ bx=si+0x04;
+ dl=0;
+ for(n=0;n<3;n++) {
+ for(o=0;o<5;o++) {
+ dh=table[si];
+ ah=table[di];
+ al=table[bx];
+ si++;
+ WriteDAC(dl,ah,al,dh);
+ }
+ si=si-2;
+ for(o=0;o<3;o++) {
+ dh=table[bx];
+ ah=table[di];
+ al=table[si];
+ si--;
+ WriteDAC(dl,ah,al,dh);
+ }
+ dl++;
+ }
+ si=si+5;
+ }
+ }
+}
+
+VOID WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh)
+{
+ USHORT temp;
+ USHORT bh,bl;
+
+ bh=ah;
+ bl=al;
+ if(dl!=0) {
+ temp=bh;
+ bh=dh;
+ dh=temp;
+ if(dl==1) {
+ temp=bl;
+ bl=dh;
+ dh=temp;
+ }
+ else {
+ temp=bl;
+ bl=bh;
+ bh=temp;
+ }
+ }
+ SetReg3(P3c9,(USHORT)dh);
+ SetReg3(P3c9,(USHORT)bh);
+ SetReg3(P3c9,(USHORT)bl);
+}
+
+
+VOID DisplayOn()
+{
+ USHORT data;
+
+ data=GetReg1(P3c4,0x01);
+ data=data&0xDF;
+ SetReg1(P3c4,0x01,data);
+}
+
+USHORT GetModeIDLength(ULONG ROMAddr, USHORT ModeNo)
+{
+ USHORT modeidlength;
+ USHORT usModeIDOffset;
+ USHORT PreviousWord,CurrentWord;
+
+ modeidlength=0;
+ usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable
+ // maybe = 2Exx or xx2E
+ CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset)); // Offset 0x20A
+ PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2)); // Offset 0x20A
+ while((CurrentWord!=0x2E07)||(PreviousWord!=0x0801)) {
+ modeidlength++;
+ usModeIDOffset=usModeIDOffset+1; // 10 <= ExtStructSize
+ CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset));
+ PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2));
+ }
+ modeidlength++;
+ return(modeidlength);
+}
+
+USHORT GetRefindexLength(ULONG ROMAddr, USHORT ModeNo)
+{
+ UCHAR ModeID;
+ UCHAR temp;
+ USHORT refindexlength;
+ USHORT usModeIDOffset;
+ USHORT usREFIndex;
+ USHORT usIDLength;
+
+ usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable
+ ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); // Offset 0x20A
+ usIDLength = GetModeIDLength(ROMAddr, ModeNo);
+ while(ModeID!=0x40) {
+ usModeIDOffset=usModeIDOffset+usIDLength; // 10 <= ExtStructSize
+ ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset));
+ }
+
+ refindexlength=1;
+ usREFIndex=*((USHORT *)(ROMAddr+usModeIDOffset+0x04)); // si+Ext_point
+ usREFIndex++;
+ temp=*((UCHAR *)(ROMAddr+usREFIndex)); // di => REFIndex
+ while(temp!=0xFF) {
+ refindexlength++;
+ usREFIndex++;
+ temp=*((UCHAR *)(ROMAddr+usREFIndex)); // di => REFIndex
+ }
+ return(refindexlength);
+}
+
+VOID SetInterlace(ULONG ROMAddr, USHORT ModeNo)
+{
+ ULONG Temp;
+ USHORT data,Temp2;
+
+ Temp = (ULONG)GetReg1(P3d4, 0x01);
+ Temp++;
+ Temp=Temp*8;
+
+ if(Temp==1024) data=0x0035;
+ else if(Temp==1280) data=0x0048;
+ else data=0x0000;
+
+ Temp2=*((USHORT *)(ROMAddr+REFIndex+0x00));
+ Temp2 &= InterlaceMode;
+ if(Temp2 == 0) data=0x0000;
+
+ SetReg1(P3d4,0x19,data);
+
+ Temp = (ULONG)GetReg1(P3d4, 0x1A);
+ Temp2= (USHORT)(Temp & 0xFC);
+ SetReg1(P3d4,0x1A,(USHORT)Temp);
+
+ Temp = (ULONG)GetReg1(P3c4, 0x0f);
+ Temp2= (USHORT)Temp & 0xBF;
+ if(ModeNo==0x37) Temp2=Temp2|0x40;
+ SetReg1(P3d4,0x1A,(USHORT)Temp2);
+}
+
+VOID SetCRT1FIFO(ULONG ROMAddr)
+{
+ USHORT colorth=0,index,data,VCLK,data2,MCLKOffset,MCLK;
+ USHORT ah,bl,A,B;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x03));
+ index=index&0x03F;
+ CRT1VCLKLen=GetVCLKLen(ROMAddr);
+ data=index*CRT1VCLKLen;
+ VCLKData=*((USHORT *)(ROMAddr+0x208));
+ VCLKData=VCLKData+data+(CRT1VCLKLen-2);
+ VCLK=*((USHORT *)(ROMAddr+VCLKData)); // Get VCLK
+
+ MCLKOffset=*((USHORT *)(ROMAddr+0x20C));
+ index=GetReg1(P3c4,0x3A);
+ index=index&07;
+ MCLKOffset=MCLKOffset+index*5;
+ MCLK=*((UCHAR *)(ROMAddr+MCLKOffset+0x03)); // Get MCLK
+
+ data2=ModeType-0x02;
+ switch (data2) {
+ case 0 : colorth=1; break;
+ case 1 : colorth=2; break;
+ case 2 : colorth=4; break;
+ case 3 : colorth=4; break;
+ case 4 : colorth=6; break;
+ case 5 : colorth=8; break;
+ }
+
+ do{
+ B=(CalcDelay(ROMAddr,0)*VCLK*colorth);
+ B=B/(16*MCLK);
+ B++;
+
+ A=(CalcDelay(ROMAddr,1)*VCLK*colorth);
+ A=A/(16*MCLK);
+ A++;
+
+ if(A<4) A=0;
+ else A=A-4;
+
+ if(A>B) bl=A;
+ else bl=B;
+
+ bl++;
+ if(bl>0x13) {
+ data=GetReg1(P3c4,0x16);
+ data=data>>6;
+ if(data!=0) {
+ data--;
+ data=data<<6;
+ data2=GetReg1(P3c4,0x16);
+ data2=(data2&0x3f)|data;
+ SetReg1(P3c4,0x16,data2);
+ }
+ else bl=0x13;
+ }
+ } while(bl>0x13);
+
+ ah=bl;
+ ah=ah<<4;
+ ah=ah|0x0f;
+ SetReg1(P3c4,0x08,ah);
+
+ data=bl;
+ data=data&0x10;
+ data=data<<1;
+ data2=GetReg1(P3c4,0x0F);
+ data2=data2&0x9f;
+ data2=data2|data;
+ SetReg1(P3c4,0x0F,data2);
+
+ data=bl+3;
+ if(data>0x0f) data=0x0f;
+ SetReg1(P3c4,0x3b,0x00);
+ data2=GetReg1(P3c4,0x09);
+ data2=data2&0xF0;
+ data2=data2|data;
+ SetReg1(P3c4,0x09,data2);
+}
+
+static USHORT CalcDelay(ULONG ROMAddr,USHORT key)
+{
+ USHORT data,data2,temp0,temp1;
+ UCHAR ThLowA[]={61,3,52,5,68,7,100,11,
+ 43,3,42,5,54,7, 78,11,
+ 34,3,37,5,47,7, 67,11};
+ UCHAR ThLowB[]={81,4,72,6,88,8,120,12,
+ 55,4,54,6,66,8, 90,12,
+ 42,4,45,6,55,8, 75,12};
+ UCHAR ThTiming[]= {1,2,2,3,0,1,1,2};
+
+ data=GetReg1(P3c4,0x16);
+ data=data>>6;
+ data2=GetReg1(P3c4,0x14);
+ data2=(data2>>4)&0x0C;
+ data=data|data2;
+ data=data<1;
+ if(key==0) {
+ temp0=(USHORT)ThLowA[data];
+ temp1=(USHORT)ThLowA[data+1];
+ }
+ else {
+ temp0=(USHORT)ThLowB[data];
+ temp1=(USHORT)ThLowB[data+1];
+ }
+
+ data2=0;
+ data=GetReg1(P3c4,0x18);
+ if(data&0x02) data2=data2|0x01;
+ if(data&0x20) data2=data2|0x02;
+ if(data&0x40) data2=data2|0x04;
+
+ data=temp1*ThTiming[data2]+temp0;
+ return(data);
+}
+
+VOID SetCRT1FIFO2(ULONG ROMAddr)
+{
+ USHORT colorth=0,index,data,VCLK,data2,MCLKOffset,MCLK;
+ USHORT ah,bl,B;
+ ULONG eax;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x03));
+ index=index&0x03F;
+ CRT1VCLKLen=GetVCLKLen(ROMAddr);
+ data=index*CRT1VCLKLen;
+ VCLKData=*((USHORT *)(ROMAddr+0x208));
+ VCLKData=VCLKData+data+(CRT1VCLKLen-2);
+ VCLK=*((USHORT *)(ROMAddr+VCLKData)); // Get VCLK
+
+ MCLKOffset=*((USHORT *)(ROMAddr+0x20C));
+ index=GetReg1(P3c4,0x1A);
+ index=index&07;
+ MCLKOffset=MCLKOffset+index*5;
+ MCLK=*((USHORT *)(ROMAddr+MCLKOffset+0x03)); // Get MCLK
+
+ data2=ModeType-0x02;
+ switch (data2) {
+ case 0 : colorth=1; break;
+ case 1 : colorth=1; break;
+ case 2 : colorth=2; break;
+ case 3 : colorth=2; break;
+ case 4 : colorth=3; break;
+ case 5 : colorth=4; break;
+ }
+
+ do{
+ B=(CalcDelay2(ROMAddr,0)*VCLK*colorth);
+ if (B%(16*MCLK) == 0)
+ {
+ B=B/(16*MCLK);
+ bl=B+1;
+ }
+ else
+ {
+ B=B/(16*MCLK);
+ bl=B+2;
+ }
+
+ if(bl>0x13) {
+ data=GetReg1(P3c4,0x15);
+ data=data&0xf0;
+ if(data!=0xb0) {
+ data=data+0x20;
+ if(data==0xa0) data=0x30;
+
+ data2=GetReg1(P3c4,0x15);
+ data2=(data2&0x0f)|data;
+ SetReg1(P3c4,0x15,data2);
+ }
+ else bl=0x13;
+ }
+ } while(bl>0x13);
+
+ data2=GetReg1(P3c4,0x15);
+ data2=(data2&0xf0)>>4;
+ data2=data2<<24;
+
+ SetReg4(0xcf8,0x80000050);
+ eax=GetReg3(0xcfc);
+ eax=eax&0x0f0ffffff;
+ eax=eax|data2;
+ SetReg4(0xcfc,eax);
+
+ ah=bl;
+ ah=ah<<4;
+ ah=ah|0x0f;
+ SetReg1(P3c4,0x08,ah);
+
+ data=bl;
+ data=data&0x10;
+ data=data<<1;
+ data2=GetReg1(P3c4,0x0F);
+ data2=data2&0x9f;
+ data2=data2|data;
+ SetReg1(P3c4,0x0F,data2);
+
+ data=bl+3;
+ if(data>0x0f) data=0x0f;
+ SetReg1(P3c4,0x3b,0x00);
+ data2=GetReg1(P3c4,0x09);
+ data2=data2&0xF0;
+ data2=data2|data;
+ SetReg1(P3c4,0x09,data2);
+}
+
+USHORT CalcDelay2(ULONG ROMAddr,USHORT key)
+{
+ USHORT data,index;
+ UCHAR LatencyFactor[]={88,80,78,72,70,00,
+ 00,79,77,71,69,49,
+ 88,80,78,72,70,00,
+ 00,72,70,64,62,44};
+
+ index=0;
+ data=GetReg1(P3c4,0x14);
+ if(data&0x80) index=index+12;
+
+ data=GetReg1(P3c4,0x15);
+ data=(data&0xf0)>>4;
+ if(data&0x01) index=index+6;
+
+ data=data>>1;
+ index=index+data;
+ data=LatencyFactor[index];
+
+ return(data);
+}
+
+#endif /* CONFIG_FB_SIS_LINUXBIOS */
\ No newline at end of file
--- /dev/null
+#include "initdef.h"
+
+USHORT DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48},
+ {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44},
+ {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40},
+ {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32},
+ {0x0B,0x08,0x02,0x08,0x21},{0x0C,0x08,0x01,0x08,0x30},
+ {0x0A,0x08,0x02,0x04,0x11},{0x0B,0x0A,0x01,0x10,0x28},
+ {0x09,0x08,0x02,0x02,0x01},{0x0B,0x09,0x01,0x08,0x24},
+ {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10},
+ {0x09,0x08,0x01,0x01,0x00}};
+
+USHORT 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};
+
+USHORT 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};
+
+USHORT 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};
+
+USHORT 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};
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+unsigned char SRegsInit[] = {
+ 0x03, 0x00, 0x03, 0x00, 0x02, 0xa1, 0x00, 0x13,
+ 0x2f, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xa1, 0x76, 0xb2, 0xf6, 0x0d, 0x00, 0x00, 0x00,
+ 0x37, 0x61, 0x80, 0x1b, 0xe1, 0x01, 0x55, 0x43,
+ 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff
+};
+
+unsigned char SRegs[] = {
+ 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13,
+ 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x0B, 0x0F, 0x00, 0x00, 0x4F, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00,
+ 0xA1, 0xB6, 0xB2, 0xF6, 0x0D, 0x00, 0xF8, 0xF0,
+ 0x37, 0x61, 0x80, 0x1B, 0xE1, 0x80, 0x55, 0x43,
+ 0x80, 0x00, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF,
+ 0x8E, 0x40, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xFF
+};
+
+unsigned char CRegs[] = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe9, 0x0b, 0xdf, 0x50, 0x40, 0xe7, 0x04, 0xa3,
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff
+}; // clear CR11[7]
+
+unsigned char GRegs[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, 0x00
+};
+
+unsigned char ARegs[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+unsigned char MReg = 0x6f;
+
+#endif
+
+USHORT P3c4,P3d4,P3c0,P3ce,P3c2,P3ca,P3c6,P3c7,P3c8,P3c9,P3da;
+USHORT CRT1VCLKLen; //VCLKData table length of bytes of each entry
+USHORT flag_clearbuffer; //0: no clear frame buffer 1:clear frame buffer
+int RAMType;
+int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,VCLKData,MCLKData, ECLKData;
+int REFIndex,ModeType;
+USHORT IF_DEF_LVDS,IF_DEF_TRUMPION;
+USHORT VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo;
+
+//int init300(int,int,int);
+VOID SetMemoryClock(ULONG);
+VOID SetDRAMSize(PHW_DEVICE_EXTENSION);
+//extern "C" int ChkBUSWidth(int);
+
+//int setmode(int,int,int,int);
+BOOLEAN SearchModeID(ULONG, USHORT);
+BOOLEAN CheckMemorySize(ULONG);
+VOID GetModePtr(ULONG, USHORT);
+BOOLEAN GetRatePtr(ULONG, USHORT);
+VOID SetSeqRegs(ULONG);
+VOID SetMiscRegs(ULONG);
+VOID SetCRTCRegs(ULONG);
+VOID SetATTRegs(ULONG);
+VOID SetGRCRegs(ULONG);
+VOID ClearExt1Regs(VOID);
+VOID SetSync(ULONG);
+VOID SetCRT1CRTC(ULONG);
+VOID SetCRT1Offset(ULONG);
+VOID SetCRT1FIFO(ULONG);
+VOID SetCRT1FIFO2(ULONG);
+VOID SetCRT1VCLK(PHW_DEVICE_EXTENSION, ULONG);
+VOID LoadDAC(ULONG);
+VOID DisplayOn(VOID);
+VOID SetCRT1ModeRegs(ULONG, USHORT);
+VOID SetVCLKState(PHW_DEVICE_EXTENSION, ULONG, USHORT);
+VOID WriteDAC(USHORT, USHORT, USHORT, USHORT);
+VOID ClearBuffer(PHW_DEVICE_EXTENSION);
+USHORT ChkBUSWidth(ULONG);
+USHORT GetModeIDLength(ULONG, USHORT);
+USHORT GetRefindexLength(ULONG, USHORT);
+VOID SetInterlace(ULONG, USHORT);
+USHORT CalcDelay2(ULONG ,USHORT);
+void Set_LVDS_TRUMPION(VOID);
+BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo);
+#ifndef CONFIG_FB_SIS_LINUXBIOS
+static USHORT CalcDelay(ULONG ,USHORT);
+#endif
+
+extern BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+extern VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr);
+extern VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension);
+extern BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4);
+extern VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr);
+extern BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension);
+extern BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr);
+extern BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension);
+extern USHORT GetVCLKLen(ULONG ROMAddr);
+extern void SetReg1(u16 port, u16 index, u16 data);
+extern void SetReg3(u16 port, u16 data);
+extern void SetReg4(u16 port, unsigned long data);
+extern u8 GetReg1(u16 port, u16 index);
+extern u8 GetReg2(u16 port);
+extern u32 GetReg3(u16 port);
+extern void ClearDAC(u16 port);
\ No newline at end of file
--- /dev/null
+/* Recently Update by v1.09.50 */
+
+#include "sis_301.h"
+
+#ifndef CONFIG_FB_SIS_LINUXBIOS
+
+BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT temp;
+
+ SetFlag=SetFlag|ProgrammingCRT2;
+ SearchModeID(ROMAddr,ModeNo);
+
+ temp=GetRatePtrCRT2(ROMAddr,ModeNo);
+ if(((temp&0x02)==0) && ((VBInfo&CRT2DisplayFlag)==0))
+ return(FALSE);
+ SaveCRT2Info(ModeNo);
+ DisableBridge(BaseAddr);
+ UnLockCRT2(BaseAddr);
+ SetDefCRT2ExtRegs(BaseAddr);
+ SetCRT2ModeRegs(BaseAddr,ModeNo);
+ if(VBInfo&CRT2DisplayFlag){
+ LockCRT2(BaseAddr);
+ return 0;
+ }
+ GetCRT2Data(ROMAddr,ModeNo);
+ if(IF_DEF_LVDS==1){ //LVDS
+ GetLVDSDesData(ROMAddr,ModeNo);
+ }
+ SetGroup1(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+ if(IF_DEF_LVDS==0){
+ SetGroup2(BaseAddr,ROMAddr);
+ SetGroup3(BaseAddr);
+ SetGroup4(BaseAddr,ROMAddr,ModeNo);
+ SetGroup5(BaseAddr,ROMAddr);
+ }else{ //LVDS
+ if(IF_DEF_TRUMPION==0){
+ ModCRT1CRTC(ROMAddr,ModeNo);
+ }
+ SetCRT2ECLK(ROMAddr,ModeNo);
+ }
+
+ EnableCRT2();
+ EnableBridge(BaseAddr);
+ SetLockRegs();
+ LockCRT2(BaseAddr);
+
+ return 1;
+}
+
+VOID overwriteregs(ULONG ROMAddr,USHORT BaseAddr)
+{
+ int i;
+ USHORT Part1Port; //reg data is for 1024x768 16bit 85hz
+ int p1reg[0x29]={0x84,0x76,0x4B,0x21,0x00,0x00,0x00,0x00,0x1F,0x51,
+ 0x0C,0x10,0x44,0x90,0x1E,0xFF,0x00,0x34,0x13,0x10,
+ 0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x97,0x16,
+ 0xA3};
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ for(i=0;i<29;i++){
+ SetReg1(Part1Port,(USHORT)i,(USHORT)p1reg[i]);
+ }
+}
+
+VOID SetDefCRT2ExtRegs(USHORT BaseAddr)
+{
+ USHORT Part1Port,Part2Port,Part4Port;
+ USHORT temp;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ SetReg1(Part1Port,0x02,0x40);
+ SetReg1(Part4Port,0x10,0x80);
+ temp=(UCHAR)GetReg1(P3c4,0x16);
+ temp=temp&0xC3;
+ SetReg1(P3d4,0x35,temp);
+}
+
+USHORT GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo)
+{ //return bit0=>0:standard mode 1:extended mode
+ SHORT index; // bit1=>0:crt2 no support this mode
+ USHORT temp; // 1:crt2 support this mode
+ USHORT ulRefIndexLength;
+ USHORT temp1;
+ SHORT LCDRefreshIndex[4]={0x0,0x0,0x03,0x01};
+ // LCDPanel:no lcd,800x600,1024x768,1280x1024
+ if(ModeNo<0x14) return(0); // Mode No <= 13h then return
+
+ index=GetReg1(P3d4,0x33); // Get 3d4 CRTC33
+ index=index>>SelectCRT2Rate; //For CRT2,cl=SelectCRT2Rate=4, shr ah,cl
+ index=index&0x0F; // Frame rate index
+ if(index!=0) index--;
+
+ if(IF_DEF_TRUMPION==1){
+ if(VBInfo&SetSimuScanMode){
+ index=0;
+ }
+ }
+ if(SetFlag&ProgrammingCRT2){
+ if(VBInfo&SetCRT2ToLCD){
+ if(IF_DEF_LVDS==0){
+ temp=LCDResInfo;
+ temp1=LCDRefreshIndex[temp];
+ if(index>temp1){
+ index=temp1;
+ }
+ }else{
+ index=0;
+ }
+ }
+ }
+
+ REFIndex=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point
+
+ ulRefIndexLength =Ext2StructSize;
+ do {
+ temp=*((USHORT *)(ROMAddr+REFIndex)); // di => REFIndex
+ if(temp==0xFFFF) break;
+ temp=temp&ModeInfoFlag;
+ if(temp<ModeType) break;
+
+ REFIndex=REFIndex+ulRefIndexLength; // rate size
+ index--;
+ if(index<0){
+ if(!(VBInfo&SetCRT2ToRAMDAC)){
+ if(VBInfo&SetInSlaveMode){
+ temp1=*((USHORT *)(ROMAddr+REFIndex+0-Ext2StructSize));
+ if(temp1&InterlaceMode){
+ index=0;
+ }
+ }
+ }
+ }
+ } while(index>=0);
+
+ REFIndex=REFIndex-ulRefIndexLength; // rate size
+
+ if((SetFlag&ProgrammingCRT2)){
+ temp1=AjustCRT2Rate(ROMAddr);
+ }else{
+ temp1=0;
+ }
+
+ return(0x01|(temp1<<1));
+}
+
+BOOLEAN AjustCRT2Rate(ULONG ROMAddr)
+{
+ USHORT tempbx=0,tempax,temp;
+ USHORT tempextinfoflag;
+ tempax=0;
+
+ if(IF_DEF_LVDS==0){
+ if(VBInfo&SetCRT2ToRAMDAC){
+ tempax=tempax|SupportRAMDAC2;
+ }
+ if(VBInfo&SetCRT2ToLCD){
+ tempax=tempax|SupportLCD;
+ if(LCDResInfo!=Panel1280x1024){
+ temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo
+ if(temp>=9){
+ tempax=0;
+ }
+ }
+ }
+ if(VBInfo&(SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)){
+ tempax=tempax|SupportTV;
+ if(!(VBInfo&SetPALTV)){
+ tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag
+ if(tempextinfoflag&NoSupportSimuTV){
+ if(VBInfo&SetInSlaveMode){
+ if(!(VBInfo&SetNotSimuTVMode)){
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ tempbx=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point
+ }else{ //for LVDS
+ if(VBInfo&SetCRT2ToLCD){
+ tempax=tempax|SupportLCD;
+ temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo
+ if(temp>0x08){ //1024x768
+ return 0;
+ }
+ if(LCDResInfo<Panel1024x768){
+ if(temp>0x07){ //800x600
+ return 0;
+ }
+ if(temp==0x04){ //512x384
+ return 0;
+ }
+ }
+ }
+ }
+
+ for(;REFIndex>tempbx;REFIndex-=Ext2StructSize){
+ tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag
+ if(tempextinfoflag&tempax){
+ return 1;
+ }
+ }
+ for(REFIndex=tempbx;;REFIndex+=Ext2StructSize){
+ tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag
+ if(tempextinfoflag==0x0FFFF){
+ return 0;
+ }
+ if(tempextinfoflag&tempax){
+ return 1;
+ }
+ }
+ return(FALSE);
+}
+
+VOID SaveCRT2Info(USHORT ModeNo){
+ USHORT temp1,temp2,temp3;
+ temp1=(VBInfo&SetInSlaveMode)>>8;
+ temp2=~(SetInSlaveMode>>8);
+ temp3=(UCHAR)GetReg1(P3d4,0x31);
+ temp3=((temp3&temp2)|temp1);
+ SetReg1(P3d4,0x31,(USHORT)temp3);
+ temp3=(UCHAR)GetReg1(P3d4,0x35);
+ temp3=temp3&0xF3;
+ SetReg1(P3d4,0x35,(USHORT)temp3);
+}
+
+VOID DisableLockRegs(){
+ UCHAR temp3;
+ temp3=(UCHAR)GetReg1(P3c4,0x32);
+ temp3=temp3&0xDF;
+ SetReg1(P3c4,0x32,(USHORT)temp3);
+}
+
+VOID DisableCRT2(){
+ UCHAR temp3;
+ temp3=(UCHAR)GetReg1(P3c4,0x1E);
+ temp3=temp3&0xDF;
+ SetReg1(P3c4,0x1E,(USHORT)temp3);
+}
+
+void DisableBridge(USHORT BaseAddr)
+{
+ USHORT Part2Port,Part1Port;
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+
+ if(IF_DEF_LVDS==0){
+ SetRegANDOR(Part2Port,0x00,0xDF,0x00); //Set Part2 Index0 D[5]=0
+ DisableLockRegs(); // SR 32
+ DisableCRT2(); // SR 1E
+ }else{
+ DisableLockRegs();
+ DisableCRT2();
+ if(IF_DEF_TRUMPION==0){
+ UnLockCRT2(BaseAddr);
+ SetRegANDOR(Part1Port,0x02,0xFF,0x40); //set Part1Port ,index 2, D6=1,
+ }
+ }
+}
+
+VOID GetCRT2Data(ULONG ROMAddr,USHORT ModeNo)
+{
+ if(IF_DEF_LVDS==0){ //301
+ GetCRT2Data301(ROMAddr,ModeNo);
+ return;
+ }else{ //LVDS
+ GetCRT2DataLVDS(ROMAddr,ModeNo);
+ return;
+ }
+}
+
+VOID GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempax,tempbx,OldREFIndex;
+
+ OldREFIndex=(USHORT)REFIndex; //push di
+ GetResInfo(ROMAddr,ModeNo);
+ GetCRT2Ptr(ROMAddr,ModeNo);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex));
+ tempax=tempax&0x0FFF;
+ VGAHT=tempax;
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+1));
+ tempax=tempax>>4;
+ tempax=tempax&0x07FF;
+ VGAVT=tempax;
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+3));
+ tempax=tempax&0x0FFF;
+ tempbx=*((USHORT *)(ROMAddr+REFIndex+4));
+ tempbx=tempbx>>4;
+ tempbx=tempbx&0x07FF;
+
+ HT=tempax;
+ VT=tempbx;
+
+ if(IF_DEF_TRUMPION==0){
+ if(VBInfo&SetCRT2ToLCD){
+ if(!(LCDInfo&LCDNonExpanding)){
+ if(LCDResInfo==Panel800x600){
+ tempax=800;
+ tempbx=600;
+ }else if(LCDResInfo==Panel1024x768){
+ tempax=1024;
+ tempbx=768;
+ }else{
+ tempax=1280;
+ tempbx=1024;
+ }
+ HDE=tempax;
+ VDE=tempbx;
+ }
+ }
+ }
+ REFIndex=OldREFIndex; //pop di
+ return;
+}
+
+VOID GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempax,tempbx,modeflag1,OldREFIndex;
+ USHORT tempal,tempah,tempbl;
+
+ OldREFIndex=(USHORT)REFIndex; //push di
+ RVBHRS=50;NewFlickerMode=0;RY1COE=0;
+ RY2COE=0;RY3COE=0;RY4COE=0;
+
+ GetResInfo(ROMAddr,ModeNo);
+ if(VBInfo&SetCRT2ToRAMDAC){
+ GetRAMDAC2DATA(ROMAddr,ModeNo);
+ REFIndex=OldREFIndex; //pop di
+ return;
+ }
+ GetCRT2Ptr(ROMAddr,ModeNo);
+
+ tempal=*((UCHAR *)(ROMAddr+REFIndex));
+ tempah=*((UCHAR *)(ROMAddr+REFIndex+4));
+ tempax=tempal|(((tempah<<8)>>7)&0xFF00);
+ RVBHCMAX=tempax;
+
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+1));
+ RVBHCFACT=tempal;
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+2));
+ VGAHT=(tempax&0x0FFF);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+3));
+ VGAVT=((tempax>>4)&0x07FF);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+5));
+ tempax=(tempax&0x0FFF);
+ tempbx=*((USHORT *)(ROMAddr+REFIndex+6));
+ tempbx=((tempbx>>4)&0x07FF);
+ tempbl=tempbx&0x00FF;
+
+ if(VBInfo&SetCRT2ToTV){
+ tempax=*((USHORT *)(ROMAddr+REFIndex+5));
+ tempax=(tempax&0x0FFF);
+ HDE=tempax;
+ tempax=*((USHORT *)(ROMAddr+REFIndex+6));
+ tempax=((tempax>>4)&0x07FF);
+ VDE=tempax;
+ //skipp something about hivisiontv
+ tempax=*((USHORT *)(ROMAddr+REFIndex+8));
+ tempbl=(tempax>>8);
+ tempax=tempax&0x0FFF;
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&HalfDCLK){
+ tempax=*((USHORT *)(ROMAddr+REFIndex+10));
+ }
+ RVBHRS=tempax;
+ NewFlickerMode=(tempbl&0x080);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+12));
+ RY1COE=(tempax&0x00FF);
+ RY2COE=((tempax&0xFF00)>>8);
+ tempax=*((USHORT *)(ROMAddr+REFIndex+14));
+ RY3COE=(tempax&0x00FF);
+ RY4COE=((tempax&0xFF00)>>8);
+ if(!(VBInfo&SetPALTV)){
+ tempax=NTSCHT;
+ tempbx=NTSCVT;
+ }else{
+ tempax=PALHT;
+ tempbx=PALVT;
+ }
+ }
+ HT=tempax;
+ VT=tempbx;
+ if(!(VBInfo&SetCRT2ToLCD)){
+ REFIndex=OldREFIndex; //pop di
+ return;
+ }
+
+ tempax=1024;
+ if(VGAVDE==350){ //cx->VGAVDE
+ tempbx=560;
+ }else if(VGAVDE==400){
+ tempbx=640;
+ }else{
+ tempbx=768;
+ }
+
+ if(LCDResInfo==Panel1280x1024){
+ tempax=1280;
+ if(VGAVDE==360){
+ tempbx=768;
+ }else if(VGAVDE==375){
+ tempbx=800;
+ }else if(VGAVDE==405){
+ tempbx=864;
+ }else{
+ tempbx=1024;
+ }
+ }
+
+ HDE=tempax;
+ VDE=tempbx;
+ REFIndex=OldREFIndex; //pop di
+ return;
+}
+
+VOID GetResInfo(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT temp,xres,yres,modeflag1;
+ if(ModeNo<=0x13){
+ temp=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x05)); // si+St_ResInfo
+ xres=StResInfo[temp][0];
+ yres=StResInfo[temp][1];
+ }else{
+ temp=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); // si+Ext_ResInfo
+ xres=ModeResInfo[temp][0]; //xres->ax
+ yres=ModeResInfo[temp][1]; //yres->bx
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&HalfDCLK){ xres=xres*2;}
+ if(modeflag1&DoubleScanMode){yres=yres*2;}
+ }
+ if(!(LCDResInfo==Panel1024x768)){
+ if(yres==400) yres=405;
+ if(yres==350) yres=360;
+ if(SetFlag&LCDVESATiming){
+ if(yres==360) yres=375;
+ }
+ }
+ VGAHDE=xres;
+ HDE=xres;
+ VGAVDE=yres;
+ VDE=yres;
+}
+
+VOID GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT old_REFIndex,tempax;
+
+ old_REFIndex=(USHORT)REFIndex; //push di
+ REFIndex=GetLVDSDesPtr(ROMAddr,ModeNo);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex));
+ tempax=tempax&0x0FFF;
+ LCDHDES=tempax;
+
+ if(LCDInfo&LCDNonExpanding){ //hw walk-a-round
+ if(LCDResInfo>=Panel1024x768){
+ if(ModeNo<=0x13){
+ LCDHDES=320;
+ }
+ }
+ }
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+1));
+ tempax=tempax>>4;
+ tempax=tempax&0x07FF;
+ LCDVDES=tempax;
+
+ REFIndex=old_REFIndex; //pop di
+ return;
+}
+
+
+VOID GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempax,tempbx,tempbh,modeflag1,t1=0,t2;
+ RVBHCMAX=1;RVBHCFACT=1;
+ if(ModeNo<=0x13){
+ tempax=*((UCHAR *)(ROMAddr+REFIndex+10));
+ tempbx=*((USHORT *)(ROMAddr+REFIndex+16));
+ }else{
+ t1=*((UCHAR *)(ROMAddr+REFIndex+0x2)); //Ext_CRT1CRTC=2
+ t1=t1&0x03F; //[06/29/2000] fix bug for vbios >=v1.07.00
+ t1=t1*CRT1Len;
+ REFIndex=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table
+ REFIndex=REFIndex+t1;
+ t1=*((UCHAR *)(ROMAddr+REFIndex+0));
+ t2=*((UCHAR *)(ROMAddr+REFIndex+14));
+ tempax=(t1&0xFF)|((t2&0x03)<<8);
+ tempbx=*((USHORT *)(ROMAddr+REFIndex+6));
+ t1=*((UCHAR *)(ROMAddr+REFIndex+13));
+ t1=(t1&0x01)<<2;
+ }
+
+ tempbh=tempbx>>8;
+ tempbh=((tempbh&0x20)>>4)|(tempbh&0x01);
+ tempbh=tempbh|t1;
+ tempbx=(tempbx&0xFF)|(tempbh<<8);
+ tempax=tempax+5;
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&Charx8Dot){
+ tempax=tempax*8;
+ }else{
+ tempax=tempax*9;
+ }
+
+ VGAHT=tempax;
+ HT=tempax;
+ tempbx++;
+ VGAVT=tempbx;
+ VT=tempbx;
+
+}
+
+VOID GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempcl,tempbx,tempal,tempax,CRT2PtrData;
+
+ if(IF_DEF_LVDS==0){
+ if(VBInfo&SetCRT2ToLCD){ //LCD
+ tempbx=0; //default tempbx=0 -> ExtLCD1Data
+ tempcl=LCDDataLen;
+ if(LCDResInfo==Panel1024x768){
+ tempbx=0;
+ }else if(LCDResInfo==Panel1280x1024){
+ tempbx=1;
+ }
+ if(!(SetFlag&LCDVESATiming)) tempbx+=5;
+ }else if(VBInfo&SetPALTV){
+ tempcl=TVDataLen;
+ tempbx=3;
+ }else{
+ tempbx=4;
+ tempcl=TVDataLen;
+ }
+ if(SetFlag&TVSimuMode){
+ tempbx=tempbx+4;
+ }
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC
+ }
+ tempal=tempal&0x1F;
+
+ tempax=tempal*tempcl;
+ REFIndex=*((USHORT *)(ROMAddr+tempbx*2+0x20E));
+ REFIndex+=tempax;
+ }else{ //for LVDS
+
+ tempcl=LVDSDataLen;
+ tempbx=LCDResInfo-Panel800x600;
+ if(LCDInfo&LCDNonExpanding){
+ tempbx=tempbx+3;
+ }
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC
+ }
+ tempal=tempal&0x1F;
+ tempax=tempal*tempcl;
+ CRT2PtrData=*((USHORT *)(ROMAddr+ADR_CRT2PtrData)); //ADR_CRT2PtrData is defined in init.def
+ REFIndex=*((USHORT *)(ROMAddr+CRT2PtrData+tempbx*2));
+ REFIndex+=tempax;
+ }
+}
+
+VOID UnLockCRT2(USHORT BaseAddr)
+{
+ UCHAR temp3;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ temp3=(UCHAR)GetReg1(Part1Port,0x24);
+ temp3=temp3|0x01;
+ SetReg1(Part1Port,0x24,(USHORT)temp3);
+}
+
+VOID SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo)
+{
+ USHORT i,j;
+ USHORT tempah=0,temp3;
+ SHORT tempcl;
+ USHORT Part4Port;
+ USHORT Part1Port;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ for(i=0,j=4;i<3;i++,j++){
+ SetReg1(Part1Port,j,0);
+ }
+
+ tempcl=(USHORT)ModeType;
+ if(ModeNo>0x13){
+ tempcl=tempcl-ModeVGA;
+ if(tempcl>=0){
+ tempah=((0x010>>tempcl)|0x080);
+ }
+ }else{
+ tempah=0x080;
+ }
+
+ if(VBInfo&SetInSlaveMode){
+ tempah=(tempah^0x0A0);
+ }
+ if(VBInfo&CRT2DisplayFlag){
+ tempah=0;
+ }
+ SetReg1(Part1Port,0,tempah);
+
+ if(IF_DEF_LVDS==0){ //301
+ tempah=0x01;
+ if(!(VBInfo&SetInSlaveMode)){
+ tempah=(tempah|0x02);
+ }
+ if(!(VBInfo&SetCRT2ToRAMDAC)){
+ tempah=(tempah^0x05);
+ if(!(VBInfo&SetCRT2ToLCD)){
+ tempah=(tempah^0x01);
+ }
+ }
+ tempah=(tempah<<5)&0xFF;
+ if(VBInfo&CRT2DisplayFlag){
+ tempah=0;
+ }
+ SetReg1(Part1Port,0x01,tempah);
+
+ tempah=tempah>>5;
+ if((ModeType==ModeVGA)&&(!(VBInfo&SetInSlaveMode))){
+ tempah=tempah|0x010;
+ }
+ if(LCDResInfo!=Panel1024x768){
+ tempah=tempah|0x080;
+ }
+ if(VBInfo&SetCRT2ToTV){
+ if(VBInfo&SetInSlaveMode){
+ tempah=tempah|0x020;
+ }
+ }
+
+ temp3=(UCHAR)GetReg1(Part4Port,0x0D);
+ temp3=temp3&(~0x0BF);
+ temp3=temp3|tempah;
+ SetReg1(Part4Port,0x0D,(USHORT)temp3);
+ }else{ //LVDS
+ tempah=0;
+ if(!(VBInfo&SetInSlaveMode)){
+ tempah=tempah|0x02;
+ }
+ tempah=(tempah<<5)&0x0FF;
+ if(VBInfo&CRT2DisplayFlag){
+ tempah=0;
+ }
+ SetReg1(Part1Port,0x01,tempah);
+ }
+}
+
+VOID SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ if(IF_DEF_LVDS==0){ //301
+ SetGroup1_301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+ }else{ //LVDS
+ SetGroup1_LVDS(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+ }
+}
+VOID SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT temp1,temp2,tempcl,tempch,tempbh,tempal,tempah,tempax,tempbx;
+ USHORT tempcx,OldREFIndex,lcdhdee;
+ USHORT Part1Port;
+ USHORT temppush1,temppush2;
+ unsigned long int tempeax,tempebx,tempecx,templong;
+
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ OldREFIndex=(USHORT)REFIndex; //push di
+
+ SetCRT2Offset(Part1Port,ROMAddr);
+ SetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension);
+ SetCRT2Sync(BaseAddr,ROMAddr,ModeNo);
+
+ temp1=(VGAHT-1)&0x0FF; //BTVGA2HT 0x08,0x09
+ SetReg1(Part1Port,0x08,temp1);
+ temp1=(((VGAHT-1)&0xFF00)>>8)<<4;
+ SetRegANDOR(Part1Port,0x09,~0x0F0,temp1);
+
+
+ temp1=(VGAHDE+12)&0x0FF; //BTVGA2HDEE 0x0A,0x0C
+ SetReg1(Part1Port,0x0A,temp1);
+
+ temp1=VGAHDE+12; //bx BTVGA@HRS 0x0B,0x0C
+ temp2=(VGAHT-VGAHDE)>>2; //cx
+ temp1=temp1+temp2;
+ temp2=(temp2<<1)+temp1;
+ tempcl=temp2&0x0FF;
+ //
+ SetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF));
+ tempah=(temp1&0xFF00)>>8;
+ tempbh=((((VGAHDE+12)&0xFF00)>>8)<<4)&0x0FF;
+ tempah=tempah|tempbh;
+ SetReg1(Part1Port,0x0C,tempah);
+ SetReg1(Part1Port,0x0D,tempcl); //BTVGA2HRE 0x0D
+ tempcx=(VGAVT-1);
+ tempah=tempcx&0x0FF;
+ SetReg1(Part1Port,0x0E,tempah); //BTVGA2TV 0x0E,0x12
+ tempbx=VGAVDE-1;
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x0F,tempah); //BTVGA2VDEE 0x0F,0x12
+ tempah=((tempbx&0xFF00)<<3)>>8;
+ tempah=tempah|((tempcx&0xFF00)>>8);
+ SetReg1(Part1Port,0x12,tempah);
+
+ tempbx=(VGAVT+VGAVDE)>>1; //BTVGA2VRS 0x10,0x11
+ tempcx=((VGAVT-VGAVDE)>>4)+tempbx+1; //BTVGA2VRE 0x11
+ //
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x10,tempah);
+ tempbh=(tempbx&0xFF00)>>8;
+ tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F);
+ SetReg1(Part1Port,0x11,tempah);
+
+ SetRegANDOR(Part1Port,0x13,~0x03C,tempah);
+
+ tempax=LCDHDES;
+ tempbx=HDE;
+ tempcx=HT;
+ tempcx=tempcx-tempbx; //HT-HDE
+ tempax=tempax+tempbx; //lcdhdee
+ tempbx=HT;
+ if(tempax>=tempbx){
+ tempax=tempax-tempbx;
+ }
+
+ lcdhdee=tempax;
+ tempcx=tempcx>>2; //temp
+ tempcx=tempcx+tempax; //lcdhrs
+ if(tempcx>=tempbx){
+ tempcx=tempcx-tempbx;
+ }
+
+ tempax=tempcx;
+ tempax=tempax>>3; //BPLHRS
+ tempah=tempax&0x0FF;
+ SetReg1(Part1Port,0x14,tempah); //Part1_14h
+ tempah=tempah+2;
+ tempah=tempah+0x01F;
+ tempcl=tempcx&0x0FF;
+ tempcl=tempcl&0x07;
+ tempcl=(tempcl<<5)&0xFF; //BPHLHSKEW
+ tempah=tempah|tempcl;
+ SetReg1(Part1Port,0x15,tempah); //Part1_15h
+ tempbx=lcdhdee; //lcdhdee
+ tempcx=LCDHDES; //lcdhdes
+ tempah=(tempcx&0xFF);
+ tempah=tempah&0x07; //BPLHDESKEW
+ SetReg1(Part1Port,0x1A,tempah); //Part1_1Ah
+ tempcx=tempcx>>3; //BPLHDES
+ tempah=(tempcx&0xFF);
+ SetReg1(Part1Port,0x16,tempah); //Part1_16h
+ tempbx=tempbx>>3; //BPLHDEE
+ tempah=tempbx&0xFF;
+ SetReg1(Part1Port,0x17,tempah); //Part1_17h
+
+ tempcx=VGAVT;
+ tempbx=VGAVDE;
+ tempcx=tempcx-tempbx; //VGAVT-VGAVDE
+ tempbx=LCDVDES; //VGAVDES
+ temppush1=tempbx; //push bx temppush1
+ if(IF_DEF_TRUMPION==0){
+ if(LCDResInfo==Panel800x600){
+ tempax=600;
+ }else{
+ tempax=768;
+ }
+ }else{
+ tempax=VGAVDE;
+ }
+ tempbx=tempbx+tempax;
+ tempax=VT; //VT
+ if(tempbx>=VT){
+ tempbx=tempbx-tempax;
+ }
+ temppush2=tempbx; //push bx temppush2
+ tempcx=tempcx>>1;
+ tempbx=tempbx+tempcx;
+ tempbx++; //BPLVRS
+ if(tempbx>=tempax){
+ tempbx=tempbx-tempax;
+ }
+ tempah=tempbx&0xFF;
+ SetReg1(Part1Port,0x18,tempah); //Part1_18h
+ tempcx=tempcx>>3;
+ tempcx=tempcx+tempbx;
+ tempcx++; //BPLVRE
+ tempah=tempcx&0xFF;
+ tempah=tempah&0x0F;
+ tempah=tempah|0x030;
+ SetRegANDOR(Part1Port,0x19,~0x03F,tempah); //Part1_19h
+ tempbh=(tempbx&0xFF00)>>8;
+ tempbh=tempbh&0x07;
+ tempah=tempbh;
+ tempah=(tempah<<3)&0xFF; //BPLDESKEW =0
+ tempbx=VGAVDE;
+ if(tempbx!=VDE){
+ tempah=tempah|0x40;
+ }
+ SetRegANDOR(Part1Port,0x1A,0x07,tempah); //Part1_1Ah
+ tempecx=VGAVT;
+ tempebx=VDE;
+ tempeax=VGAVDE;
+ tempecx=tempecx-tempeax; //VGAVT-VGAVDE
+ tempeax=tempeax*64;
+ templong=tempeax/tempebx;
+ if(templong*tempebx<tempeax){
+ templong++;
+ }
+ tempebx=templong; //BPLVCFACT
+ if(SetFlag&EnableLVDSDDA){
+ tempebx=tempebx&0x03F;
+ }
+ tempah=(USHORT)(tempebx&0x0FF);
+ SetReg1(Part1Port,0x1E,tempah); //Part1_1Eh
+ tempbx=temppush2; //pop bx temppush2 BPLVDEE
+ tempcx=temppush1; //pop cx temppush1 NPLVDES
+ tempbh=(tempbx&0xFF00)>>8;
+ tempah=tempah&0x07;
+ tempah=tempbh;
+ tempah=tempah<<3;
+ tempch=(tempcx&0xFF00)>>8;
+ tempch=tempah&0x07;
+ tempah=tempah|tempch;
+ SetReg1(Part1Port,0x1D,tempah); //Part1_1Dh
+ tempah=tempbx&0xFF;
+ SetReg1(Part1Port,0x1C,tempah); //Part1_1Ch
+ tempah=tempcx&0xFF;
+ SetReg1(Part1Port,0x1B,tempah); //Part1_1Bh
+
+ tempecx=VGAHDE;
+ tempebx=HDE;
+ tempeax=tempecx;
+ tempeax=tempeax<<6;
+ tempeax=tempeax<<10;
+ tempeax=tempeax/tempebx;
+ if(tempebx==tempecx){
+ tempeax=65535;
+ }
+ tempecx=tempeax;
+ tempeax=VGAHT;
+ tempeax=tempeax<<6;
+ tempeax=tempeax<<10;
+ tempeax=tempeax/tempecx;
+ tempecx=tempecx<<16;
+ tempeax=tempeax-1;
+ tempax=(USHORT)(tempeax&0x00FFFF);
+ tempcx=tempax;
+ tempah=tempcx&0x0FF;
+ SetReg1(Part1Port,0x1F,tempah); //Part1_1Fh
+ tempbx=VDE;
+ tempbx--; //BENPLACCEND
+ if(SetFlag&EnableLVDSDDA){
+ tempbx=1;
+ }
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<3)&0xFF;
+ tempch=(tempcx&0xFF00)>>8;
+ tempch=tempch&0x07;
+ tempah=tempah|tempch;
+ SetReg1(Part1Port,0x20,tempah); //Part1_20h
+ tempah=tempbx&0xFF;
+ SetReg1(Part1Port,0x21,tempah); //Part1_21h
+ tempecx=tempecx>>16; //BPLHCFACT
+ temp1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(temp1&HalfDCLK){
+ tempecx=tempecx>>1;
+ }
+ tempcx=(USHORT)(tempecx&0x0FFFF);
+ tempah=(tempcx&0xFF00)>>8;
+ SetReg1(Part1Port,0x22,tempah); //Part1_22h
+ tempah=tempcx&0x0FF;
+ SetReg1(Part1Port,0x23,tempah); //Part1_23h
+ if(IF_DEF_TRUMPION==1){
+ tempal=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x05)); // si+St_ResInfo
+ if(ModeNo>0x13){
+ SetFlag=SetFlag|ProgrammingCRT2;
+ GetRatePtrCRT2(ROMAddr,ModeNo);
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC
+ tempal=tempal&0x1F;
+ }
+ tempah=0x80;
+ tempal=tempal*tempah;
+ REFIndex= offset_Zurac; //offset Zurac need added in rompost.asm
+ REFIndex=REFIndex+tempal;
+ SetTPData(); //this function not implemented yet
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ }
+
+ REFIndex=OldREFIndex; //pop di
+ return;
+}
+
+VOID SetTPData(VOID)
+{
+ return;
+}
+
+VOID SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT temp1,temp2,tempcl,tempch,tempbl,tempbh,tempal,tempah,tempax,tempbx;
+ USHORT tempcx,OldREFIndex;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ OldREFIndex=(USHORT)REFIndex; //push di
+
+ SetCRT2Offset(Part1Port,ROMAddr);
+ SetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension);
+ SetCRT2Sync(BaseAddr,ROMAddr,ModeNo);
+
+ GetCRT1Ptr(ROMAddr);
+
+ temp1=(VGAHT-1)&0x0FF; //BTVGA2HT 0x08,0x09
+ SetReg1(Part1Port,0x08,temp1);
+ temp1=(((VGAHT-1)&0xFF00)>>8)<<4;
+ SetRegANDOR(Part1Port,0x09,~0x0F0,temp1);
+
+ temp1=(VGAHDE+12)&0x0FF; //BTVGA2HDEE 0x0A,0x0C
+ SetReg1(Part1Port,0x0A,temp1);
+
+ temp1=VGAHDE+12; //bx BTVGA@HRS 0x0B,0x0C
+ temp2=(VGAHT-VGAHDE)>>2; //cx
+ temp1=temp1+temp2;
+ temp2=(temp2<<1)+temp1;
+ tempcl=temp2&0x0FF;
+ if(VBInfo&SetCRT2ToRAMDAC){
+ tempbl=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+4
+ tempbh=*((UCHAR *)(ROMAddr+REFIndex+14)); //di+14
+ temp1=((tempbh>>6)<<8)|tempbl; //temp1->bx
+ temp1=(temp1-1)<<3;
+ tempcl=*((UCHAR *)(ROMAddr+REFIndex+5)); //di+5
+ tempch=*((UCHAR *)(ROMAddr+REFIndex+15)); //di+15
+ tempcl=tempcl&0x01F;
+ tempch=(tempch&0x04)<<(6-2);
+ tempcl=((tempcl|tempch)-1)<<3;
+ }
+ SetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF));
+ tempah=(temp1&0xFF00)>>8;
+ tempbh=((((VGAHDE+12)&0xFF00)>>8)<<4)&0x0FF;
+ tempah=tempah|tempbh;
+ SetReg1(Part1Port,0x0C,tempah);
+ SetReg1(Part1Port,0x0D,tempcl); //BTVGA2HRE 0x0D
+ tempcx=(VGAVT-1);
+ tempah=tempcx&0x0FF;
+ SetReg1(Part1Port,0x0E,tempah); //BTVGA2TV 0x0E,0x12
+ tempbx=VGAVDE-1;
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x0F,tempah); //BTVGA2VDEE 0x0F,0x12
+ tempah=((tempbx&0xFF00)<<3)>>8;
+ tempah=tempah|((tempcx&0xFF00)>>8);
+ SetReg1(Part1Port,0x12,tempah);
+
+ tempbx=(VGAVT+VGAVDE)>>1; //BTVGA2VRS 0x10,0x11
+ tempcx=((VGAVT-VGAVDE)>>4)+tempbx+1; //BTVGA2VRE 0x11
+ if(VBInfo&SetCRT2ToRAMDAC){
+ tempbx=*((UCHAR *)(ROMAddr+REFIndex+8)); //di+8
+ temp1=*((UCHAR *)(ROMAddr+REFIndex+7)); //di+7
+ if(temp1&0x04){
+ tempbx=tempbx|0x0100;
+ }
+ if(temp1&0x080){
+ tempbx=tempbx|0x0200;
+ }
+ temp1=*((UCHAR *)(ROMAddr+REFIndex+13)); //di+13
+ if(temp1&0x08){
+ tempbx=tempbx|0x0400;
+ }
+ tempcl= *((UCHAR *)(ROMAddr+REFIndex+9)); //di+9
+ tempcx=(tempcx&0xFF00)|(tempcl&0x00FF);
+ }
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x10,tempah);
+ tempbh=(tempbx&0xFF00)>>8;
+ tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F);
+ SetReg1(Part1Port,0x11,tempah);
+
+ if(HwDeviceExtension->jChipID == SIS_Glamour)
+ {
+ tempah=0x10;
+ if((LCDResInfo!=Panel1024x768)&&(LCDResInfo==Panel1280x1024)){
+ tempah=0x20;
+ }
+ }else{
+ tempah=0x20;
+ }
+ if(VBInfo&SetCRT2ToTV){
+ tempah=0x08;
+ }
+
+ SetRegANDOR(Part1Port,0x13,~0x03C,tempah);
+
+ if(!(VBInfo&SetInSlaveMode)){
+ REFIndex=OldREFIndex;
+ return;
+ }
+ if(VBInfo&SetCRT2ToTV){
+ tempax=0xFFFF;
+ }else{
+ tempax=GetVGAHT2();
+ }
+ tempcl=0x08; //Reg 0x03 Horozontal Total
+ temp1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(!(temp1&Charx8Dot)){ //temp1->St_ModeFlag
+ tempcl=0x09;
+ }
+ if(tempax>=VGAHT){
+ tempax=VGAHT;
+ }
+ if(temp1&HalfDCLK){
+ tempax=tempax>>1;
+ }
+ tempax=(tempax/tempcl)-5;
+ tempbl=tempax;
+ tempah=0xFF; //set MAX HT
+ SetReg1(Part1Port,0x03,tempah);
+
+ tempax=VGAHDE; //0x04 Horizontal Display End
+ if(temp1&HalfDCLK){
+ tempax=tempax>>1;
+ }
+ tempax=(tempax/tempcl)-1;
+ tempbh=tempax;
+ SetReg1(Part1Port,0x04,tempax);
+
+ tempah=tempbh;
+ if(VBInfo&SetCRT2ToTV){
+ tempah=tempah+2;
+ }
+ SetReg1(Part1Port,0x05,tempah); //0x05 Horizontal Display Start
+ SetReg1(Part1Port,0x06,0x03); //0x06 Horizontal Blank end
+ //0x07 horizontal Retrace Start
+ tempcx=(tempbl+tempbh)>>1;
+ tempah=(tempcx&0xFF)+2;
+
+ if(VBInfo&SetCRT2ToTV){
+ tempah=tempah-1;
+ if(!(temp1&HalfDCLK)){
+ if((temp1&Charx8Dot)){
+ tempah=tempah+4;
+ if(VGAHDE>=800){
+ tempah=tempah-6;
+ }
+ }
+ }
+ }else{
+ if(!(temp1&HalfDCLK)){
+ tempah=tempah-4;
+ if(VGAHDE>=800){
+ tempah=tempah-7;
+ if(ModeType==ModeEGA){
+ if(VGAVDE==1024){
+ tempah=tempah+15;
+ if(LCDResInfo!=Panel1280x1024){
+ tempah=tempah+7;
+ }
+ }
+ }
+ if(VGAHDE>=1280){
+ tempah=tempah+28;
+ }
+ }
+ }
+ }
+
+ SetReg1(Part1Port,0x07,tempah);//0x07 Horizontal Retrace Start
+
+ SetReg1(Part1Port,0x08,0); //0x08 Horizontal Retrace End
+ SetReg1(Part1Port,0x18,0x03); //0x18 SR08
+ SetReg1(Part1Port,0x19,0); //0x19 SR0C
+ SetReg1(Part1Port,0x09,0xFF); //0x09 Set Max VT
+
+ tempcx=0x121;
+ tempcl=0x21;
+ tempch=0x01;
+ tempbx=VGAVDE; //0x0E Virtical Display End
+ if(tempbx==360) tempbx=350;
+ if(tempbx==375) tempbx=350;
+ if(tempbx==405) tempbx=400;
+ tempbx--;
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x0E,tempah);
+ SetReg1(Part1Port,0x10,tempah);//0x10 vertical Blank Start
+ tempbh=(tempbx&0xFF00)>>8;
+ if(tempbh&0x01){
+ tempcl=tempcl|0x0A;
+ }
+ tempah=0;tempal=0x0B;
+ if(temp1&DoubleScanMode){
+ tempah=tempah|0x080;
+ }
+ if(tempbh&0x02){
+ tempcl=tempcl|0x040;
+ tempah=tempah|0x020;
+ }
+ SetReg1(Part1Port,0x0B,tempah);
+ if(tempbh&0x04){
+ tempch=tempch|0x06;
+ }
+
+ SetReg1(Part1Port,0x11,0); //0x11 Vertival Blank End
+
+ tempax=VGAVT-tempbx; //0x0C Vertical Retrace Start
+ tempax=tempax>>2;
+ temp2=tempax; //push ax
+ tempax=tempax<<1;
+ tempbx=tempax+tempbx;
+ if((SetFlag&TVSimuMode)&&(VBInfo&SetPALTV)&&(VGAHDE==800)){
+ tempbx=tempbx+40;
+ }
+ tempah=(tempbx&0x0FF);
+ SetReg1(Part1Port,0x0C,tempah);
+ tempbh=(tempbx&0xFF00)>>8;
+ if(tempbh&0x01){
+ tempcl=tempcl|0x04;
+ }
+ if(tempbh&0x02){
+ tempcl=tempcl|0x080;
+ }
+ if(tempbh&0x04){
+ tempch=tempch|0x08;
+ }
+
+ tempax=temp2; //pop ax
+ tempax=(tempax>>2)+1;
+ tempbx=tempbx+tempax;
+ tempah=(tempbx&0x0FF)&0x0F;
+ SetReg1(Part1Port,0x0D,tempah); //0x0D vertical Retrace End
+ tempbl=tempbx&0x0FF;
+ if(tempbl&0x10){
+ tempch=tempch|0x020;
+ }
+
+ tempah=tempcl;
+ SetReg1(Part1Port,0x0A,tempah); //0x0A CR07
+ tempah=tempch;
+ SetReg1(Part1Port,0x17,tempah); //0x17 SR0A
+ tempax=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ tempah=(tempax&0xFF00)>>8;
+ tempah=(tempah>>1)&0x09;
+ SetReg1(Part1Port,0x16,tempah); //0x16 SR01
+ SetReg1(Part1Port,0x0F,0); //0x0F CR14
+ SetReg1(Part1Port,0x12,0); //0x12 CR17
+ SetReg1(Part1Port,0x1A,0); //0x1A SR0E
+
+ REFIndex=OldREFIndex; //pop di
+}
+
+VOID SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr)
+{
+ USHORT offset;
+ if(VBInfo&SetInSlaveMode){
+ return;
+ }
+ offset=GetOffset(ROMAddr);
+ SetReg1(Part1Port,0x07,(USHORT)(offset&0xFF));
+ SetReg1(Part1Port,0x09,(USHORT)((offset&0xFF00)>>8));
+ SetReg1(Part1Port,0x03,(USHORT)(((offset>>3)&0xFF)+1));
+}
+
+USHORT GetOffset(ULONG ROMAddr)
+{
+ USHORT tempal,temp1,colordepth;
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+Ext_ModeInfo
+ tempal=(tempal>>4)&0xFF;
+ ScreenOffset=*((USHORT *)(ROMAddr+0x206)); // Get ScreeOffset table
+ tempal=*((UCHAR *)(ROMAddr+ScreenOffset+tempal)); // get ScreenOffset
+ tempal=tempal&0xFF;
+ temp1=*((UCHAR *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag
+ if(temp1&InterlaceMode){
+ tempal=tempal<<1;
+ }
+ colordepth=GetColorDepth(ROMAddr);
+ return(tempal*colordepth);
+}
+
+USHORT GetColorDepth(ULONG ROMAddr)
+{
+ USHORT ColorDepth[6]={1,2,4,4,6,8};
+ USHORT temp;
+ int temp1;
+ temp=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ temp1=(temp&ModeInfoFlag)-ModeEGA;
+ if(temp1<0) temp1=0;
+ return(ColorDepth[temp1]);
+}
+
+VOID SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT temp,temp1,temp2,temp3,flag;
+ USHORT vclk2ptr,latencyindex;
+ USHORT oldREFIndex,CRT1ModeNo,oldModeIDOffset;
+ long int longtemp;
+
+ USHORT LatencyFactor[48]={ 88, 80, 78, 72, 70, 00, // 64 bit BQ=2
+ 00, 79, 77, 71, 69, 49, // 64 bit BQ=1
+ 88, 80, 78, 72, 70, 00, // 128 bit BQ=2
+ 00, 72, 70, 64, 62, 44, // 128 bit BQ=1
+ 73, 65, 63, 57, 55, 00, // 64 bit BQ=2
+ 00, 64, 62, 56, 54, 34, // 64 bit BQ=1
+ 78, 70, 68, 62, 60, 00, // 128 bit BQ=2
+ 00, 62, 60, 54, 52, 34}; // 128 bit BQ=1
+
+ oldREFIndex=(USHORT)REFIndex; //push REFIndex(CRT2 now)
+ oldModeIDOffset=(USHORT)ModeIDOffset; //push ModeIDOffset
+
+ CRT1ModeNo=(UCHAR)GetReg1(P3d4,0x34); //get CRT1 ModeNo
+ SearchModeID(ROMAddr,CRT1ModeNo); //Get ModeID Table
+
+ GetRatePtr(ROMAddr,CRT1ModeNo); //Set REFIndex-> for crt1 refreshrate
+ temp1=GetVCLK(ROMAddr,CRT1ModeNo,HwDeviceExtension);
+ temp2=GetColorTh(ROMAddr);
+ temp3=GetMCLK(ROMAddr);
+ temp=((USHORT)(temp1*temp2)/temp3); //temp->bx
+ temp1=(UCHAR)GetReg1(P3c4,0x14); //SR_14
+ temp1=temp1>>6;
+ temp1=temp1<<1;
+ if(temp1==0) temp1=1;
+ temp1=temp1<<2; //temp1->ax
+
+ longtemp=temp1-temp;
+
+ temp2=(USHORT)((28*16)/(int)longtemp); //temp2->cx
+ if(!((temp2*(int)longtemp)==(28*16))) temp2++;
+
+ if( HwDeviceExtension->jChipID == SIS_Glamour ){
+ temp1=CalcDelay();
+ }else{ //for Trojan and Spartan
+ flag=(UCHAR)GetReg1(P3c4,0x14); //SR_14
+ if(flag&0x80){
+ latencyindex=12; //128 bit
+ }else{
+ latencyindex=0; //64 bit
+ }
+ flag=GetQueueConfig();
+ if(!(flag&0x01)){
+ latencyindex+=24; //GUI timing =0
+ }
+ if(flag&0x10){
+ latencyindex+=6; //BQ =2
+ }
+ latencyindex=latencyindex + (flag>>5);
+ temp1= LatencyFactor[latencyindex];
+ temp1=temp1+15;
+ flag=(UCHAR)GetReg1(P3c4,0x14); //SR_14
+ if(!(flag&0x80)){
+ temp1=temp1+5; //64 bit
+ }
+ }
+
+ temp2=temp2+temp1;
+ REFIndex=oldREFIndex; //pop REFIndex(CRT2)
+ ModeIDOffset=oldModeIDOffset; //pop ModeIDOffset
+
+ vclk2ptr=GetVCLK2Ptr(ROMAddr,ModeNo);
+ temp1=*((USHORT *)(ROMAddr+vclk2ptr+(VCLKLen-2)));
+ temp3=GetColorTh(ROMAddr);
+ longtemp=temp1*temp2*temp3;
+ temp3=GetMCLK(ROMAddr);
+ temp3=temp3<<4;
+ temp2=(int)(longtemp/temp3);
+ if((long int)temp2*(long int)temp3<(long int)longtemp) temp2++; //temp2->cx
+
+ temp1=(UCHAR)GetReg1(Part1Port,0x01); //part1port index 01
+
+
+ if( (HwDeviceExtension->jChipID == SIS_Trojan ) &&
+ ((HwDeviceExtension->revision_id & 0xf0) == 0x30) ) /* 630s */
+ {
+ temp1=(temp1&(~0x1F))|0x19;
+ }else
+ {
+ temp1=(temp1&(~0x1F))|0x16;
+ }
+ SetReg1(Part1Port,0x01,temp1);
+
+ if(temp2<=6) temp2=6;
+ if(temp2>0x14) temp2=0x14;
+ temp1=(UCHAR)GetReg1(Part1Port,0x02); //part1port index 02
+ temp1=(temp1&(~0x1F))|temp2;
+ SetReg1(Part1Port,0x02,temp1);
+}
+
+USHORT GetVCLK(ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT tempptr;
+ USHORT temp1;
+ tempptr=GetVCLKPtr(ROMAddr,ModeNo);
+ temp1=*((USHORT *)(ROMAddr+tempptr+(VCLKLen-2)));
+
+ return temp1;
+}
+
+USHORT GetQueueConfig(void)
+{
+ USHORT tempal,tempbl;
+ ULONG tempeax;
+
+ SetReg4(0xcf8,0x80000050);
+ tempeax=GetReg3(0xcfc);
+ tempeax=(tempeax>>24)&0x0f;
+ tempbl=(USHORT)tempeax;
+ tempbl=tempbl<<4;
+
+ SetReg4(0xcf8,0x800000A0);
+ tempeax=GetReg3(0xcfc);
+ tempeax=(tempeax>>24)&0x0f;
+ tempal=(USHORT)tempeax;
+ tempbl=tempbl|tempal;
+
+ return(tempbl);
+}
+
+USHORT GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempal;
+ tempal=(UCHAR)GetReg2((USHORT)(P3ca+0x02)); // Port 3cch
+ tempal=((tempal>>2)&0x03);
+ if(ModeNo>0x13){
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK
+ tempal=tempal&0x03F;
+ }
+ VCLKLen=GetVCLKLen(ROMAddr);
+ tempal=tempal*VCLKLen;
+ tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); // VCLKData
+ return ((USHORT)tempal);
+}
+
+USHORT GetColorTh(ULONG ROMAddr)
+{
+ USHORT temp;
+ temp=GetColorDepth(ROMAddr);
+ temp=temp>>1;
+ if(temp==0) temp++;
+ return temp;
+}
+
+USHORT GetMCLK(ULONG ROMAddr)
+{
+ USHORT tempmclkptr;
+ USHORT tempmclk;
+ tempmclkptr=GetMCLKPtr(ROMAddr);
+ tempmclk=*((USHORT *)(ROMAddr+tempmclkptr+0x03)); //di+3
+ return tempmclk;
+}
+
+USHORT GetMCLKPtr(ULONG ROMAddr)
+{
+ USHORT tempdi;
+ USHORT tempdramtype,tempax;
+
+ tempdi=*((USHORT *)(ROMAddr+0x20C)); // MCLKData
+ tempdramtype=GetDRAMType(ROMAddr);
+ tempax=5*tempdramtype;
+ tempdi=tempdi+tempax;
+ return (tempdi);
+}
+
+USHORT GetDRAMType(ULONG ROMAddr)
+{
+ USHORT tsoftsetting,temp3;
+
+ tsoftsetting=*((UCHAR *)(ROMAddr+0x52));
+ if(!(tsoftsetting&SoftDramType)){
+ temp3=(UCHAR)GetReg1(P3c4,0x3A);
+ tsoftsetting=temp3;
+ }
+ tsoftsetting=tsoftsetting&0x07;
+ return(tsoftsetting);
+}
+
+static USHORT CalcDelay()
+{
+ USHORT tempal,tempah,temp1,tempbx;
+ USHORT ThTiming[8]={1,2,2,3,0,1,1,2};
+ USHORT ThLowB[24]={81,4,72,6,88,8,120,12,
+ 55,4,54,6,66,8,90,12,
+ 42,4,45,6,55,8,75,12};
+
+ tempah=(UCHAR)GetReg1(P3c4,0x18); //SR_18
+ tempah=tempah&0x62;
+ tempah=tempah>>1;
+ tempal=tempah;
+ tempah=tempah>>3;
+ tempal=tempal|tempah;
+ tempal=tempal&0x07;
+
+ temp1=ThTiming[tempal]; //temp1->cl
+
+ tempbx=(UCHAR)GetReg1(P3c4,0x16); //SR_16
+ tempbx=tempbx>>6;
+ tempah=(UCHAR)GetReg1(P3c4,0x14); //SR_14
+ tempah=((tempah>>4)&0x0C);
+ tempbx=((tempbx|tempah)<<1);
+
+ tempal=ThLowB[tempbx+1]*temp1;
+ tempbx=ThLowB[tempbx];
+ tempbx=tempal+tempbx;
+
+ return(tempbx);
+}
+
+USHORT GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempal;
+ USHORT LCDXlat1VCLK[4]={VCLK65,VCLK65,VCLK65,VCLK65};
+ USHORT LCDXlat2VCLK[4]={VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2};
+
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC
+ }
+ tempal=tempal>>6;
+ if(LCDResInfo!=Panel1024x768){
+ tempal=LCDXlat2VCLK[tempal];
+ }else{
+ tempal=LCDXlat1VCLK[tempal];
+ }
+
+ if(VBInfo&SetCRT2ToLCD){
+ tempal=tempal;
+ }else if(VBInfo&SetCRT2ToTV){
+ if(SetFlag&RPLLDIV2XO){
+ tempal=TVVCLKDIV2;
+ }else{
+ tempal=TVVCLK;
+ }
+ }else{
+ tempal=(UCHAR)GetReg2((USHORT)(P3ca+0x02)); // Port 3cch
+ tempal=((tempal>>2)&0x03);
+ if(ModeNo>0x13){
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK
+ tempal=tempal&0x03F;
+ }
+ }
+ VCLKLen=GetVCLKLen(ROMAddr);
+ tempal=tempal*VCLKLen;
+ tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); // VCLKData
+ return ((USHORT)tempal);
+}
+
+USHORT GetVCLKLen(ULONG ROMAddr)
+{
+ USHORT VCLKDataStart,vclklabel,temp;
+ VCLKDataStart=*((USHORT *)(ROMAddr+0x208));
+ for(temp=0;;temp++){
+ vclklabel=*((USHORT *)(ROMAddr+VCLKDataStart+temp));
+ if(vclklabel==VCLKStartFreq){
+ temp=temp+2;
+ return(temp);
+ }
+ }
+ return(0);
+}
+
+
+VOID SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT temp1,tempah=0;
+ USHORT temp;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ if(IF_DEF_LVDS==1){ //LVDS
+ if(VBInfo&SetCRT2ToLCD){
+ tempah=LCDInfo;
+ if(!(tempah&LCDSync)){
+ temp=*((USHORT *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag
+ tempah=(temp>>8)&0x0C0;
+ }else{
+ tempah=tempah&0x0C0;
+ }
+ }
+ }else{
+ temp=*((USHORT *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag
+ tempah=(temp>>8)&0x0C0;
+ }
+ temp1=(UCHAR)GetReg1(Part1Port,0x19); //part1port index 02
+ temp1=(temp1&(~0x0C0))|tempah;
+ SetReg1(Part1Port,0x19,temp1);
+}
+
+VOID GetCRT1Ptr(ULONG ROMAddr)
+{
+ USHORT temprefcrt1;
+ USHORT temp;
+ temp=*((UCHAR *)(ROMAddr+REFIndex+0x02)); //di+Ext_CRT1CRTC
+ temp=temp&0x03F;
+ temp=temp*CRT1Len;
+ temprefcrt1=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table
+ REFIndex=temprefcrt1+temp; // di->CRT1Table+Ext_CRT1CRTC*CRT1Len
+}
+
+USHORT GetVGAHT2()
+{
+ long int temp1,temp2;
+
+ temp1=(VGAVT-VGAVDE)*RVBHCMAX;
+ temp1=temp1&0x0FFFF;
+ temp2=(VT-VDE)*RVBHCFACT;
+ temp2=temp2&0x0FFFF;
+ temp2=temp2*HT;
+ temp2=temp2/temp1;
+ return((USHORT)temp2);
+}
+
+VOID SetGroup2(USHORT BaseAddr,ULONG ROMAddr)
+{
+ USHORT tempah,tempbl,tempbh,tempcl,i,j,tempcx,pushcx,tempbx,tempax;
+ USHORT tempmodeflag,tempflowflag;
+ UCHAR *temp1;
+ USHORT *temp2;
+ USHORT pushbx;
+ USHORT Part2Port;
+ long int longtemp;
+
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+
+ tempcx=VBInfo;
+ tempah=VBInfo&0x0FF;
+ tempbl=VBInfo&0x0FF;
+ tempbh=VBInfo&0x0FF;
+ tempbx=(tempbl&0xFF)|(tempbh<<8);
+ tempbl=tempbl&0x10;
+ tempbh=(tempbh&0x04)<<1;
+ tempah=(tempah&0x08)>>1;
+ tempah=tempah|tempbh;
+ tempbl=tempbl>>3;
+ tempah=tempah|tempbl;
+ tempah=tempah^0x0C;
+
+ if(VBInfo&SetPALTV){
+ temp1=(UCHAR *)(ROMAddr+0x0F1); //PALPhase
+ temp2=PALTiming;
+ }else{
+ tempah=tempah|0x10;
+ temp1=(UCHAR *)(ROMAddr+0x0ED); //NTSCPhase
+ temp2=NTSCTiming;
+ }
+
+ SetReg1(Part2Port,0x0,tempah);
+ for(i=0x31;i<=0x34;i++,temp1++){
+ SetReg1(Part2Port,i,*(UCHAR *)temp1);
+ }
+ for(i=0x01,j=0;i<=0x2D;i++,j++){
+ SetReg1(Part2Port,i,temp2[j]);
+ }
+ for(i=0x39;i<=0x45;i++,j++){
+ SetReg1(Part2Port,i,temp2[j]); //di->temp2[j]
+ }
+
+ tempah=GetReg1(Part2Port,0x0A);
+ tempah=tempah|NewFlickerMode;
+ SetReg1(Part2Port,0x0A,tempah);
+
+ SetReg1(Part2Port,0x35,RY1COE);
+ SetReg1(Part2Port,0x36,RY2COE);
+ SetReg1(Part2Port,0x37,RY3COE);
+ SetReg1(Part2Port,0x38,RY4COE);
+
+ tempcx=HT-1;
+ tempah=tempcx&0xFF;
+ SetReg1(Part2Port,0x1B,tempah);
+ tempah=(tempcx&0xFF00)>>8;
+ SetRegANDOR(Part2Port,0x1D,~0x0F,(UCHAR)tempah);
+
+ tempcx=HT>>1;
+ pushcx=tempcx;
+
+ tempcx=tempcx+7;
+ tempah=(tempcx&0xFF);
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x22,~0x0F0,tempah);
+
+
+ tempbx=temp2[j];
+ tempbx=tempbx+tempcx;
+ tempah=tempbx&0xFF;
+ SetReg1(Part2Port,0x24,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x25,~0x0F0,tempah);
+
+ tempbx=tempbx+8;
+
+ tempah=((tempbx&0xFF)<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x29,~0x0F0,tempah);
+
+ tempcx=tempcx+temp2[++j];
+ tempah=tempcx&0xFF;
+ SetReg1(Part2Port,0x27,tempah);
+ tempah=(((tempcx&0xFF00)>>8)<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x28,~0x0F0,tempah);
+
+ tempcx=tempcx+8;
+
+ tempah=tempcx&0xFF;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x2A,~0x0F0,tempah);
+
+ tempcx=pushcx; //pop cx
+ tempcx=tempcx-temp2[++j];
+ tempah=tempcx&0xFF;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x2D,~0x0F0,tempah);
+
+ tempcx=tempcx-11;
+ if(!(VBInfo&SetCRT2ToTV)){
+ tempax=GetVGAHT2();
+ tempcx=tempax-1;
+ }
+ tempah=tempcx&0xFF;
+ SetReg1(Part2Port,0x2E,tempah);
+
+ tempbx=VDE;
+ if(VGAVDE==360){
+ tempbx=746;
+ }
+ if(VGAVDE==375){
+ tempbx=746;
+ }
+ if(VGAVDE==405){
+ tempbx=853;
+ }
+ if((VBInfo&SetCRT2ToTV)){
+ tempbx=tempbx>>1;
+ }
+
+ tempbx=tempbx-2;
+ tempah=tempbx&0xFF;
+ SetReg1(Part2Port,0x2F,tempah);
+
+ tempah=(tempcx&0xFF00)>>8;
+ tempbh=(tempbx&0xFF00)>>8;
+ tempbh=(tempbh<<6)&0xFF;
+ tempah=tempah|tempbh;
+ //assuming <<ifndef>> hivisiontv
+ tempah=tempah|0x10;
+ if(!(VBInfo&SetCRT2ToSVIDEO)){
+ tempah=tempah|0x20;
+ }
+
+ SetReg1(Part2Port,0x30,tempah);
+
+ tempbh=0;
+ tempbx=tempbx&0xFF;
+
+ tempmodeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ tempflowflag=0;
+ if(!(tempmodeflag&HalfDCLK)){
+ tempcx=VGAHDE;
+ if(tempcx>=HDE){
+ tempbh=tempbh|0x20;
+ tempbx=(tempbh<<8)|(tempbx&0xFF);
+ tempah=0;
+ }
+ }
+ tempcx=0x0101;
+ if(!(tempbh&0x20)){
+ if(tempmodeflag&HalfDCLK){
+ tempcl=((tempcx&0xFF)<<1)&0xFF;
+ tempcx=(tempcx&0xFF00)|tempcl;
+ }
+ pushbx=tempbx;
+ tempax=VGAHDE;
+ tempbx=(tempcx&0xFF00)>>8;
+ longtemp=tempax*tempbx;
+ tempcx=tempcx&0xFF;
+ longtemp=longtemp/tempcx;
+ longtemp=longtemp*8*1024;
+ tempax=(USHORT)((longtemp)/HDE);
+ if(tempax*HDE<longtemp){
+ tempax=tempax+1;
+ }else{
+ tempax=tempax;
+ }
+ tempbx=pushbx;
+ tempah=((tempax&0xFF00)>>8)&0x01F;
+ tempbh=tempbh|tempah;
+ tempah=tempax&0xFF;
+ }
+
+ SetReg1(Part2Port,0x44,tempah);
+ tempah=tempbh;
+ SetRegANDOR(Part2Port,0x45,~0x03F,tempah);
+
+ if(VBInfo&SetCRT2ToTV){
+ return;
+ }
+
+ tempah=0x01;
+ if(LCDResInfo==Panel1280x1024){
+ if(ModeType==ModeEGA){
+ if(VGAHDE>=1024){
+ tempah=0x02;
+ }
+ }
+ }
+ SetReg1(Part2Port,0x0B,tempah);
+
+ tempbx=HDE-1; //RHACTE=HDE-1
+ tempah=tempbx&0xFF;
+ SetReg1(Part2Port,0x2C,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x2B,~0x0F0,tempah);
+
+ tempbx=VDE-1; //RTVACTEO=(VDE-1)&0xFF
+ tempah=tempbx&0xFF;
+ SetReg1(Part2Port,0x03,tempah);
+ tempah=((tempbx&0xFF00)>>8)&0x07;
+ SetRegANDOR(Part2Port,0x0C,~0x07,tempah);
+
+ tempcx=VT-1;
+ tempah=tempcx&0xFF; //RVTVT=VT-1
+ SetReg1(Part2Port,0x19,tempah);
+ tempah=(tempcx&0xFF00)>>8;
+ tempah=(tempah<<5)&0xFF;
+ if(LCDInfo&LCDRGB18Bit){
+ tempah=tempah|0x10;
+ }
+ SetReg1(Part2Port,0x1A,tempah);
+
+ tempcx++;
+ if(LCDResInfo==Panel1024x768){
+ tempbx=768;
+ }else{
+ tempbx=1024;
+ }
+
+ if(tempbx==VDE){
+ tempax=1;
+ }else{
+ tempax=tempbx;
+ tempax=(tempax-VDE)>>1;
+ }
+ tempcx=tempcx-tempax; //lcdvdes
+ tempbx=tempbx-tempax; //lcdvdee
+
+ tempah=tempcx&0xFF; //RVEQ1EQ=lcdvdes
+ SetReg1(Part2Port,0x05,tempah);
+ tempah=tempbx&0xFF; //RVEQ2EQ=lcdvdee
+ SetReg1(Part2Port,0x06,tempah);
+
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<3)&0xFF;
+ tempah=tempah|((tempcx&0xFF00)>>8);
+ //RTVACTSE=(lcdvdes&0x700>>8)+(lcdvdee&0x700>>5);
+ SetReg1(Part2Port,0x02,tempah);
+
+
+ tempcx=(VT-VDE)>>4; //(VT-VDE)>>4
+ tempbx=(VT+VDE)>>1;
+ tempah=tempbx&0xFF; //RTVACTEE=lcdvrs
+ SetReg1(Part2Port,0x04,tempah);
+
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<4)&0xFF;
+ tempbx=tempbx+tempcx+1;
+ tempbl=(tempbx&0x0F);
+ tempah=tempah|tempbl; //RTVACTSO=lcdvrs&0x700>>4+lcdvre
+ SetReg1(Part2Port,0x01,tempah);
+
+ tempah=GetReg1(Part2Port,0x09);
+ tempah=tempah&0xF0;
+ SetReg1(Part2Port,0x09,tempah);
+
+ tempah=GetReg1(Part2Port,0x0A);
+ tempah=tempah&0xF0;
+ SetReg1(Part2Port,0x0A,tempah);
+
+ tempcx=(HT-HDE)>>2; //(HT-HDE)>>2
+ tempbx=(HDE+7); //lcdhdee
+ tempah=tempbx&0xFF; //RHEQPLE=lcdhdee
+ SetReg1(Part2Port,0x23,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ SetRegANDOR(Part2Port,0x25,~0x0F,tempah);
+
+ SetReg1(Part2Port,0x1F,0x07); //RHBLKE=lcdhdes
+ tempah=GetReg1(Part2Port,0x20);
+ tempah=tempah&0x0F;
+ SetReg1(Part2Port,0x20,tempah);
+
+ tempbx=tempbx+tempcx;
+ tempah=tempbx&0xFF; //RHBURSTS=lcdhrs
+ SetReg1(Part2Port,0x1C,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x1D,~0x0F0,tempah);
+
+ tempbx=tempbx+tempcx;
+ tempah=tempbx&0xFF; //RHSYEXP2S=lcdhre
+ SetReg1(Part2Port,0x21,tempah);
+
+ tempah=GetReg1(Part2Port,0x17);
+ tempah=tempah&0xFB;
+ SetReg1(Part2Port,0x17,tempah);
+
+ tempah=GetReg1(Part2Port,0x18);
+ tempah=tempah&0xDF;
+ SetReg1(Part2Port,0x18,tempah);
+ return;
+}
+
+VOID SetGroup3(USHORT BaseAddr)
+{
+ USHORT i;
+ USHORT *tempdi;
+ USHORT Part3Port;
+ Part3Port=BaseAddr+IND_SIS_CRT2_PORT_12;
+ if(VBInfo&SetPALTV){
+ tempdi=PALGroup3Data;
+ }else{
+ tempdi=NTSCGroup3Data;
+ }
+
+ for(i=0;i<=0x3E;i++){
+ SetReg1(Part3Port,i,tempdi[i]);
+ }
+ return;
+}
+
+VOID SetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT Part4Port;
+ USHORT tempax,tempah,tempcx,tempbx,tempbh,tempch,tempmodeflag;
+ long int tempebx,tempeax,templong;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+
+ tempax=0x0c;
+ if(VBInfo&SetCRT2ToTV){
+ if(VBInfo&SetInSlaveMode){
+ if(!(SetFlag&TVSimuMode)){
+ SetFlag=SetFlag|RPLLDIV2XO;
+ tempax=tempax|0x04000;
+ }
+ }else{
+ SetFlag=SetFlag|RPLLDIV2XO;
+ tempax=tempax|0x04000;
+ }
+ }
+
+ if(LCDResInfo!=Panel1024x768){
+ tempax=tempax|0x08000;
+ }
+ tempah=(tempax&0xFF00)>>8;
+ SetReg1(Part4Port,0x0C,tempah);
+
+ tempah=RVBHCFACT;
+ SetReg1(Part4Port,0x13,tempah);
+
+ tempbx=RVBHCMAX;
+ tempah=tempbx&0xFF;
+ SetReg1(Part4Port,0x14,tempah);
+ tempbh=(((tempbx&0xFF00)>>8)<<7)&0xFF;
+
+ tempcx=VGAHT-1;
+ tempah=tempcx&0xFF;
+ SetReg1(Part4Port,0x16,tempah);
+ tempch=(((tempcx&0xFF00)>>8)<<3)&0xFF;
+ tempbh=tempbh|tempch;
+
+ tempcx=VGAVT-1;
+ if(!(VBInfo&SetCRT2ToTV)){
+ tempcx=tempcx-5;
+ }
+ tempah=tempcx&0xFF;
+ SetReg1(Part4Port,0x17,tempah);
+ tempbh=tempbh|((tempcx&0xFF00)>>8);
+ tempah=tempbh;
+ SetReg1(Part4Port,0x15,tempah);
+
+ tempcx=VBInfo;
+ tempbx=VGAHDE;
+ tempmodeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(tempmodeflag&HalfDCLK){
+ tempbx=tempbx>>1;
+ }
+
+ if(VBInfo&SetCRT2ToLCD){
+ tempah=0;
+ if(tempbx>800){
+ tempah=0x60;
+ }
+ }else{
+ tempah=0x080;
+ }
+ if(LCDResInfo!=Panel1280x1024){
+ tempah=tempah|0x0A;
+ }
+
+ SetRegANDOR(Part4Port,0x0E,~0xEF,tempah);
+
+ tempebx=VDE;
+
+ tempcx=RVBHRS;
+ tempah=tempcx&0xFF;
+ SetReg1(Part4Port,0x18,tempah);
+
+ tempeax=VGAVDE;
+ tempcx=tempcx|0x04000;
+ tempeax=tempeax-tempebx;
+ if(tempeax<0){
+ tempcx=tempcx^(0x04000);
+ tempeax=VGAVDE;
+ }
+
+ templong=(tempeax*256*1024)/tempebx;
+ if(tempeax*256*1024-templong*tempebx>0){
+ tempebx=templong+1;
+ }else{
+ tempebx=templong;
+ }
+
+
+ tempah=(USHORT)(tempebx&0xFF);
+ SetReg1(Part4Port,0x1B,tempah);
+ tempah=(USHORT)((tempebx&0xFF00)>>8);
+ SetReg1(Part4Port,0x1A,tempah);
+ tempebx=tempebx>>16;
+ tempah=(USHORT)(tempebx&0xFF);
+ tempah=(tempah<<4)&0xFF;
+ tempah=tempah|((tempcx&0xFF00)>>8);
+ SetReg1(Part4Port,0x19,tempah);
+
+ SetCRT2VCLK(BaseAddr,ROMAddr,ModeNo);
+}
+
+VOID SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT vclk2ptr;
+ USHORT tempah,temp1;
+ USHORT Part4Port;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ vclk2ptr=GetVCLK2Ptr(ROMAddr,ModeNo);
+ SetReg1(Part4Port,0x0A,0x01);
+ tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x01)); //di+1
+ SetReg1(Part4Port,0x0B,tempah);
+ tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x00)); //di
+ SetReg1(Part4Port,0x0A,tempah);
+ SetReg1(Part4Port,0x12,0x00);
+ tempah=0x08;
+ if(VBInfo&SetCRT2ToRAMDAC){
+ tempah=tempah|0x020;
+ }
+ temp1=GetReg1(Part4Port,0x12);
+ tempah=tempah|temp1;
+ SetReg1(Part4Port,0x12,tempah);
+}
+
+VOID SetGroup5(USHORT BaseAddr,ULONG ROMAddr)
+{
+ USHORT Part5Port;
+ USHORT Pindex,Pdata;
+ Part5Port=BaseAddr+IND_SIS_CRT2_PORT_14+2;
+ Pindex=Part5Port;
+ Pdata=Part5Port+1;
+ if(ModeType==ModeVGA){
+ if(!(VBInfo&(SetInSlaveMode|LoadDACFlag|CRT2DisplayFlag))){
+ EnableCRT2();
+ LoadDAC2(ROMAddr,Part5Port);
+ }
+ }
+ return;
+}
+
+VOID EnableCRT2()
+{
+ USHORT temp1;
+ temp1=GetReg1(P3c4,0x1E);
+ temp1=temp1|0x20;
+ SetReg1(P3c4,0x1E,temp1); //SR 1E
+}
+
+VOID LoadDAC2(ULONG ROMAddr,USHORT Part5Port)
+{
+ USHORT data,data2;
+ USHORT time,i,j,k;
+ USHORT m,n,o;
+ USHORT si,di,bx,dl;
+ USHORT al,ah,dh;
+ USHORT *table=VGA_DAC;
+ USHORT Pindex,Pdata;
+ Pindex=Part5Port;
+ Pdata=Part5Port+1;
+ data=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ data=data&DACInfoFlag;
+ time=64;
+ if(data==0x00) table=MDA_DAC;
+ if(data==0x08) table=CGA_DAC;
+ if(data==0x10) table=EGA_DAC;
+ if(data==0x18) {
+ time=256;
+ table=VGA_DAC;
+ }
+ if(time==256) j=16;
+ else j=time;
+
+ //SetReg3(P3c6,0xFF);
+ SetReg3(Pindex,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=data2+0x15;
+ SetReg3(Pdata,data2);
+ data=data>>2;
+ }
+ }
+
+ if(time==256) {
+ for(i=16;i<32;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) SetReg3(Pdata,data);
+ }
+ si=32;
+ for(m=0;m<9;m++) {
+ di=si;
+ bx=si+0x04;
+ dl=0;
+ for(n=0;n<3;n++) {
+ for(o=0;o<5;o++) {
+ dh=table[si];
+ ah=table[di];
+ al=table[bx];
+ si++;
+ WriteDAC2(Pdata,dl,ah,al,dh);
+ } // for 5
+ si=si-2;
+ for(o=0;o<3;o++) {
+ dh=table[bx];
+ ah=table[di];
+ al=table[si];
+ si--;
+ WriteDAC2(Pdata,dl,ah,al,dh);
+ } // for 3
+ dl++;
+ } // for 3
+ si=si+5;
+ } // for 9
+ }
+}
+
+VOID WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh)
+{
+ USHORT temp;
+ USHORT bh,bl;
+
+ bh=ah;
+ bl=al;
+ if(dl!=0) {
+ temp=bh;
+ bh=dh;
+ dh=temp;
+ if(dl==1) {
+ temp=bl;
+ bl=dh;
+ dh=temp;
+ }
+ else {
+ temp=bl;
+ bl=bh;
+ bh=temp;
+ }
+ }
+ SetReg3(Pdata,(USHORT)dh);
+ SetReg3(Pdata,(USHORT)bh);
+ SetReg3(Pdata,(USHORT)bl);
+}
+
+VOID LockCRT2(USHORT BaseAddr)
+{
+ USHORT Part1Port;
+ USHORT Part4Port;
+ USHORT temp1;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ temp1=GetReg1(Part1Port,0x24);
+ temp1=temp1&0xFE;
+ SetReg1(Part1Port,0x24,temp1);
+}
+
+VOID SetLockRegs()
+{
+ USHORT temp1;
+
+ if((VBInfo&SetInSlaveMode)&&(!(VBInfo&SetCRT2ToRAMDAC))){
+ VBLongWait();
+ temp1=GetReg1(P3c4,0x32);
+ temp1=temp1|0x20;
+ SetReg1(P3c4,0x32,temp1);
+ VBLongWait();
+ }
+}
+
+VOID EnableBridge(USHORT BaseAddr)
+{
+ USHORT part2_02,part2_05;
+ USHORT Part2Port,Part1Port;
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+
+ if(IF_DEF_LVDS==0){
+ part2_02=(UCHAR)GetReg1(Part2Port,0x02);
+ part2_05=(UCHAR)GetReg1(Part2Port,0x05);
+ SetReg1(Part2Port,0x02,0x38);
+ SetReg1(Part2Port,0x05,0xFF);
+ LongWait();
+ SetRegANDOR(Part2Port,0x00,~0x0E0,0x020);
+ WaitVBRetrace(BaseAddr);
+ SetReg1(Part2Port,0x02,part2_02);
+ SetReg1(Part2Port,0x05,part2_05);
+ }else{
+ EnableCRT2();
+ UnLockCRT2(BaseAddr);
+ SetRegANDOR(Part1Port,0x02,~0x040,0x0);
+ }
+}
+
+USHORT GetLockInfo(USHORT pattern)
+{
+ USHORT temp1;
+ temp1=GetReg1(P3d4,0x36);
+ return(temp1&pattern);
+}
+
+VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr)
+{
+ USHORT flag1,tempbx,tempbl,tempbh,tempah;
+
+ SetFlag=0;
+ tempbx=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ tempbl=tempbx&ModeInfoFlag;
+ ModeType=tempbl;
+ tempbx=0;
+ flag1=GetReg1(P3c4,0x38); //call BridgeisOn
+ if(!(flag1&0x20)){
+ VBInfo=CRT2DisplayFlag;
+ return;
+ }
+ tempbl=GetReg1(P3d4,0x30);
+ tempbh=GetReg1(P3d4,0x31);
+ if(!(tempbl&0x07C)){
+ VBInfo=CRT2DisplayFlag;
+ return;
+ }
+ if(IF_DEF_LVDS==1){ //for LVDS
+ if(!(tempbl&SetCRT2ToLCD)){
+ VBInfo=CRT2DisplayFlag;
+ return;
+ }
+ }
+ if(IF_DEF_LVDS==0){ //for 301
+ if(tempbl&SetCRT2ToRAMDAC){
+ tempbl=tempbl&(SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode);
+ }else if(tempbl&SetCRT2ToLCD){
+ tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+ }else if(tempbl&SetCRT2ToSCART){
+ tempbl=tempbl&(SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode);
+ }else if(tempbl&SetCRT2ToHiVisionTV){
+ tempbl=tempbl&(SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode);
+ }
+ }else{ //for LVDS
+ if(tempbl&SetCRT2ToLCD){
+ tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+ }
+ }
+ tempah=GetReg1(P3d4,0x31);
+ if(tempah&(CRT2DisplayFlag>>8)){
+ if(!(tempbl&(SwitchToCRT2|SetSimuScanMode))){
+ tempbx=SetSimuScanMode|CRT2DisplayFlag;
+ tempbh=((tempbx&0xFF00)>>8);
+ tempbl=tempbx&0xFF;
+ }
+ }
+ if(!(tempbh&(DriverMode>>8))){
+ tempbl=tempbl|SetSimuScanMode;
+ }
+ VBInfo=tempbl|(tempbh<<8);
+ if(!(VBInfo&SetSimuScanMode)){
+ if(!(VBInfo&SwitchToCRT2)){
+ if(BridgeIsEnable(BaseAddr)){
+ if(BridgeInSlave()){
+ VBInfo=VBInfo|SetSimuScanMode;
+ }
+ }
+ }
+ }
+ if(!((VBInfo&(SetSimuScanMode|SwitchToCRT2)))){
+ return;
+ }
+ if(!(VBInfo&DriverMode)){
+ VBInfo=VBInfo|SetInSlaveMode;
+ if((VBInfo&SetCRT2ToTV)&&(!(VBInfo&SetNotSimuTVMode))){
+ SetFlag=SetFlag|TVSimuMode;
+ }
+ return;
+ }
+ flag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(!(flag1&(CRT2Mode|CRT2DisplayFlag))){
+ VBInfo=VBInfo|SetInSlaveMode;
+ if((VBInfo&SetCRT2ToTV)&&(!(VBInfo&SetNotSimuTVMode))){
+ SetFlag=SetFlag|TVSimuMode;
+ }
+ }
+}
+
+BOOLEAN BridgeIsEnable(USHORT BaseAddr)
+{
+ USHORT flag1;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+
+ if(IF_DEF_LVDS==1){
+ return 1;
+ }
+ flag1=GetReg1(P3c4,0x38); //call BridgeisOn
+ if(!(flag1&0x20)){ return 0;}
+ flag1=GetReg1(Part1Port,0x0);
+ if(flag1&0x0a0){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+BOOLEAN BridgeInSlave()
+{
+ USHORT flag1;
+ flag1=GetReg1(P3d4,0x31);
+ if(flag1&(SetInSlaveMode>>8)){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4)
+{
+ USHORT tempah,tempbh,tempflag;
+
+ tempah=(UCHAR)GetReg1(P3d4,0x36);
+ tempbh=tempah;
+ tempah=tempah&0x0F;
+ if(tempah>Panel1280x1024) tempah=Panel1024x768;
+ LCDResInfo=tempah;
+ tempbh=tempbh>>4;
+ LCDTypeInfo=tempbh;
+
+ tempah=(UCHAR)GetReg1(P3d4,0x37);
+ LCDInfo=tempah;
+ if(IF_DEF_TRUMPION){
+ LCDInfo=LCDInfo&(~LCDNonExpanding);
+ }
+ if(IF_DEF_LVDS==1){
+ tempflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(tempflag&HalfDCLK){
+ if(IF_DEF_TRUMPION==0){
+ if(!(LCDInfo&LCDNonExpanding)){
+ if(LCDResInfo==Panel1024x768){
+ tempflag=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo
+ if(tempflag==4){ //512x384
+ SetFlag=SetFlag|EnableLVDSDDA;
+ }
+ }else{
+ if(LCDResInfo==Panel800x600){
+ tempflag=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo
+ if(tempflag==3){ //400x300
+ SetFlag=SetFlag|EnableLVDSDDA;
+ }
+ }
+ }
+ }else{
+ SetFlag=SetFlag|EnableLVDSDDA;
+ }
+ }else{
+ SetFlag=SetFlag|EnableLVDSDDA;
+ }
+ }
+ }
+
+ if(!(VBInfo&SetCRT2ToLCD)){
+ return 1;
+ }
+ if(!(VBInfo&(SetSimuScanMode|SwitchToCRT2))){
+ return 1;
+ }
+ if(VBInfo&SetInSlaveMode){
+ if(VBInfo&SetNotSimuTVMode){
+ SetFlag=SetFlag|LCDVESATiming;
+ }
+ }else{
+ SetFlag=SetFlag|LCDVESATiming;
+ }
+ return 1;
+}
+
+VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ SetReg1(P3d4,0x37,0x00);
+}
+
+BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT tempah;
+ tempah=(HwDeviceExtension->usLCDType);// set in sisv.c
+ //0:no lcd 1:1024x768 2:1280x1024
+ if(tempah>0) tempah++; // usLCDType:
+ // 0:no lcd 1:800x600 2:1024x768 3:1280x1024
+ SetReg1(P3d4,0x36,tempah);//cr 36 0:no LCD 1:800x600 2:1024x768 3:1280x1024
+ if(tempah>0) return 1;
+ else return 0;
+}
+
+VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr)
+{
+ USHORT tempah,temp;
+
+ if(IF_DEF_LVDS==0){ //301
+ if(PRIMARY_VGA==1){ //primary vga
+ if(HwDeviceExtension->jChipID >= SIS_Trojan){
+ tempah=GetReg1(P3c4,0x17);
+ if(tempah&ModeSwitchStatus){
+ tempah=GetReg1(P3c4,0x16);
+ tempah=tempah&ActivePAL;
+ tempah=tempah>>ActivePALShift;
+ }else{
+ temp=*((UCHAR *)(ROMAddr+SoftSettingAddr));
+ if(temp&SoftTVType){
+ tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr));
+ }else{
+ tempah=GetReg1(P3c4,0x38); //SR 38
+ }
+ }
+ }else{
+ temp=*((UCHAR *)(ROMAddr+SoftSettingAddr));
+ if(temp&SoftTVType){
+ tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr));
+ }else{
+ tempah=GetReg1(P3c4,0x38); //SR 38
+ }
+ }
+ tempah=tempah&0x01; //get SR 38 D0 TV Type Selection
+ //0:NTSC 1:PAL
+ SetRegANDOR(P3d4,0x31,~0x01,tempah);//set CR 31 D0= SR 38 D0
+ }
+ else{ //Secondary
+ tempah=GetReg1(P3c4,0x38); //SR 38
+ tempah=tempah&0x01; //get SR 38 D0 TV Type Selection
+ //0:NTSC 1:PAL
+ SetRegANDOR(P3d4,0x31,~0x01,tempah);//set CR 31 D0= SR 38 D0
+ }
+ return;
+ }else{ //LVDS
+ tempah=GetReg1(P3c4,0x16); //SR 16
+ tempah=tempah&ActiveNonExpanding;
+ tempah=tempah>>ActiveNonExpandingShift;
+ tempah=tempah&0x01;
+ tempah=tempah<<LCDNonExpandingShift;
+ SetRegANDOR(P3d4,0x37,~LCDNonExpanding,tempah);
+ return;
+ }
+}
+
+BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr)
+{
+ USHORT flag1,tempbx,tempal,tempah,tempcx,i;
+ USHORT Part2Port,Part4Port;
+ USHORT RGBSenseData,YCSenseData,VideoSenseData;
+ USHORT P2reg0,SenseModeNo,OutputSelect;
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ RGBSenseData=*((USHORT *)(ROMAddr+0xF8)); //0:F8 in rompost.asm
+ YCSenseData=*((USHORT *)(ROMAddr+0xFA)); //0:FA in rompost.asm
+ VideoSenseData=*((USHORT *)(ROMAddr+0xFC)); //0:FC in rompost.asm
+
+ if(IF_DEF_LVDS==1){
+ GetPanelID();
+ tempah=LCDSense;
+ SetRegANDOR(P3d4,0x32,~0x5F,tempah); //Set CR 32
+ return 0;
+ }
+
+ flag1=GetReg1(P3c4,0x38); //call BridgeisOn
+ if(!(flag1&0x20)){ return 0;}
+ P2reg0=GetReg1(Part2Port,0x00); //save Part2 Reg index 0
+
+ if(!(BridgeIsEnable(BaseAddr))){
+ SenseModeNo=0x2E;
+ ModeType=ModeVGA;
+ VBInfo=SetCRT2ToRAMDAC;
+ SetFlag=0;
+ SetCRT2Group(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
+ //here perform I/O delay ,read SR 05
+ for(i=0;i<0x7FFF;i++){
+ flag1=GetReg1(P3c4,0x05);
+ }
+ }
+
+ SetReg1(Part2Port,0x00,0x1C); //Set part2 index 0= 0x1C
+ tempah=0;
+
+ OutputSelect=*((UCHAR *)(ROMAddr+0xFE)); //OutputSelect 0:FE in Rompost.asm
+ if(OutputSelect&SetSCARTOutput){
+ tempal=SCARTSense;
+ }else{
+ tempal=Monitor2Sense;
+ }
+ tempbx=RGBSenseData;
+ tempcx=0x0E08;
+ if(Sense(Part4Port,tempbx,tempcx)){
+ if(Sense(Part4Port,tempbx,tempcx)){
+ tempah=tempah|tempal;
+ }
+ }
+ tempbx=YCSenseData;
+ tempcx=0x0604;
+ if(Sense(Part4Port,tempbx,tempcx)){
+ if(Sense(Part4Port,tempbx,tempcx)){
+ tempah=tempah|SVIDEOSense;
+ //Skipped lines about HiTVSense, assuming not HiTV
+ }
+ }
+
+ //Assuming not HiTV ,below is of ifndef HiVisionTV
+ if(OutputSelect&BoardTVType){
+ tempbx=VideoSenseData;
+ tempcx=0x0804;
+ if(Sense(Part4Port,tempbx,tempcx)){
+ if(Sense(Part4Port,tempbx,tempcx)){
+ tempah=tempah|AVIDEOSense;
+ }
+ }
+ }else{
+ if(!(tempah&SVIDEOSense)){
+ tempbx=VideoSenseData;
+ tempcx=0x0804;
+ if(Sense(Part4Port,tempbx,tempcx)){
+ if(Sense(Part4Port,tempbx,tempcx)){
+ tempah=tempah|AVIDEOSense;
+ }
+ }
+ }
+ }
+ //end of ifndef HivisionTv
+ if(SenseLCD(HwDeviceExtension,Part4Port,ROMAddr)){
+ if(SenseLCD(HwDeviceExtension,Part4Port,ROMAddr)){
+ tempah=tempah|LCDSense;
+ }
+ }
+
+ tempbx=0;
+ tempcx=0;
+ Sense(Part4Port,tempbx,tempcx);
+
+ SetRegANDOR(P3d4,0x32,~0x5F,tempah); //Set CR 32
+ SetReg1(Part2Port,0x00,P2reg0); //recover Part2 reg index 0
+
+ //here skipped lines about DisableCRT2Display
+ return 0;
+}
+
+BOOLEAN Sense(USHORT Part4Port,USHORT inputbx,USHORT inputcx)
+{
+ USHORT tempah,tempcl,tempch;
+
+ tempah=inputbx&0xFF;
+ SetReg1(Part4Port,0x11,tempah);//Part4 index 11
+ tempah=(inputbx&0xFF00)>>8;
+ tempcl=inputcx&0xFF;
+ tempah=tempah|tempcl;
+ SetRegANDOR(Part4Port,0x10,~0x1F,tempah);//Part4 index 10
+
+ tempch=(inputcx&0xFF00)>>8;
+ tempch=tempch&0x7F;
+ //here skipped lines about call Delay
+ tempah=GetReg1(Part4Port,0x03); //Part4 index 03
+ tempah=tempah^(0x0E);
+ tempah=tempah&tempch;
+ if(tempah>0) return 1;
+ else return 0;
+}
+
+BOOLEAN SenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr)
+{
+ USHORT SoftSetting;
+ USHORT tempah;
+ SoftSetting=*((UCHAR *)(ROMAddr+0x52));//0:52 in rompost.asm
+ if(GetLCDDDCInfo(HwDeviceExtension)){
+ return 1;
+ }
+ if(SoftSetting&HotPlugFunction){
+ tempah=GetReg1(Part4Port,0x0F);
+ tempah=tempah&0x3F;
+ SetReg1(Part4Port,0x0F,tempah); //Part4 index 0F
+ if(Sense(Part4Port,0x0,0x9010)){
+ return 1;
+ }else{
+ return 0;
+ }
+ }else{
+ return 0;
+ }
+}
+#endif
+
+VOID SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR)
+{
+ USHORT temp1;
+ temp1=GetReg1(Port,Index); //part1port index 02
+ temp1=(temp1&(DataAND))|DataOR;
+ SetReg1(Port,Index,temp1);
+}
+
+BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT flag1 ;
+ USHORT DAC_TEST_PARMS[3]={0x0F,0x0F,0x0F};
+ USHORT DAC_CLR_PARMS[3]={0x00,0x00,0x00};
+
+ flag1=GetReg1(P3c4,0x38); //call BridgeisOn
+ if((flag1&0x20)){
+ SetReg1(P3d4,0x30,0x41);
+ }
+
+ SiSSetMode(HwDeviceExtension,0x2E); //set mode to 0x2E instead of 0x3
+
+ ClearDAC(P3c8);
+ ClearALLBuffer(HwDeviceExtension);
+
+ LongWait(); //wait vertical retrace
+ LongWait();
+
+ flag1=TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],
+ DAC_TEST_PARMS[2]);
+ if(flag1==0){
+ flag1=TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],
+ DAC_TEST_PARMS[2]);
+ }
+ if(flag1==1){
+ SetRegANDOR(P3d4,0x32,~Monitor1Sense,Monitor1Sense);
+ }else{
+ SetRegANDOR(P3d4,0x32,~Monitor1Sense,0x0);
+ }
+ TestMonitorType(DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]);
+
+ SetReg1(P3d4,0x34,0x4A); //Preset default CRT1 ModeNo =0x4A
+ //which is used in SetCRT2FIFO()
+ return 1;
+}
+
+BOOLEAN TestMonitorType(USHORT d1,USHORT d2,USHORT d3)
+{
+ USHORT temp;
+ SetReg3(P3c6,0xFF);
+ SetReg3(P3c8,0x00);
+ SetReg3(P3c9,d1);
+ SetReg3(P3c9,d2);
+ SetReg3(P3c9,d3);
+ WaitDisplay(); //wait horizontal retrace
+ temp=GetReg2(P3c2);
+ if(temp&0x10) return 1;
+ else return 0;
+}
+
+VOID WaitDisplay(void)
+{
+ USHORT temp;
+
+ for(temp=0;temp==0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x01;
+ }
+ for(;temp==1;){
+ temp=GetReg2(P3da);
+ temp=temp&0x01;
+ }
+}
+
+VOID LongWait(void)
+{
+ USHORT temp;
+
+ for(temp=1;temp>0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x08;
+ }
+ for(;temp==0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x08;
+ }
+}
+
+#ifndef CONFIG_FB_SIS_LINUXBIOS
+
+VOID VBLongWait(VOID)
+{
+ USHORT regsr1f,tempah,temp;
+
+ regsr1f=GetReg1(P3c4,0x1F);
+ tempah=regsr1f&(~0xC0);
+ SetReg1(P3c4,0x1F,tempah);
+
+ for(temp=1;temp>0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x08;
+ }
+ for(;temp==0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x08;
+ }
+
+ SetReg1(P3c4,0x1F,regsr1f);
+ return;
+}
+
+BOOLEAN WaitVBRetrace(USHORT BaseAddr)
+{
+ USHORT temp;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ temp=GetReg1(Part1Port,0x00);
+ if(!(temp&0x80)){
+ return 0;
+ }
+
+ for(temp=0;temp==0;){
+ temp=GetReg1(Part1Port,0x25);
+ temp=temp&0x01;
+ }
+ for(;temp>0;){
+ temp=GetReg1(Part1Port,0x25);
+ temp=temp&0x01;
+ }
+ return 1;
+}
+
+BOOLEAN GetPanelID(VOID)
+{
+ USHORT PanelTypeTable[16]={ SyncPP|Panel800x600|PanelType00,
+ SyncPP|Panel1024x768|PanelType01,
+ SyncPP|Panel1024x768|PanelType02,
+ SyncPP|Panel1024x768|PanelType03,
+ SyncPP|Panel1024x768|PanelType04,
+ SyncPP|Panel1024x768|PanelType05,
+ SyncPP|Panel1024x768|PanelType06,
+ SyncPP|Panel1024x768|PanelType07,
+ SyncPP|Panel1024x768|PanelType08,
+ SyncPP|Panel1024x768|PanelType09,
+ SyncPP|Panel800x600|PanelType0A,
+ SyncPP|Panel1024x768|PanelType0B,
+ SyncPP|Panel1024x768|PanelType0C,
+ SyncPP|Panel1024x768|PanelType0D,
+ SyncPP|Panel1024x768|PanelType0E,
+ SyncPP|Panel1024x768|PanelType0F};
+ // Bit 15 BPLVSPLTY
+ // Bit 14 BPLHSPLTY
+ // Bit 6-3 Panel Type
+ // Bit 2-0 Display Resolution(001:800x600 010:1024x768 011:1280x1024)
+ USHORT tempah,tempbx;
+ USHORT return_flag;
+
+ tempah=GetReg1(P3c4,0x18);
+ tempbx=tempah&0x0F;
+ if(tempah&0x10){
+ return_flag=1;
+ }else{
+ return_flag=0;
+ }
+
+ if(return_flag==0){
+ if(IF_DEF_LVDS==1){
+ tempbx=0;
+ tempah=GetReg1(P3c4,0x38);
+ if(tempah&0x40) tempbx=tempbx|0x08;
+ if(tempah&0x20) tempbx=tempbx|0x02;
+ if(tempah&0x01) tempbx=tempbx|0x01;
+ tempah=GetReg1(P3c4,0x39);
+ if(tempah&0x80) tempbx=tempbx|0x04;
+ }else{
+ return 0;
+ }
+ }
+
+ if(IF_DEF_TRUMPION==1){
+ tempbx=1;
+ }
+ tempbx=PanelTypeTable[tempbx]; //LVDS table entry
+ tempbx=tempbx|(USHORT)(LCDSync<<8);
+
+ tempah=tempbx&0x0FF;
+ SetReg1(P3d4,0x36,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ SetRegANDOR(P3d4,0x37,~LCDSyncBit,tempah);
+ return 1;
+}
+
+VOID ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT OldREFIndex,temp,tempah,i,modeflag1;
+
+ OldREFIndex=(USHORT)REFIndex;
+ temp=GetLVDSCRT1Ptr(ROMAddr,ModeNo);
+ if(temp==0){
+ REFIndex=OldREFIndex;
+ return;
+ }
+ tempah=(UCHAR)GetReg1(P3d4,0x11);//unlock cr0-7
+ tempah=tempah&0x7F;
+ SetReg1(P3d4,0x11,tempah);
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,0x0,tempah);
+ REFIndex++;
+ for(i=0x02;i<=0x05;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,i,tempah);
+ }
+ for(i=0x06;i<=0x07;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,i,tempah);
+ }
+ for(i=0x10;i<=0x11;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,i,tempah);
+ }
+ for(i=0x15;i<=0x16;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,i,tempah);
+ }
+
+ for(i=0x0A;i<=0x0C;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3c4,i,tempah);
+ }
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ tempah=tempah&0x0E0;
+ SetReg1(P3c4,0x0E,tempah);
+
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ tempah=tempah&0x01;
+ tempah=tempah<<5;
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&DoubleScanMode){
+ tempah=tempah|0x080;
+ }
+ SetRegANDOR(P3d4,0x09,~0x020,tempah);
+ REFIndex=OldREFIndex;
+ return;
+}
+
+VOID SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo)
+{
+ USHORT OldREFIndex,tempah,tempal;
+ USHORT P3cc=P3c9+3;
+ OldREFIndex=(USHORT)REFIndex;
+ if(IF_DEF_TRUMPION==0){ //no trumpion
+ tempal=GetReg2(P3cc);
+ tempal=tempal&0x0C;
+ SetReg3(P3c2,tempal);
+ REFIndex=GetVCLKPtr(ROMAddr,ModeNo);
+ }else{ //trumpion
+ SetFlag=SetFlag&(~ProgrammingCRT2);
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK
+ tempal=tempal&0x03F;
+ if(tempal==0x02){ //31.5MHz
+ REFIndex=REFIndex-Ext2StructSize;
+ }
+ REFIndex=GetVCLKPtr(ROMAddr,ModeNo);
+ SetFlag=SetFlag|ProgrammingCRT2;
+ }
+ tempal=0x02B;
+ if(!(VBInfo&SetInSlaveMode)){
+ tempal=tempal+3;
+ }
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3c4,tempal,tempah);
+ tempah=*((UCHAR *)(ROMAddr+REFIndex+1));
+ tempal++;
+ SetReg1(P3c4,tempal,tempah);
+ REFIndex=OldREFIndex;
+ return;
+}
+
+USHORT GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempcl,tempbx,tempal,tempptr,LVDSDesPtrData;
+ tempcl=LVDSDesDataLen;
+ tempbx=LCDTypeInfo;
+ if(LCDInfo&LCDNonExpanding){
+ tempbx=tempbx+16;
+ }
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC
+ }
+ tempal=tempal&0x1F;
+ tempal=tempal*tempcl;
+ tempbx=tempbx<<1;
+ LVDSDesPtrData=*((USHORT *)(ROMAddr+ADR_LVDSDesPtrData));
+ tempptr=*((USHORT *)(ROMAddr+LVDSDesPtrData+tempbx));
+ tempptr=tempptr+tempal;
+ return(tempptr);
+
+}
+
+BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempal,tempbx,modeflag1;
+ USHORT LVDSCRT1DataPtr;
+
+ if(!(VBInfo&SetInSlaveMode)){
+ return 0;
+ }
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC
+ }
+ tempal=tempal&0x3F;
+
+ tempbx=LCDResInfo;
+ tempbx=tempbx-Panel800x600;
+ if(LCDInfo&LCDNonExpanding){
+ tempbx=tempbx+6;
+ }
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&HalfDCLK){
+ tempbx=tempbx+3;
+ }
+ tempbx=tempbx<<1;
+ LVDSCRT1DataPtr=*((USHORT *)(ROMAddr+ADR_LVDSCRT1DataPtr));
+ REFIndex=*((USHORT *)(ROMAddr+LVDSCRT1DataPtr+tempbx));
+ tempal=tempal*LVDSCRT1Len;
+ REFIndex=REFIndex+tempal;
+ return 1;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+#include "initdef.h"
+
+USHORT SetFlag,RVBHCFACT,RVBHCMAX,VGAVT,VGAHT,VT,HT,VGAVDE,VGAHDE;
+USHORT VDE,HDE,RVBHRS,NewFlickerMode,RY1COE,RY2COE,RY3COE,RY4COE;
+;USHORT LCDResInfo,LCDTypeInfo,LCDInfo;
+USHORT VCLKLen;
+USHORT LCDHDES,LCDVDES;
+
+USHORT StResInfo[5][2]={{640,400},{640,350},{720,400},{720,350},{640,480}};
+
+USHORT ModeResInfo[15][4]={{320,200,8,8},{320,240,8,8},{320,400,8,8},
+ {400,300,8,8},{512,384,8,8},{640,400,8,16},
+ {640,480,8,16},{800,600,8,16},{1024,768,8,16},
+ {1280,1024,8,16},{1600,1200,8,16},{1920,1440,8,16},
+ {720,480,8,16},{720,576,8,16},{1280,960,8,16}};
+
+
+USHORT NTSCTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C,
+ 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A,
+ 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B,
+ 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017,
+ 0x088,0x000,0x04B,0x000,0x000,0x0E2,0x000,0x002,
+ 0x003,0x00A,0x065,0x09D,0x008,
+ 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C,
+ 0x060,0x014,0x050,0x000,0x040,
+ 0x00044,0x002DB,0x0003B};//Ajust xxx
+
+USHORT PALTiming[61]={ 0x019,0x052,0x035,0x06E,0x004,0x038,0x03D,0x070,
+ 0x094,0x049,0x001,0x012,0x006,0x03E,0x035,0x06D,
+ 0x006,0x014,0x03E,0x035,0x06D,0x000,0x045,0x02B,
+ 0x070,0x050,0x000,0x097,0x000,0x0D7,0x05D,0x017,
+ 0x088,0x000,0x045,0x000,0x000,0x0E8,0x000,0x002,
+ 0x00D,0x000,0x068,0x0B0,0x00B,
+ 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C,
+ 0x060,0x014,0x063,0x000,0x040,
+ 0x0003E,0x002E1,0x00028};//Ajust xxx
+
+USHORT HiTVTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C,
+ 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A,
+ 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B,
+ 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017,
+ 0x088,0x000,0x04B,0x000,0x000,0x0E2,0x000,0x002,
+ 0x003,0x00A,0x065,0x09D,0x008,
+ 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C,
+ 0x060,0x014,0x050,0x000,0x040,
+ 0x00027,0x0FFFC,0x0003B};//Ajust xxx
+
+USHORT HiTVTimingSimu[61]={0x020,0x054,0x02C,0x060,0x008,0x031,0x03A,0x061,
+ 0x028,0x002,0x001,0x03D,0x006,0x00D,0x004,0x00A,
+ 0x006,0x014,0x00D,0x004,0x00A,0x000,0x0C5,0x03F,
+ 0x064,0x090,0x000,0x0AA,0x000,0x006,0x060,0x003,
+ 0x011,0x005,0x011,0x00F,0x010,0x011,0x000,0x000,
+ 0x005,0x005,0x034,0x034,0x008,
+ 0x092,0x00F,0x040,0x060,0x080,0x014,0x090,0x08C,
+ 0x060,0x004,0x05F,0x000,0x060,
+ 0x0000E,0x0FFFC,0x00042};//Ajust xxx
+
+USHORT HiTVGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x05B,
+ 0x0FF,0x021,0x0AD,0x0AD,0x055,0x077,0x02A,0x0A6,
+ 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020,
+ 0x08C,0x06E,0x060,0x02D,0x056,0x047,0x070,0x044,
+ 0x056,0x036,0x04F,0x06E,0x03F,0x080,0x000,0x080,
+ 0x045,0x07D,0x003,0x0A5,0x076,0x020,0x01A,0x0A4,
+ 0x014,0x005,0x003,0x07E,0x064,0x031,0x014,0x075,
+ 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001};
+
+USHORT HiTVGroup3Simu[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x094,
+ 0x0DA,0x020,0x0B7,0x0B7,0x055,0x047,0x02A,0x0A6,
+ 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020,
+ 0x08C,0x06E,0x060,0x015,0x026,0x0D3,0x0E4,0x011,
+ 0x056,0x036,0x04F,0x06E,0x03F,0x080,0x000,0x080,
+ 0x066,0x035,0x001,0x047,0x00E,0x010,0x0BE,0x0B4,
+ 0x001,0x005,0x003,0x07E,0x065,0x031,0x014,0x075,
+ 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001};
+
+USHORT NTSCGroup3Data[63]= {0x000,0x014,0x015,0x025,0x055,0x015,0x00B,0x089,
+ 0x0D7,0x040,0x0B0,0x0B0,0x0FF,0x0C4,0x045,0x0A6,
+ 0x025,0x02F,0x067,0x0F6,0x0BF,0x0FF,0x08E,0x020,
+ 0x08C,0x0DA,0x060,0x092,0x0C8,0x055,0x08B,0x000,
+ 0x051,0x004,0x018,0x00A,0x0F8,0x087,0x000,0x080,
+ 0x03B,0x03B,0x000,0x0F0,0x0F0,0x000,0x0F0,0x0F0,
+ 0x000,0x051,0x00F,0x00F,0x008,0x00F,0x008,0x06F,
+ 0x018,0x005,0x005,0x005,0x04C,0x0AA,0x001};
+
+USHORT PALGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x085,
+ 0x0C3,0x020,0x0A4,0x0A4,0x055,0x047,0x02A,0x0A6,
+ 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020,
+ 0x08C,0x0DC,0x060,0x092,0x0C8,0x04F,0x085,0x000,
+ 0x056,0x036,0x04F,0x06E,0x0FE,0x083,0x054,0x081,
+ 0x030,0x030,0x000,0x0F3,0x0F3,0x000,0x0A2,0x0A2,
+ 0x000,0x048,0x0FE,0x07E,0x008,0x040,0x008,0x091,
+ 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001};
+
+VOID overwriteregs(ULONG ROMAddr, USHORT BaseAddr);
+VOID SetDefCRT2ExtRegs(USHORT BaseAddr);
+BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+USHORT GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo);
+BOOLEAN AjustCRT2Rate(ULONG ROMAddr);
+VOID SaveCRT2Info(USHORT ModeNo);
+VOID DisableLockRegs(VOID);
+VOID DisableCRT2(VOID);
+VOID DisableBridge(USHORT BaseAddr);
+VOID GetCRT2Data(ULONG ROMAddr,USHORT ModeNo);
+VOID GetResInfo(ULONG ROMAddr,USHORT ModeNo);
+VOID GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo);
+VOID GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo);
+VOID UnLockCRT2(USHORT BaseAddr);
+VOID SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo);
+VOID SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr);
+USHORT GetOffset(ULONG ROMAddr);
+USHORT GetColorDepth(ULONG ROMAddr);
+VOID SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+USHORT GetVCLK(ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+USHORT GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo);
+USHORT GetColorTh(ULONG ROMAddr);
+USHORT GetMCLK(ULONG ROMAddr);
+USHORT GetMCLKPtr(ULONG ROMAddr);
+USHORT GetDRAMType(ULONG ROMAddr);
+#ifndef CONFIG_FB_SIS_LINUXBIOS
+static USHORT CalcDelay(VOID);
+#endif
+USHORT GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo);
+VOID SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
+VOID GetCRT1Ptr(ULONG ROMAddr);
+VOID SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR);
+USHORT GetVGAHT2(VOID);
+VOID SetGroup2(USHORT BaseAddr,ULONG ROMAddr);
+VOID SetGroup3(USHORT BaseAddr);
+VOID SetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
+VOID SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
+VOID SetGroup5(USHORT BaseAddr,ULONG ROMAddr);
+VOID EnableCRT2(VOID);
+VOID LoadDAC2(ULONG ROMAddr,USHORT Part5Port);
+VOID WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh);
+VOID LockCRT2(USHORT BaseAddr);
+VOID SetLockRegs(VOID);
+VOID EnableBridge(USHORT BaseAddr);
+USHORT GetLockInfo(USHORT pattern);
+VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr);
+BOOLEAN BridgeIsEnable(USHORT BaseAddr);
+BOOLEAN BridgeInSlave(VOID);
+BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4);
+VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension);
+BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr);
+BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr);
+BOOLEAN Sense(USHORT Part4Port,USHORT inputbx,USHORT inputcx);
+BOOLEAN SenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr);
+BOOLEAN TestMonitorType(USHORT d1,USHORT d2,USHORT d3);
+VOID WaitDisplay(VOID);
+BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID LongWait(VOID);
+//VOID ClearALLBuffer(PHW_DEVICE_EXTENSION HwDeviceExtension);
+USHORT GetQueueConfig(VOID);
+VOID VBLongWait(VOID);
+USHORT GetVCLKLen(ULONG ROMAddr);
+BOOLEAN WaitVBRetrace(USHORT BaseAddr);
+VOID GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo);
+VOID ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo);
+VOID SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo);
+VOID GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo);
+VOID GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo);
+USHORT GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo);
+VOID SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID SetTPData(VOID);
+BOOLEAN GetPanelID(VOID);
+BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo);
+
+extern USHORT DRAMType[17][5];
+extern USHORT MDA_DAC[];
+extern USHORT CGA_DAC[];
+extern USHORT EGA_DAC[];
+extern USHORT VGA_DAC[];
+
+extern USHORT P3c4,P3d4,P3c0,P3ce,P3c2,P3ca,P3c6,P3c7,P3c8,P3c9,P3da;
+extern USHORT flag_clearbuffer; //0:no clear frame buffer 1:clear frame buffer
+extern int RAMType;
+extern int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,VCLKData,MCLKData, ECLKData;
+extern int REFIndex,ModeType;
+extern USHORT VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo;
+extern USHORT IF_DEF_LVDS,IF_DEF_TRUMPION;
+
+extern VOID SetMemoryClock(ULONG);
+extern VOID SetDRAMSize(PHW_DEVICE_EXTENSION);
+extern BOOLEAN SearchModeID(ULONG, USHORT);
+extern BOOLEAN CheckMemorySize(ULONG);
+extern VOID GetModePtr(ULONG, USHORT);
+extern BOOLEAN GetRatePtr(ULONG, USHORT);
+extern VOID SetSeqRegs(ULONG);
+extern VOID SetMiscRegs(ULONG);
+extern VOID SetCRTCRegs(ULONG);
+extern VOID SetATTRegs(ULONG);
+extern VOID SetGRCRegs(ULONG);
+extern VOID ClearExt1Regs(VOID);
+extern VOID SetSync(ULONG);
+extern VOID SetCRT1CRTC(ULONG);
+extern VOID SetCRT1Offset(ULONG);
+extern VOID SetCRT1FIFO(ULONG);
+extern VOID SetCRT1VCLK(ULONG);
+extern VOID LoadDAC(ULONG);
+extern VOID DisplayOn(VOID);
+extern VOID SetCRT1ModeRegs(ULONG, USHORT);
+extern VOID SetVCLKState(ULONG, USHORT);
+extern VOID WriteDAC(USHORT, USHORT, USHORT, USHORT);
+extern VOID ClearBuffer(PHW_DEVICE_EXTENSION);
+//extern VOID ClearDAC(ULONG);
+extern void ClearDAC(u16 port);
+extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo);
+extern void SetReg1(u16 port, u16 index, u16 data);
+extern void SetReg3(u16 port, u16 data);
+extern void SetReg4(u16 port, unsigned long data);
+extern u8 GetReg1(u16 port, u16 index);
+extern u8 GetReg2(u16 port);
+extern u32 GetReg3(u16 port);
--- /dev/null
+/*
+ * SiS 300/630/540 frame buffer device For Kernal 2.4.x
+ *
+ * This driver is partly based on the VBE 2.0 compliant graphic
+ * boards framebuffer driver, which is
+ *
+ * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#define EXPORT_SYMTAB
+#undef SISFBDEBUG
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vt_kern.h>
+#include <linux/capability.h>
+#include <linux/sisfb.h>
+#include <linux/fs.h>
+
+#include <asm/io.h>
+#include <asm/mtrr.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "sis.h"
+#ifdef NOBIOS
+#include "bios.h"
+#endif
+
+/* ------------------- Constant Definitions ------------------------- */
+
+/* capabilities */
+#define TURBO_QUEUE_CAP 0x80
+#define HW_CURSOR_CAP 0x40
+
+/* VGA register Offsets */
+#define SEQ_ADR (0x14)
+#define SEQ_DATA (0x15)
+#define DAC_ADR (0x18)
+#define DAC_DATA (0x19)
+#define CRTC_ADR (0x24)
+#define CRTC_DATA (0x25)
+
+#define DAC2_ADR 0x16 - 0x30
+#define DAC2_DATA 0x17 - 0x30
+
+
+/* SiS indexed register indexes */
+#define IND_SIS_PASSWORD (0x05)
+#define IND_SIS_DRAM_SIZE (0x14)
+#define IND_SIS_MODULE_ENABLE (0x1E)
+#define IND_SIS_PCI_ADDRESS_SET (0x20)
+#define IND_SIS_TURBOQUEUE_ADR (0x26)
+#define IND_SIS_TURBOQUEUE_SET (0x27)
+
+/* Sis register value */
+#define SIS_PASSWORD (0x86)
+
+#define SIS_2D_ENABLE (0x40)
+
+#define SIS_MEM_MAP_IO_ENABLE (0x01)
+#define SIS_PCI_ADDR_ENABLE (0x80)
+
+//#define MMIO_SIZE 0x10000 /* 64K MMIO capability */
+#define MAX_ROM_SCAN 0x10000
+
+#define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
+#define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
+
+/* Mode set stuff */
+#define DEFAULT_MODE 0 /* 640x480x8 */
+#define DEFAULT_LCDMODE 9 /* 800x600x8 */
+#define DEFAULT_TVMODE 9 /* 800x600x8 */
+
+/* heap stuff */
+#define OH_ALLOC_SIZE 4000
+#define SENTINEL 0x7fffffff
+
+#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
+#define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
+
+/* ------------------- Global Variables ----------------------------- */
+
+struct video_info ivideo;
+HW_DEVICE_EXTENSION HwExt={0,0,0,0,0,0};
+
+struct GlyInfo {
+ unsigned char ch;
+ int fontwidth;
+ int fontheight;
+ u8 gmask[72];
+ int ngmask;
+};
+
+/* Supported SiS Chips list */
+static struct board {
+ u16 vendor, device;
+ const char *name;
+} dev_list[] = {
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730_VGA, "SIS 730"},
+ {0, 0, NULL}
+};
+
+/* card parameters */
+unsigned long rom_base;
+unsigned long rom_vbase;
+
+/* mode */
+static int video_type = FB_TYPE_PACKED_PIXELS;
+static int video_linelength;
+static int video_cmap_len;
+static int sisfb_off = 0;
+static int crt1off = 0;
+
+static struct fb_var_screeninfo default_var = {
+ 0, 0, 0, 0,
+ 0, 0,
+ 0,
+ 0,
+ {0, 8, 0},
+ {0, 8, 0},
+ {0, 8, 0},
+ {0, 0, 0},
+ 0,
+ FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ {0, 0, 0, 0, 0, 0}
+};
+
+static struct display disp;
+static struct fb_info fb_info;
+static struct {
+ u16 blue, green, red, pad;
+} palette[256];
+static union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+} fbcon_cmap;
+
+static int inverse = 0;
+static int currcon = 0;
+
+static struct display_switch sisfb_sw;
+
+static u8 caps = 0;
+static unsigned long MMIO_SIZE = 0;
+
+/* ModeSet stuff */
+unsigned char uDispType = 0;
+int mode_idx = -1;
+u8 mode_no = 0;
+u8 rate_idx = 0;
+
+static const struct _sisbios_mode {
+ char name[15];
+ u8 mode_no;
+ u16 xres;
+ u16 yres;
+ u16 bpp;
+ u16 rate_idx;
+ u16 cols;
+ u16 rows;
+} sisbios_mode[] = {
+ {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30},
+ {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30},
+ {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30},
+ {"720x480x8", 0x31, 720, 480, 8, 1, 90, 30}, /* NTSC TV */
+ {"720x480x16", 0x33, 720, 480, 16, 1, 90, 30},
+ {"720x480x32", 0x35, 720, 480, 32, 1, 90, 30},
+ {"720x576x8", 0x32, 720, 576, 8, 1, 90, 36}, /* PAL TV */
+ {"720x576x16", 0x34, 720, 576, 16, 1, 90, 36},
+ {"720x576x32", 0x36, 720, 576, 32, 1, 90, 36},
+ {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37},
+ {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37},
+ {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37},
+ {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48},
+ {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48},
+ {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48},
+ {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64},
+ {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
+ {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
+ {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75},
+ {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
+ {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
+ {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75},
+ {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
+ {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
+ {"\0", 0x00, 0, 0, 0, 0, 0, 0}
+};
+
+static struct _vrate {
+ u16 idx;
+ u16 xres;
+ u16 yres;
+ u16 refresh;
+} vrate[] = {
+ {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85},
+ {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200},
+ {1, 720, 480, 60},
+ {1, 720, 576, 50},
+ {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75},
+ {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160},
+ {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75},
+ {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
+ {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
+ {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
+ {5, 1600, 1200, 85},
+ {1, 1920, 1440, 60},
+ {0, 0, 0, 0}
+};
+
+
+/* HEAP stuff */
+
+struct OH {
+ struct OH *pohNext;
+ struct OH *pohPrev;
+ unsigned long ulOffset;
+ unsigned long ulSize;
+};
+
+struct OHALLOC {
+ struct OHALLOC *pohaNext;
+ struct OH aoh[1];
+};
+
+struct HEAP {
+ struct OH ohFree;
+ struct OH ohUsed;
+ struct OH *pohFreeList;
+ struct OHALLOC *pohaChain;
+
+ unsigned long ulMaxFreeSize;
+};
+
+struct HEAP heap;
+unsigned long heap_start;
+unsigned long heap_end;
+unsigned long heap_size;
+
+unsigned int tqueue_pos;
+unsigned long hwcursor_vbase;
+
+
+/* -------------------- Macro definitions --------------------------- */
+
+#ifdef SISFBDEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define vgawb(reg,data) \
+ (outb(data, ivideo.vga_base+reg))
+#define vgaww(reg,data) \
+ (outw(data, ivideo.vga_base+reg))
+#define vgawl(reg,data) \
+ (outl(data, ivideo.vga_base+reg))
+#define vgarb(reg) \
+ (inb(ivideo.vga_base+reg))
+
+/* ---------------------- Routine Prototype ------------------------- */
+
+/* Interface used by the world */
+int sisfb_setup(char *options);
+static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int sisfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info);
+
+/* Interface to the low level console driver */
+int sisfb_init(void);
+static int sisfb_update_var(int con, struct fb_info *info);
+static int sisfb_switch(int con, struct fb_info *info);
+static void sisfb_blank(int blank, struct fb_info *info);
+
+/* Internal routines */
+static void crtc_to_var(struct fb_var_screeninfo *var);
+static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
+static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *fb_info);
+static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *fb_info);
+static void do_install_cmap(int con, struct fb_info *info);
+static int do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info);
+
+/* set-mode routines */
+void SetReg1(u16 port, u16 index, u16 data);
+void SetReg3(u16 port, u16 data);
+void SetReg4(u16 port, unsigned long data);
+u8 GetReg1(u16 port, u16 index);
+u8 GetReg2(u16 port);
+u32 GetReg3(u16 port);
+extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo);
+extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension);
+static void pre_setmode(void);
+static void post_setmode(void);
+static void search_mode(const char *name);
+static u8 search_refresh_rate(unsigned int rate);
+
+/* heap routines */
+static int sisfb_heap_init(void);
+static struct OH *poh_new_node(void);
+static struct OH *poh_allocate(unsigned long size);
+static struct OH *poh_free(unsigned long base);
+static void delete_node(struct OH *poh);
+static void insert_node(struct OH *pohList, struct OH *poh);
+static void free_node(struct OH *poh);
+
+/* ---------------------- Internal Routines ------------------------- */
+
+inline static u32 RD32(unsigned char *base, s32 off)
+{
+ return readl(base + off);
+}
+
+inline static void WR32(unsigned char *base, s32 off, u32 v)
+{
+ writel(v, base + off);
+}
+
+inline static void WR16(unsigned char *base, s32 off, u16 v)
+{
+ writew(v, base + off);
+}
+
+inline static void WR8(unsigned char *base, s32 off, u8 v)
+{
+ writeb(v, base + off);
+}
+
+inline static u32 regrl(s32 off)
+{
+ return RD32(ivideo.mmio_vbase, off);
+}
+
+inline static void regwl(s32 off, u32 v)
+{
+ WR32(ivideo.mmio_vbase, off, v);
+}
+
+inline static void regww(s32 off, u16 v)
+{
+ WR16(ivideo.mmio_vbase, off, v);
+}
+
+inline static void regwb(s32 off, u8 v)
+{
+ WR8(ivideo.mmio_vbase, off, v);
+}
+
+/*
+ * Get CRTC registers to set var
+ */
+static void crtc_to_var(struct fb_var_screeninfo *var)
+{
+ u16 VRE, VBE, VRS, VBS, VDE, VT;
+ u16 HRE, HBE, HRS, HBS, HDE, HT;
+ u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;
+ int A, B, C, D, E, F, temp;
+ double hrate, drate;
+
+ vgawb(SEQ_ADR, 0x6);
+ uSRdata = vgarb(SEQ_DATA);
+
+ if (uSRdata & 0x20)
+ var->vmode = FB_VMODE_INTERLACED;
+ else
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ switch ((uSRdata & 0x1c) >> 2) {
+ case 0:
+ var->bits_per_pixel = 8;
+ break;
+ case 2:
+ var->bits_per_pixel = 16;
+ break;
+ case 4:
+ var->bits_per_pixel = 32;
+ break;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ video_cmap_len = 256;
+ break;
+ case 16: /* RGB 565 */
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ video_cmap_len = 16;
+
+ break;
+ case 24: /* RGB 888 */
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ video_cmap_len = 16;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ video_cmap_len = 16;
+ break;
+ }
+
+ vgawb(SEQ_ADR, 0xa);
+ uSRdata = vgarb(SEQ_DATA);
+
+ vgawb(CRTC_ADR, 0x6);
+ uCRdata = vgarb(CRTC_DATA);
+ vgawb(CRTC_ADR, 0x7);
+ uCRdata2 = vgarb(CRTC_DATA);
+ VT =
+ (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |
+ ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<
+ 10);
+ A = VT + 2;
+
+ vgawb(CRTC_ADR, 0x12);
+ uCRdata = vgarb(CRTC_DATA);
+ VDE =
+ (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |
+ ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);
+ E = VDE + 1;
+
+ vgawb(CRTC_ADR, 0x10);
+ uCRdata = vgarb(CRTC_DATA);
+ VRS =
+ (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |
+ ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);
+ F = VRS + 1 - E;
+
+ vgawb(CRTC_ADR, 0x15);
+ uCRdata = vgarb(CRTC_DATA);
+ vgawb(CRTC_ADR, 0x9);
+ uCRdata3 = vgarb(CRTC_DATA);
+ VBS =
+ (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |
+ ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);
+
+ vgawb(CRTC_ADR, 0x16);
+ uCRdata = vgarb(CRTC_DATA);
+ VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);
+ temp = VBE - ((E - 1) & 511);
+ B = (temp > 0) ? temp : (temp + 512);
+
+ vgawb(CRTC_ADR, 0x11);
+ uCRdata = vgarb(CRTC_DATA);
+ VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);
+ temp = VRE - ((E + F - 1) & 31);
+ C = (temp > 0) ? temp : (temp + 32);
+
+ D = B - F - C;
+
+ var->yres = var->yres_virtual = E;
+ var->upper_margin = D;
+ var->lower_margin = F;
+ var->vsync_len = C;
+
+ vgawb(SEQ_ADR, 0xb);
+ uSRdata = vgarb(SEQ_DATA);
+
+ vgawb(CRTC_ADR, 0x0);
+ uCRdata = vgarb(CRTC_DATA);
+ HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);
+ A = HT + 5;
+
+ vgawb(CRTC_ADR, 0x1);
+ uCRdata = vgarb(CRTC_DATA);
+ HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);
+ E = HDE + 1;
+
+ vgawb(CRTC_ADR, 0x4);
+ uCRdata = vgarb(CRTC_DATA);
+ HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);
+ F = HRS - E - 3;
+
+ vgawb(CRTC_ADR, 0x2);
+ uCRdata = vgarb(CRTC_DATA);
+ HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);
+
+ vgawb(SEQ_ADR, 0xc);
+ uSRdata = vgarb(SEQ_DATA);
+ vgawb(CRTC_ADR, 0x3);
+ uCRdata = vgarb(CRTC_DATA);
+ vgawb(CRTC_ADR, 0x5);
+ uCRdata2 = vgarb(CRTC_DATA);
+ HBE =
+ (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |
+ ((u16) (uSRdata & 0x03) << 6);
+ HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);
+
+ temp = HBE - ((E - 1) & 255);
+ B = (temp > 0) ? temp : (temp + 256);
+
+ temp = HRE - ((E + F + 3) & 63);
+ C = (temp > 0) ? temp : (temp + 64);
+
+ D = B - F - C;
+
+ var->xres = var->xres_virtual = E * 8;
+ var->left_margin = D * 8;
+ var->right_margin = F * 8;
+ var->hsync_len = C * 8;
+
+ var->activate = FB_ACTIVATE_NOW;
+
+ var->sync = 0;
+
+ uMRdata = vgarb(0x1C);
+ if (uMRdata & 0x80)
+ var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ else
+ var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ if (uMRdata & 0x40)
+ var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ else
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+ VT += 2;
+ VT <<= 1;
+ HT = (HT + 5) * 8;
+
+ hrate = (double) ivideo.refresh_rate * (double) VT / 2;
+ drate = hrate * HT;
+ var->pixclock = (u32) (1E12 / drate);
+}
+
+static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+ struct display_switch *sw;
+ u32 flags;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &disp; /* used during initialization */
+
+ sisfb_get_fix(&fix, con, 0);
+
+ display->screen_base = ivideo.video_vbase;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ /*display->can_soft_blank = 1; */
+ display->can_soft_blank = 0;
+ display->inverse = inverse;
+ display->var = *var;
+
+ save_flags(flags);
+ switch (ivideo.video_bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ sw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 15:
+ case 16:
+ sw = &fbcon_cfb16;
+ display->dispsw_data = fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ sw = &fbcon_cfb24;
+ display->dispsw_data = fbcon_cmap.cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ sw = &fbcon_cfb32;
+ display->dispsw_data = fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ sw = &fbcon_dummy;
+ return;
+ }
+ memcpy(&sisfb_sw, sw, sizeof(*sw));
+ display->dispsw = &sisfb_sw;
+ restore_flags(flags);
+
+ display->scrollmode = SCROLL_YREDRAW;
+ sisfb_sw.bmove = fbcon_redraw_bmove;
+
+}
+
+/*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
+ unsigned *transp, struct fb_info *fb_info)
+{
+ if (regno >= video_cmap_len)
+ return 1;
+
+ *red = palette[regno].red;
+ *green = palette[regno].green;
+ *blue = palette[regno].blue;
+ *transp = 0;
+ return 0;
+}
+
+/*
+ * Set a single color register. The values supplied are already
+ * rounded down to the hardware's capabilities (according to the
+ * entries in the var structure). Return != 0 for invalid regno.
+ */
+static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *fb_info)
+{
+
+ if (regno >= video_cmap_len)
+ return 1;
+
+ palette[regno].red = red;
+ palette[regno].green = green;
+ palette[regno].blue = blue;
+
+ switch (ivideo.video_bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ vgawb(DAC_ADR, regno);
+ vgawb(DAC_DATA, red >> 10);
+ vgawb(DAC_DATA, green >> 10);
+ vgawb(DAC_DATA, blue >> 10);
+ if(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ /* VB connected */
+ vgawb(DAC2_ADR, regno);
+ vgawb(DAC2_DATA, red >> 8);
+ vgawb(DAC2_DATA, green >> 8);
+ vgawb(DAC2_DATA, blue >> 8);
+ }
+
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 15:
+ case 16:
+ fbcon_cmap.cfb16[regno] =
+ ((red & 0xf800)) |
+ ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fbcon_cmap.cfb24[regno] =
+ (red << 16) | (green << 8) | (blue);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fbcon_cmap.cfb32[regno] =
+ (red << 16) | (green << 8) | (blue);
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+ if (con != currcon)
+ return;
+
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
+ sis_setcolreg, info);
+}
+
+static int do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info)
+{
+ unsigned int htotal =
+ var->left_margin + var->xres + var->right_margin +
+ var->hsync_len;
+ unsigned int vtotal =
+ var->upper_margin + var->yres + var->lower_margin +
+ var->vsync_len;
+ double drate = 0, hrate = 0;
+ int found_mode = 0;
+ int old_mode;
+
+ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
+ vtotal <<= 1;
+ else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+ vtotal <<= 2;
+ else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+ var->yres <<= 1;
+
+
+ if (!htotal || !vtotal) {
+ DPRINTK("Invalid 'var' Information!\n");
+ return 1;
+ }
+
+ drate = 1E12 / var->pixclock;
+ hrate = drate / htotal;
+ ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
+
+ old_mode = mode_idx;
+ mode_idx = 0;
+
+ while ((sisbios_mode[mode_idx].mode_no != 0)
+ && (sisbios_mode[mode_idx].xres <= var->xres)) {
+ if ((sisbios_mode[mode_idx].xres == var->xres)
+ && (sisbios_mode[mode_idx].yres == var->yres)
+ && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) {
+ mode_no = sisbios_mode[mode_idx].mode_no;
+ found_mode = 1;
+ break;
+ }
+ mode_idx++;
+ }
+
+ if(found_mode)
+ {
+ switch(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ case MASK_DISPTYPE_LCD:
+ switch(HwExt.usLCDType)
+ {
+ case LCD1024:
+ if(var->xres > 1024)
+ found_mode = 0;
+ break;
+ case LCD1280:
+ if(var->xres > 1280)
+ found_mode = 0;
+ break;
+ case LCD2048:
+ if(var->xres > 2048)
+ found_mode = 0;
+ break;
+ case LCD1920:
+ if(var->xres > 1920)
+ found_mode = 0;
+ break;
+ case LCD1600:
+ if(var->xres > 1600)
+ found_mode = 0;
+ break;
+ case LCD800:
+ if(var->xres > 800)
+ found_mode = 0;
+ break;
+ case LCD640:
+ if(var->xres > 640)
+ found_mode = 0;
+ break;
+ default:
+ found_mode = 0;
+ }
+ if(var->xres == 720) /* mode only for TV */
+ found_mode = 0;
+ break;
+ case MASK_DISPTYPE_TV:
+ switch(var->xres)
+ {
+ case 800:
+ case 640:
+ break;
+ case 720:
+ if(ivideo.TV_type == TVMODE_NTSC)
+ {
+ if(sisbios_mode[mode_idx].yres != 480)
+ found_mode = 0;
+ }
+ else if(ivideo.TV_type == TVMODE_PAL)
+ {
+ if(sisbios_mode[mode_idx].yres != 576)
+ found_mode = 0;
+ }
+ break;
+ default:
+ /* illegal mode */
+ found_mode = 0;
+ }
+ break;
+ }
+ }
+
+ if (!found_mode) {
+ printk("sisfb does not support mode %dx%d-%d\n", var->xres,
+ var->yres, var->bits_per_pixel);
+ mode_idx = old_mode;
+ return 1;
+ }
+
+ if (search_refresh_rate(ivideo.refresh_rate) == 0) {
+ /* not supported rate */
+ rate_idx = sisbios_mode[mode_idx].rate_idx;
+ ivideo.refresh_rate = 60;
+ }
+
+ if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
+ pre_setmode();
+
+ if (SiSSetMode(&HwExt, mode_no)) {
+ DPRINTK("sisfb: set mode[0x%x]: failed\n",
+ mode_no);
+ return 1;
+ }
+
+ post_setmode();
+
+ printk(KERN_DEBUG "Current Mode: %dx%dx%d-%d \n", sisbios_mode[mode_idx].xres,
+ sisbios_mode[mode_idx].yres, sisbios_mode[mode_idx].bpp, ivideo.refresh_rate);
+
+ ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
+ ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres;
+ ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres;
+ ivideo.org_x = ivideo.org_y = 0;
+ video_linelength =
+ ivideo.video_width * (ivideo.video_bpp >> 3);
+
+ DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
+ ivideo.video_width, ivideo.video_height,
+ ivideo.video_bpp, video_linelength);
+ }
+
+ return 0;
+}
+
+/* ---------------------- Draw Funtions ----------------------------- */
+
+static void sis_get_glyph(struct GlyInfo *gly)
+{
+ struct display *p = &fb_display[currcon];
+ u16 c;
+ u8 *cdat;
+ int widthb;
+ u8 *gbuf = gly->gmask;
+ int size;
+
+
+ gly->fontheight = fontheight(p);
+ gly->fontwidth = fontwidth(p);
+ widthb = (fontwidth(p) + 7) / 8;
+
+ c = gly->ch & p->charmask;
+ if (fontwidth(p) <= 8)
+ cdat = p->fontdata + c * fontheight(p);
+ else
+ cdat = p->fontdata + (c * fontheight(p) << 1);
+
+ size = fontheight(p) * widthb;
+ memcpy(gbuf, cdat, size);
+ gly->ngmask = size;
+}
+
+
+/* ---------------------- HEAP Routines ----------------------------- */
+
+/*
+ * Heap Initialization
+ */
+
+static int sisfb_heap_init(void)
+{
+ struct OH *poh;
+ u8 jTemp, tq_state;
+
+ if(ivideo.video_size > 0x800000)
+ /* video ram is large than 8M */
+ heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
+ else
+ heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
+
+ heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
+ heap_size = heap_end - heap_start;
+
+
+ /* Setting for Turbo Queue */
+ if (heap_size >= TURBO_QUEUE_AREA_SIZE) {
+ tqueue_pos =
+ (ivideo.video_size -
+ TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
+ jTemp = (u8) (tqueue_pos & 0xff);
+ vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
+ tq_state = vgarb(SEQ_DATA);
+ tq_state |= 0xf0;
+ tq_state &= 0xfc;
+ tq_state |= (u8) (tqueue_pos >> 8);
+ vgawb(SEQ_DATA, tq_state);
+ vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
+ vgawb(SEQ_DATA, jTemp);
+
+ caps |= TURBO_QUEUE_CAP;
+
+ heap_end -= TURBO_QUEUE_AREA_SIZE;
+ heap_size -= TURBO_QUEUE_AREA_SIZE;
+ }
+
+ /* Setting for HW cursor(4K) */
+ if (heap_size >= HW_CURSOR_AREA_SIZE) {
+ heap_end -= HW_CURSOR_AREA_SIZE;
+ heap_size -= HW_CURSOR_AREA_SIZE;
+ hwcursor_vbase = heap_end;
+
+ caps |= HW_CURSOR_CAP;
+ }
+
+ heap.pohaChain = NULL;
+ heap.pohFreeList = NULL;
+
+ poh = poh_new_node();
+
+ if (poh == NULL)
+ return 1;
+
+ /* The first node describles the entire heap size */
+ poh->pohNext = &heap.ohFree;
+ poh->pohPrev = &heap.ohFree;
+ poh->ulSize = heap_end - heap_start + 1;
+ poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase;
+
+ DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
+ (char *) heap_start, (char *) heap_end,
+ (unsigned int) poh->ulSize / 1024);
+
+ DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
+ (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024);
+
+ /* The second node in our free list sentinel */
+ heap.ohFree.pohNext = poh;
+ heap.ohFree.pohPrev = poh;
+ heap.ohFree.ulSize = 0;
+ heap.ulMaxFreeSize = poh->ulSize;
+
+ /* Initialize the discardable list */
+ heap.ohUsed.pohNext = &heap.ohUsed;
+ heap.ohUsed.pohPrev = &heap.ohUsed;
+ heap.ohUsed.ulSize = SENTINEL;
+
+ return 0;
+}
+
+/*
+ * Allocates a basic memory unit in which we'll pack our data structures.
+ */
+
+static struct OH *poh_new_node(void)
+{
+ int i;
+ unsigned long cOhs;
+ struct OHALLOC *poha;
+ struct OH *poh;
+
+ if (heap.pohFreeList == NULL) {
+ poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+
+ poha->pohaNext = heap.pohaChain;
+ heap.pohaChain = poha;
+
+ cOhs =
+ (OH_ALLOC_SIZE -
+ sizeof(struct OHALLOC)) / sizeof(struct OH) + 1;
+
+ poh = &poha->aoh[0];
+ for (i = cOhs - 1; i != 0; i--) {
+ poh->pohNext = poh + 1;
+ poh = poh + 1;
+ }
+
+ poh->pohNext = NULL;
+ heap.pohFreeList = &poha->aoh[0];
+ }
+
+ poh = heap.pohFreeList;
+ heap.pohFreeList = poh->pohNext;
+
+ return (poh);
+}
+
+/*
+ * Allocates space, return NULL when failed
+ */
+
+static struct OH *poh_allocate(unsigned long size)
+{
+ struct OH *pohThis;
+ struct OH *pohRoot;
+ int bAllocated = 0;
+
+ if (size > heap.ulMaxFreeSize) {
+ DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+ (unsigned int) size / 1024);
+ return (NULL);
+ }
+
+ pohThis = heap.ohFree.pohNext;
+
+ while (pohThis != &heap.ohFree) {
+ if (size <= pohThis->ulSize) {
+ bAllocated = 1;
+ break;
+ }
+ pohThis = pohThis->pohNext;
+ }
+
+ if (!bAllocated) {
+ DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+ (unsigned int) size / 1024);
+ return (NULL);
+ }
+
+ if (size == pohThis->ulSize) {
+ pohRoot = pohThis;
+ delete_node(pohThis);
+ } else {
+ pohRoot = poh_new_node();
+
+ if (pohRoot == NULL) {
+ return (NULL);
+ }
+
+ pohRoot->ulOffset = pohThis->ulOffset;
+ pohRoot->ulSize = size;
+
+ pohThis->ulOffset += size;
+ pohThis->ulSize -= size;
+ }
+
+ heap.ulMaxFreeSize -= size;
+
+ pohThis = &heap.ohUsed;
+ insert_node(pohThis, pohRoot);
+
+ return (pohRoot);
+}
+
+/*
+ * To remove a node from a list.
+ */
+
+static void delete_node(struct OH *poh)
+{
+ struct OH *pohPrev;
+ struct OH *pohNext;
+
+
+ pohPrev = poh->pohPrev;
+ pohNext = poh->pohNext;
+
+ pohPrev->pohNext = pohNext;
+ pohNext->pohPrev = pohPrev;
+
+ return;
+}
+
+/*
+ * To insert a node into a list.
+ */
+
+static void insert_node(struct OH *pohList, struct OH *poh)
+{
+ struct OH *pohTemp;
+
+ pohTemp = pohList->pohNext;
+
+ pohList->pohNext = poh;
+ pohTemp->pohPrev = poh;
+
+ poh->pohPrev = pohList;
+ poh->pohNext = pohTemp;
+}
+
+/*
+ * Frees an off-screen heap allocation.
+ */
+
+static struct OH *poh_free(unsigned long base)
+{
+
+ struct OH *pohThis;
+ struct OH *pohFreed;
+ struct OH *pohPrev;
+ struct OH *pohNext;
+ unsigned long ulUpper;
+ unsigned long ulLower;
+ int foundNode = 0;
+
+ pohFreed = heap.ohUsed.pohNext;
+
+ while (pohFreed != &heap.ohUsed) {
+ if (pohFreed->ulOffset == base) {
+ foundNode = 1;
+ break;
+ }
+
+ pohFreed = pohFreed->pohNext;
+ }
+
+ if (!foundNode)
+ return (NULL);
+
+ heap.ulMaxFreeSize += pohFreed->ulSize;
+
+ pohPrev = pohNext = NULL;
+ ulUpper = pohFreed->ulOffset + pohFreed->ulSize;
+ ulLower = pohFreed->ulOffset;
+
+ pohThis = heap.ohFree.pohNext;
+
+ while (pohThis != &heap.ohFree) {
+ if (pohThis->ulOffset == ulUpper) {
+ pohNext = pohThis;
+ }
+ else if ((pohThis->ulOffset + pohThis->ulSize) ==
+ ulLower) {
+ pohPrev = pohThis;
+ }
+ pohThis = pohThis->pohNext;
+ }
+
+ delete_node(pohFreed);
+
+ if (pohPrev && pohNext) {
+ pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);
+ delete_node(pohNext);
+ free_node(pohFreed);
+ free_node(pohNext);
+ return (pohPrev);
+ }
+
+ if (pohPrev) {
+ pohPrev->ulSize += pohFreed->ulSize;
+ free_node(pohFreed);
+ return (pohPrev);
+ }
+
+ if (pohNext) {
+ pohNext->ulSize += pohFreed->ulSize;
+ pohNext->ulOffset = pohFreed->ulOffset;
+ free_node(pohFreed);
+ return (pohNext);
+ }
+
+ insert_node(&heap.ohFree, pohFreed);
+
+ return (pohFreed);
+}
+
+/*
+ * Frees our basic data structure allocation unit by adding it to a free
+ * list.
+ */
+
+static void free_node(struct OH *poh)
+{
+ if (poh == NULL) {
+ return;
+ }
+
+ poh->pohNext = heap.pohFreeList;
+ heap.pohFreeList = poh;
+
+ return;
+}
+
+void sis_malloc(struct sis_memreq *req)
+{
+ struct OH *poh;
+
+ poh = poh_allocate(req->size);
+
+ if (poh == NULL) {
+ req->offset = 0;
+ req->size = 0;
+ DPRINTK("sisfb: VMEM Allocation Failed\n");
+ } else {
+ DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
+ (char *) (poh->ulOffset +
+ (unsigned long) ivideo.video_vbase));
+
+ req->offset = poh->ulOffset;
+ req->size = poh->ulSize;
+ }
+
+}
+
+void sis_free(unsigned long base)
+{
+ struct OH *poh;
+
+ poh = poh_free(base);
+
+ if (poh == NULL) {
+ DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
+ (unsigned int) base);
+ }
+}
+
+void sis_dispinfo(struct ap_data *rec)
+{
+ rec->minfo.bpp = ivideo.video_bpp;
+ rec->minfo.xres = ivideo.video_width;
+ rec->minfo.yres = ivideo.video_height;
+ rec->minfo.v_xres = ivideo.video_vwidth;
+ rec->minfo.v_yres = ivideo.video_vheight;
+ rec->minfo.org_x = ivideo.org_x;
+ rec->minfo.org_y = ivideo.org_y;
+ rec->minfo.vrate = ivideo.refresh_rate;
+ rec->iobase = ivideo.vga_base - 0x30;
+ rec->mem_size = ivideo.video_size;
+ rec->disp_state = ivideo.disp_state;
+ switch(HwExt.jChipID)
+ {
+ case SIS_Glamour:
+ rec->chip = SiS_300;
+ break;
+ case SIS_Trojan:
+ if((HwExt.revision_id & 0xf0) == 0x30)
+ rec->chip = SiS_630S;
+ else
+ rec->chip = SiS_630;
+ break;
+ case SIS_Spartan:
+ rec->chip = SiS_540;
+ break;
+ case SIS_730:
+ rec->chip = SiS_730;
+ break;
+ default:
+ rec->chip = SiS_UNKNOWN;
+ break;
+ }
+}
+
+
+/* ---------------------- SetMode Routines -------------------------- */
+
+void SetReg1(u16 port, u16 index, u16 data)
+{
+ outb((u8) (index & 0xff), port);
+ port++;
+ outb((u8) (data & 0xff), port);
+}
+
+void SetReg3(u16 port, u16 data)
+{
+ outb((u8) (data & 0xff), port);
+}
+
+void SetReg4(u16 port, unsigned long data)
+{
+ outl((u32) (data & 0xffffffff), port);
+}
+
+u8 GetReg1(u16 port, u16 index)
+{
+ u8 data;
+
+ outb((u8) (index & 0xff), port);
+ port += 1;
+ data = inb(port);
+ return (data);
+}
+
+u8 GetReg2(u16 port)
+{
+ u8 data;
+
+ data = inb(port);
+
+ return (data);
+}
+
+u32 GetReg3(u16 port)
+{
+ u32 data;
+
+ data = inl(port);
+ return (data);
+}
+
+void ClearDAC(u16 port)
+{
+ int i,j;
+
+ vgawb(DAC_ADR, 0x00);
+ for(i=0; i<256; i++)
+ for(j=0; j<3; j++)
+ vgawb(DAC_DATA, 0);
+}
+
+void ClearBuffer(PHW_DEVICE_EXTENSION pHwExt)
+{
+ memset((char *) ivideo.video_vbase, 0,
+ video_linelength * ivideo.video_height);
+}
+
+static void pre_setmode(void)
+{
+ unsigned char uCR30=0, uCR31=0;
+
+ switch(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ case MASK_DISPTYPE_CRT2:
+ uCR30 = 0x41;
+ uCR31 = 0x40;
+ break;
+ case MASK_DISPTYPE_LCD:
+ uCR30 = 0x21;
+ uCR31 = 0x40;
+ break;
+ case MASK_DISPTYPE_TV:
+ if(ivideo.TV_type == TVMODE_HIVISION)
+ uCR30 = 0x81;
+ else if(ivideo.TV_plug == TVPLUG_SVIDEO)
+ uCR30 = 0x09;
+ else if(ivideo.TV_plug == TVPLUG_COMPOSITE)
+ uCR30 = 0x05;
+ else if(ivideo.TV_plug == TVPLUG_SCART)
+ uCR30 = 0x11;
+ uCR31 = 0x40; /* CR31[0] will be set in setmode() */
+ break;
+ default:
+ uCR30 = 0x00;
+ uCR31 = 0x60;
+ }
+
+ vgawb(CRTC_ADR, 0x30);
+ vgawb(CRTC_DATA, uCR30);
+ vgawb(CRTC_ADR, 0x31);
+ vgawb(CRTC_DATA, uCR31);
+ vgawb(CRTC_ADR, 0x33);
+ vgawb(CRTC_DATA, rate_idx & 0x0f);
+}
+
+static void post_setmode(void)
+{
+ u8 uTemp;
+
+ vgawb(CRTC_ADR, 0x17);
+ uTemp = vgarb(CRTC_DATA);
+
+ if(crt1off) /* turn off CRT1 */
+ uTemp &= ~0x80;
+ else /* turn on CRT1 */
+ uTemp |= 0x80;
+ vgawb(CRTC_DATA, uTemp);
+
+ /* disable 24-bit palette RAM and Gamma correction */
+ vgawb(SEQ_ADR, 0x07);
+ uTemp = vgarb(SEQ_DATA);
+ uTemp &= ~0x04;
+ vgawb(SEQ_DATA, uTemp);
+}
+
+static void search_mode(const char *name)
+{
+ int i = 0;
+
+ if (name == NULL)
+ return;
+
+ while (sisbios_mode[i].mode_no != 0) {
+ if (!strcmp(name, sisbios_mode[i].name)) {
+ mode_idx = i;
+ break;
+ }
+ i++;
+ }
+
+ if (mode_idx < 0)
+ DPRINTK("Invalid user mode : %s\n", name);
+}
+
+static u8 search_refresh_rate(unsigned int rate)
+{
+ u16 xres, yres;
+ int i = 0;
+
+ xres = sisbios_mode[mode_idx].xres;
+ yres = sisbios_mode[mode_idx].yres;
+
+ while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {
+ if ((vrate[i].xres == xres) && (vrate[i].yres == yres)
+ && (vrate[i].refresh == rate)) {
+ rate_idx = vrate[i].idx;
+ return rate_idx;
+ }
+ i++;
+ }
+
+ DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,
+ yres);
+
+ return 0;
+}
+
+/* ------------------ Public Routines ------------------------------- */
+
+/*
+ * Get the Fixed Part of the Display
+ */
+
+static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, fb_info.modename);
+
+ fix->smem_start = ivideo.video_base;
+ if(ivideo.video_size > 0x800000)
+ fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */
+ else
+ fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */
+
+ fix->type = video_type;
+ fix->type_aux = 0;
+ if (ivideo.video_bpp == 8)
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ else
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->ywrapstep = 0;
+ fix->line_length = video_linelength;
+ fix->mmio_start = ivideo.mmio_base;
+ fix->mmio_len = MMIO_SIZE;
+ fix->accel = FB_ACCEL_SIS_GLAMOUR;
+ fix->reserved[0] = ivideo.video_size & 0xFFFF;
+ fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
+ fix->reserved[2] = caps; /* capabilities */
+
+ return 0;
+}
+
+/*
+ * Get the User Defined Part of the Display
+ */
+
+static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);
+
+ if (con == -1)
+ memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+ else
+ *var = fb_display[con].var;
+ return 0;
+}
+
+/*
+ * Set the User Defined Part of the Display
+ */
+
+static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ int err;
+ unsigned int cols, rows;
+
+ fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+ /* Set mode */
+ if (do_set_var(var, con == currcon, info)) {
+ crtc_to_var(var); /* return current mode to user */
+ return -EINVAL;
+ }
+
+ /* get actual setting value */
+ crtc_to_var(var);
+
+ /* update display of current console */
+ sisfb_set_disp(con, var);
+
+ if (info->changevar)
+ (*info->changevar) (con);
+
+ if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
+ return err;
+
+ do_install_cmap(con, info);
+
+ /* inform console to update struct display */
+ cols = sisbios_mode[mode_idx].cols;
+ rows = sisbios_mode[mode_idx].rows;
+ vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+
+ return 0;
+}
+
+
+/*
+ * Get the Colormap
+ */
+
+static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);
+
+ if (con == currcon)
+ return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
+ else if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+/*
+ * Set the Colormap
+ */
+
+static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
+
+ if (!fb_display[con].cmap.len) { /* no colormap allocated */
+ err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
+ if (err)
+ return err;
+ }
+ if (con == currcon) /* current console */
+ return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int sisfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+ switch (cmd) {
+ case FBIO_ALLOC:
+ if(!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ sis_malloc((struct sis_memreq *) arg);
+ break;
+ case FBIO_FREE:
+ if(!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ sis_free(*(unsigned long *) arg);
+ break;
+ case FBIOGET_GLYPH:
+ sis_get_glyph((struct GlyInfo *) arg);
+ break;
+ case FBIOGET_HWCINFO:
+ {
+ unsigned long *hwc_offset = (unsigned long *) arg;
+
+ if (caps & HW_CURSOR_CAP)
+ *hwc_offset = hwcursor_vbase -
+ (unsigned long) ivideo.video_vbase;
+ else
+ *hwc_offset = 0;
+
+ break;
+ }
+ case FBIOPUT_MODEINFO:
+ {
+ struct mode_info *x = (struct mode_info *)arg;
+
+ /* Set Mode Parameters by XServer */
+ ivideo.video_bpp = x->bpp;
+ ivideo.video_width = x->xres;
+ ivideo.video_height = x->yres;
+ ivideo.video_vwidth = x->v_xres;
+ ivideo.video_vheight = x->v_yres;
+ ivideo.org_x = x->org_x;
+ ivideo.org_y = x->org_y;
+ ivideo.refresh_rate = x->vrate;
+
+ break;
+ }
+ case FBIOGET_DISPINFO:
+ sis_dispinfo((struct ap_data *)arg);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sisfb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fb_var_screeninfo var;
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ off = vma->vm_pgoff << PAGE_SHIFT;
+
+ /* frame buffer memory */
+ start = (unsigned long) ivideo.video_base;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
+
+ if (off >= len) {
+ /* memory mapped io */
+ off -= len;
+ sisfb_get_var(&var, currcon, info);
+ if (var.accel_flags)
+ return -EINVAL;
+ start = (unsigned long) ivideo.mmio_base;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE);
+ }
+
+ start &= PAGE_MASK;
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+
+#if defined(__i386__)
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#endif
+ if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+ return 0;
+}
+
+static struct fb_ops sisfb_ops = {
+ owner: THIS_MODULE,
+ fb_get_fix: sisfb_get_fix,
+ fb_get_var: sisfb_get_var,
+ fb_set_var: sisfb_set_var,
+ fb_get_cmap: sisfb_get_cmap,
+ fb_set_cmap: sisfb_set_cmap,
+ fb_ioctl: sisfb_ioctl,
+ fb_mmap: sisfb_mmap,
+};
+
+int sisfb_setup(char *options)
+{
+ char *this_opt;
+
+ fb_info.fontname[0] = '\0';
+ ivideo.refresh_rate = 0;
+
+ if (!options || !*options)
+ return 0;
+
+ for (this_opt = strtok(options, ","); this_opt;
+ this_opt = strtok(NULL, ",")) {
+ if (!*this_opt)
+ continue;
+
+ if (!strcmp(this_opt, "inverse")) {
+ inverse = 1;
+ fb_invert_cmaps();
+ } else if (!strncmp(this_opt, "font:", 5)) {
+ strcpy(fb_info.fontname, this_opt + 5);
+ } else if (!strncmp(this_opt, "mode:", 5)) {
+ search_mode(this_opt + 5);
+ } else if (!strncmp(this_opt, "vrate:", 6)) {
+ ivideo.refresh_rate =
+ simple_strtoul(this_opt + 6, NULL, 0);
+ } else if (!strncmp(this_opt, "off", 3)) {
+ sisfb_off = 1;
+ } else if (!strncmp(this_opt, "crt1off", 7)) {
+ crt1off = 1;
+ } else
+ DPRINTK("invalid parameter %s\n", this_opt);
+ }
+ return 0;
+}
+
+static int sisfb_update_var(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+/*
+ * Switch Console (called by fbcon.c)
+ */
+
+static int sisfb_switch(int con, struct fb_info *info)
+{
+ int cols, rows;
+
+ DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);
+
+ /* update colormap of current console */
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+
+ fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+ /* same mode, needn't change mode actually */
+
+ if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo)))
+ {
+ currcon = con;
+ return 1;
+ }
+
+ currcon = con;
+
+ do_set_var(&fb_display[con].var, 1, info);
+
+ sisfb_set_disp(con, &fb_display[con].var);
+
+ /* Install new colormap */
+ do_install_cmap(con, info);
+
+ cols = sisbios_mode[mode_idx].cols;
+ rows = sisbios_mode[mode_idx].rows;
+ vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+
+ sisfb_update_var(con, info);
+
+ return 1;
+
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void sisfb_blank(int blank, struct fb_info *info)
+{
+ u8 CRData;
+
+ vgawb(CRTC_ADR, 0x17);
+ CRData = vgarb(CRTC_DATA);
+
+ if (blank > 0) /* turn off CRT1 */
+ CRData &= 0x7f;
+ else /* turn on CRT1 */
+ CRData |= 0x80;
+
+ vgawb(CRTC_ADR, 0x17);
+ vgawb(CRTC_DATA, CRData);
+}
+
+int has_VB(void)
+{
+ u8 uSR38, uSR39, uVBChipID;
+
+ vgawb(SEQ_ADR, 0x38);
+ uSR38 = vgarb(SEQ_DATA);
+ vgawb(SEQ_ADR, 0x39);
+ uSR39 = vgarb(SEQ_DATA);
+ vgawb(IND_SIS_CRT2_PORT_14, 0x0);
+ uVBChipID = vgarb(IND_SIS_CRT2_PORT_14+1);
+
+ if (
+ ( (HwExt.jChipID == SIS_Glamour) && (uSR38 & 0x20) ) /* 300 */
+ ||
+ ( (HwExt.jChipID >= SIS_Trojan ) && (uSR38 & 0x20) && (!(uSR39 & 0x80)) ) /* 630/540 */
+ ||
+ ( (HwExt.jChipID == SIS_Trojan ) && ((HwExt.revision_id & 0xf0) == 0x30) && (uVBChipID == 1) ) /* 630s */
+ ||
+ ( (HwExt.jChipID == SIS_730) && (uVBChipID == 1) ) /* 730 */
+ )
+ {
+ ivideo.hasVB = HASVB_301;
+ return TRUE;
+ }
+ else
+ {
+ ivideo.hasVB = HASVB_NONE;
+ return FALSE;
+ }
+}
+
+void sis_get301info(void)
+{
+ u8 uCRData;
+ unsigned long disp_state=0;
+
+ if (HwExt.jChipID >= SIS_Trojan)
+ {
+ if (!has_VB())
+ {
+ vgawb(CRTC_ADR, 0x37);
+ uCRData = vgarb(CRTC_DATA);
+
+ switch((uCRData >> 1) & 0x07)
+ {
+ case 2:
+ ivideo.hasVB = HASVB_LVDS;
+ break;
+ case 4:
+ ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+ break;
+ case 3:
+ ivideo.hasVB = HASVB_TRUMPION;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ has_VB();
+ }
+
+ vgawb(CRTC_ADR, 0x32);
+ uCRData = vgarb(CRTC_DATA);
+
+ switch(uDispType)
+ {
+ case MASK_DISPTYPE_CRT2:
+ disp_state = DISPTYPE_CRT2;
+ break;
+ case MASK_DISPTYPE_LCD:
+ disp_state = DISPTYPE_LCD;
+ break;
+ case MASK_DISPTYPE_TV:
+ disp_state = DISPTYPE_TV;
+ break;
+ }
+
+ if(disp_state & 0x7)
+ {
+ if(crt1off)
+ disp_state |= DISPMODE_SINGLE;
+ else
+ disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
+ }
+ else
+ disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
+
+ ivideo.disp_state = disp_state;
+}
+
+
+int __init sisfb_init(void)
+{
+ struct pci_dev *pdev = NULL;
+ struct board *b;
+ int pdev_valid = 0;
+ unsigned char jTemp;
+ u8 uSRData, uCRData;
+
+ outb(0x77, 0x80);
+
+ if (sisfb_off)
+ return -ENXIO;
+
+ pci_for_each_dev(pdev) {
+ for (b = dev_list; b->vendor; b++)
+ {
+ if ((b->vendor == pdev->vendor)
+ && (b->device == pdev->device))
+ {
+ pdev_valid = 1;
+ strcpy(fb_info.modename, b->name);
+ ivideo.chip_id = pdev->device;
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &HwExt.revision_id);
+ break;
+ }
+ }
+
+ if (pdev_valid)
+ break;
+ }
+
+ if (!pdev_valid)
+ return -1;
+
+ switch(ivideo.chip_id)
+ {
+ case PCI_DEVICE_ID_SI_300:
+ HwExt.jChipID = SIS_Glamour;
+ break;
+ case PCI_DEVICE_ID_SI_630_VGA:
+ HwExt.jChipID = SIS_Trojan;
+ break;
+ case PCI_DEVICE_ID_SI_540_VGA:
+ HwExt.jChipID = SIS_Spartan;
+ break;
+ case PCI_DEVICE_ID_SI_730_VGA:
+ HwExt.jChipID = SIS_730;
+ break;
+ }
+
+ ivideo.video_base = pci_resource_start(pdev, 0);
+ ivideo.mmio_base = pci_resource_start(pdev, 1);
+ ivideo.vga_base = pci_resource_start(pdev, 2) + 0x30;
+
+ HwExt.IOAddress = (unsigned short)ivideo.vga_base;
+ rom_base = 0x000C0000;
+
+ MMIO_SIZE = pci_resource_len(pdev, 1);
+
+#ifdef NOBIOS
+ if (pci_enable_device(pdev))
+ return -EIO;
+ /* Image file instead of VGA-bios */
+ HwExt.VirtualRomBase = rom_vbase = (unsigned long) RomData;
+#else
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+ if (pci_enable_device(pdev))
+ return -EIO;
+ HwExt.VirtualRomBase = rom_vbase = 0;
+#else
+ request_region(rom_base, 32, "sisfb");
+ HwExt.VirtualRomBase = rom_vbase
+ = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN);
+#endif
+#endif
+ /* set passwd */
+ vgawb(SEQ_ADR, IND_SIS_PASSWORD);
+ vgawb(SEQ_DATA, SIS_PASSWORD);
+
+ /* Enable MMIO & PCI linear address */
+ vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
+ jTemp = vgarb(SEQ_DATA);
+ jTemp |= SIS_PCI_ADDR_ENABLE;
+ jTemp |= SIS_MEM_MAP_IO_ENABLE;
+ vgawb(SEQ_DATA, jTemp);
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+ pdev_valid = 0;
+ pci_for_each_dev(pdev) {
+ u8 uPCIData=0;
+
+ if ((pdev->vendor == PCI_VENDOR_ID_SI) && (pdev->device==0x630))
+ {
+ pci_read_config_byte(pdev, 0x63, &uPCIData);
+ uPCIData = (uPCIData & 0x70) >> 4;
+ ivideo.video_size = (unsigned int)(1 << (uPCIData+21));
+ pdev_valid = 1;
+ break;
+ }
+ }
+
+ if (!pdev_valid)
+ return -1;
+#else
+ vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
+ ivideo.video_size = ((unsigned int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20);
+#endif
+
+
+ /* get CRT2 connection state */
+ vgawb(SEQ_ADR, 0x17);
+ uSRData = vgarb(SEQ_DATA);
+ vgawb(CRTC_ADR, 0x32);
+ uCRData = vgarb(CRTC_DATA);
+
+ ivideo.TV_plug = ivideo.TV_type = 0;
+ if((uSRData&0x0F) && (HwExt.jChipID>=SIS_Trojan))
+ {
+ /* CRT1 connect detection */
+ if((uSRData & 0x01) && !crt1off)
+ crt1off = 0;
+ else
+ {
+ if(uSRData&0x0E) /* DISP2 connected */
+ crt1off = 1;
+ else
+ crt1off = 0;
+ }
+
+ /* detection priority : CRT2 > LCD > TV */
+ if(uSRData & 0x08 )
+ uDispType = MASK_DISPTYPE_CRT2;
+ else if(uSRData & 0x02)
+ uDispType = MASK_DISPTYPE_LCD;
+ else if(uSRData & 0x04)
+ {
+ if(uSRData & 0x80)
+ {
+ ivideo.TV_type = TVMODE_HIVISION;
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ }
+ else if(uSRData & 0x20)
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ else if(uSRData & 0x10)
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ else if(uSRData & 0x40)
+ ivideo.TV_plug = TVPLUG_SCART;
+
+ if(ivideo.TV_type == 0)
+ {
+ u8 uSR16;
+ vgawb(SEQ_ADR, 0x16);
+ uSR16 = vgarb(SEQ_DATA);
+ if(uSR16 & 0x20)
+ ivideo.TV_type = TVMODE_PAL;
+ else
+ ivideo.TV_type = TVMODE_NTSC;
+ }
+
+ uDispType = MASK_DISPTYPE_TV;
+ }
+ }
+ else
+ {
+ if((uCRData & 0x20) && !crt1off)
+ crt1off = 0;
+ else
+ {
+ if(uCRData&0x5F) /* DISP2 connected */
+ crt1off = 1;
+ else
+ crt1off = 0;
+ }
+
+ if(uCRData & 0x10)
+ uDispType = MASK_DISPTYPE_CRT2;
+ else if(uCRData & 0x08)
+ uDispType = MASK_DISPTYPE_LCD;
+ else if(uCRData & 0x47)
+ {
+ uDispType = MASK_DISPTYPE_TV;
+
+ if(uCRData & 0x40)
+ {
+ ivideo.TV_type = TVMODE_HIVISION;
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ }
+ else if(uCRData & 0x02)
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ else if(uCRData & 0x01)
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ else if(uCRData & 0x04)
+ ivideo.TV_plug = TVPLUG_SCART;
+
+ if(ivideo.TV_type == 0)
+ {
+ u8 uTemp;
+ uTemp = *((u8 *)(HwExt.VirtualRomBase+0x52));
+ if(uTemp&0x40)
+ {
+ uTemp=*((u8 *)(HwExt.VirtualRomBase+0x53));
+ }
+ else
+ {
+ vgawb(SEQ_ADR, 0x38);
+ uTemp = vgarb(SEQ_DATA);
+ }
+ if(uTemp & 0x01)
+ ivideo.TV_type = TVMODE_PAL;
+ else
+ ivideo.TV_type = TVMODE_NTSC;
+ }
+ }
+ }
+
+ if(uDispType == MASK_DISPTYPE_LCD) // LCD conntected
+ {
+ // TODO: set LCDType by EDID
+ HwExt.usLCDType = LCD1024;
+ }
+
+ if (HwExt.jChipID >= SIS_Trojan)
+ {
+ vgawb(SEQ_ADR, 0x1A);
+ uSRData = vgarb(SEQ_DATA);
+ if (uSRData & 0x10)
+ HwExt.bIntegratedMMEnabled = TRUE;
+ else
+ HwExt.bIntegratedMMEnabled = FALSE;
+ }
+
+ if(mode_idx >= 0) /* mode found */
+ {
+ /* Filtering mode for VB */
+ switch(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ case MASK_DISPTYPE_LCD:
+ switch(HwExt.usLCDType)
+ {
+ case LCD1024:
+ if(sisbios_mode[mode_idx].xres > 1024)
+ mode_idx = -1;
+ break;
+ case LCD1280:
+ if(sisbios_mode[mode_idx].xres > 1280)
+ mode_idx = -1;
+ break;
+ case LCD2048:
+ if(sisbios_mode[mode_idx].xres > 2048)
+ mode_idx = -1;
+ break;
+ case LCD1920:
+ if(sisbios_mode[mode_idx].xres > 1920)
+ mode_idx = -1;
+ break;
+ case LCD1600:
+ if(sisbios_mode[mode_idx].xres > 1600)
+ mode_idx = -1;
+ break;
+ case LCD800:
+ if(sisbios_mode[mode_idx].xres > 800)
+ mode_idx = -1;
+ break;
+ case LCD640:
+ if(sisbios_mode[mode_idx].xres > 640)
+ mode_idx = -1;
+ break;
+ default:
+ mode_idx = -1;
+ }
+
+ if(sisbios_mode[mode_idx].xres == 720) /* only for TV */
+ mode_idx = -1;
+ break;
+ case MASK_DISPTYPE_TV:
+ switch(sisbios_mode[mode_idx].xres)
+ {
+ case 800:
+ case 640:
+ break;
+ case 720:
+ if(ivideo.TV_type == TVMODE_NTSC)
+ {
+ if(sisbios_mode[mode_idx].yres != 480)
+ mode_idx = -1;
+ }
+ else if(ivideo.TV_type == TVMODE_PAL)
+ {
+ if(sisbios_mode[mode_idx].yres != 576)
+ mode_idx = -1;
+ }
+ break;
+ default:
+ /* illegal mode */
+ mode_idx = -1;
+ }
+ break;
+ }
+ }
+
+ if (mode_idx < 0)
+ {
+ switch(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ case MASK_DISPTYPE_LCD:
+ mode_idx = DEFAULT_LCDMODE;
+ break;
+ case MASK_DISPTYPE_TV:
+ mode_idx = DEFAULT_TVMODE;
+ break;
+ default:
+ mode_idx = DEFAULT_MODE;
+ }
+ }
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+ mode_idx = DEFAULT_MODE;
+ rate_idx = sisbios_mode[mode_idx].rate_idx;
+ /* set to default refresh rate 60MHz */
+ ivideo.refresh_rate = 60;
+#endif
+
+ mode_no = sisbios_mode[mode_idx].mode_no;
+
+ if (ivideo.refresh_rate != 0)
+ search_refresh_rate(ivideo.refresh_rate);
+
+ if (rate_idx == 0) {
+ rate_idx = sisbios_mode[mode_idx].rate_idx;
+ /* set to default refresh rate 60MHz */
+ ivideo.refresh_rate = 60;
+ }
+
+ ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
+ ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres;
+ ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres;
+ ivideo.org_x = ivideo.org_y = 0;
+ video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+
+ printk(KERN_DEBUG "FB base: 0x%lx, size: 0x%dK\n",
+ ivideo.video_base, (unsigned int)ivideo.video_size/1024);
+ printk(KERN_DEBUG "MMIO base: 0x%lx, size: 0x%dK\n",
+ ivideo.mmio_base, (unsigned int)MMIO_SIZE/1024);
+
+
+ if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB"))
+ {
+ printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n");
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(ivideo.mmio_base, MMIO_SIZE, "sisfb MMIO"))
+ {
+ printk(KERN_ERR "sisfb: cannot reserve MMIO region\n");
+ release_mem_region(ivideo.video_base, ivideo.video_size);
+ return -ENODEV;
+ }
+
+ HwExt.VirtualVideoMemoryAddress = ivideo.video_vbase
+ = ioremap(ivideo.video_base, ivideo.video_size);
+ ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE);
+
+#ifdef NOBIOS
+ SiSInit300(&HwExt);
+#else
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+ SiSInit300(&HwExt);
+#endif
+#endif
+ printk(KERN_INFO
+ "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+ ivideo.video_base, ivideo.video_vbase,
+ ivideo.video_size / 1024);
+ printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n",
+ ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
+ video_linelength);
+
+ /* enable 2D engine */
+ vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
+ jTemp = vgarb(SEQ_DATA);
+ jTemp |= SIS_2D_ENABLE;
+ vgawb(SEQ_DATA, jTemp);
+
+ pre_setmode();
+
+ if (SiSSetMode(&HwExt, mode_no)) {
+ DPRINTK("sisfb: set mode[0x%x]: failed\n", mode_no);
+ return -1;
+ }
+
+ post_setmode();
+
+ /* Get VB functions */
+ sis_get301info();
+
+ crtc_to_var(&default_var);
+
+ fb_info.changevar = NULL;
+ fb_info.node = -1;
+ fb_info.fbops = &sisfb_ops;
+ fb_info.disp = &disp;
+ fb_info.switch_con = &sisfb_switch;
+ fb_info.updatevar = &sisfb_update_var;
+ fb_info.blank = &sisfb_blank;
+ fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+ sisfb_set_disp(-1, &default_var);
+
+ if (sisfb_heap_init()) {
+ DPRINTK("sisfb: Failed to enable offscreen heap\n");
+ }
+
+ /* to avoid the inversed bgcolor bug of the initial state */
+ vc_resize_con(1, 1, 0);
+
+ if (register_framebuffer(&fb_info) < 0)
+ return -EINVAL;
+
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename);
+
+ return 0;
+}
+
+#ifdef MODULE
+
+static char *mode = NULL;
+static unsigned int rate = 0;
+static unsigned int crt1 = 1;
+
+MODULE_PARM(mode, "s");
+MODULE_PARM(rate, "i");
+MODULE_PARM(crt1, "i"); /* default: CRT1 enable */
+
+int init_module(void)
+{
+ if (mode)
+ search_mode(mode);
+
+ ivideo.refresh_rate = rate;
+
+ if(crt1 == 0)
+ crt1off = 1;
+ else
+ crt1off = 0;
+
+ sisfb_init();
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_framebuffer(&fb_info);
+}
+#endif /* MODULE */
+
+
+EXPORT_SYMBOL(sis_malloc);
+EXPORT_SYMBOL(sis_free);
+
+EXPORT_SYMBOL(ivideo);
+++ /dev/null
-/*
- * SiS 300/630/540 frame buffer device For Kernal 2.4.x
- *
- * This driver is partly based on the VBE 2.0 compliant graphic
- * boards framebuffer driver, which is
- *
- * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
- *
- */
-
-#define EXPORT_SYMTAB
-#undef SISFBDEBUG
-#undef CONFIG_FB_SIS_LINUXBIOS
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/console.h>
-#include <linux/selection.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vt_kern.h>
-#include <linux/capability.h>
-#include <linux/sisfb.h>
-
-#include <asm/io.h>
-#include <asm/mtrr.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-
-/* ------------------- Constant Definitions ------------------------- */
-
-#define FALSE 0
-#define TRUE 1
-
-/* Draw Function
-#define FBIOGET_GLYPH 0x4620
-#define FBIOGET_HWCINFO 0x4621
-*/
-#define BR(x) (0x8200 | (x) << 2)
-
-#define BITBLT 0x00000000
-#define COLOREXP 0x00000001
-#define ENCOLOREXP 0x00000002
-#define MULTIPLE_SCANLINE 0x00000003
-#define LINE 0x00000004
-#define TRAPAZOID_FILL 0x00000005
-#define TRANSPARENT_BITBLT 0x00000006
-
-#define SRCVIDEO 0x00000000
-#define SRCSYSTEM 0x00000010
-#define SRCAGP 0x00000020
-
-#define PATFG 0x00000000
-#define PATPATREG 0x00000040
-#define PATMONO 0x00000080
-
-#define X_INC 0x00010000
-#define X_DEC 0x00000000
-#define Y_INC 0x00020000
-#define Y_DEC 0x00000000
-
-#define NOCLIP 0x00000000
-#define NOMERGECLIP 0x04000000
-#define CLIPENABLE 0x00040000
-#define CLIPWITHOUTMERGE 0x04040000
-
-#define OPAQUE 0x00000000
-#define TRANSPARENT 0x00100000
-
-#define DSTAGP 0x02000000
-#define DSTVIDEO 0x02000000
-
-#define LINE_STYLE 0x00800000
-#define NO_RESET_COUNTER 0x00400000
-#define NO_LAST_PIXEL 0x00200000
-
-/* capabilities */
-#define TURBO_QUEUE_CAP 0x80
-#define HW_CURSOR_CAP 0x40
-
-/* VGA register Offsets */
-#define SEQ_ADR (0x14)
-#define SEQ_DATA (0x15)
-#define DAC_ADR (0x18)
-#define DAC_DATA (0x19)
-#define CRTC_ADR (0x24)
-#define CRTC_DATA (0x25)
-
-/* SiS indexed register indexes */
-#define IND_SIS_PASSWORD (0x05)
-#define IND_SIS_DRAM_SIZE (0x14)
-#define IND_SIS_MODULE_ENABLE (0x1E)
-#define IND_SIS_PCI_ADDRESS_SET (0x20)
-#define IND_SIS_TURBOQUEUE_ADR (0x26)
-#define IND_SIS_TURBOQUEUE_SET (0x27)
-
-/* Sis register value */
-#define SIS_PASSWORD (0x86)
-
-#define SIS_2D_ENABLE (0x40)
-
-#define SIS_MEM_MAP_IO_ENABLE (0x01)
-#define SIS_PCI_ADDR_ENABLE (0x80)
-
-#define MMIO_SIZE 0x20000 /* 128K MMIO capability */
-#define MAX_ROM_SCAN 0x10000
-
-#define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
-#define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
-
-/* Mode set stuff */
-#define DEFAULT_MODE 0
-
-#define ModeInfoFlag 0x07
-#define MemoryInfoFlag 0x1E0
-#define MemorySizeShift 0x05
-#define ModeVGA 0x03
-#define ModeEGA 0x02
-#define CRT1Len 17
-#define DoubleScanMode 0x8000
-#define HalfDCLK 0x1000
-
-#define InterlaceMode 0x80
-#define LineCompareOff 0x400
-#define DACInfoFlag 0x18
-
-#define VCLKStartFreq 25
-
-#define SIS_Glamour 0x0300
-#define SIS_Trojan 0x6300
-#define SIS_Spartan 0x5300
-
-/* heap stuff */
-#define OH_ALLOC_SIZE 4000
-#define SENTINEL 0x7fffffff
-
-#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
-#define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
-
-/* video connection status */
-#define VB_COMPOSITE 0x01
-#define VB_SVIDEO 0x02
-#define VB_SCART 0x04
-#define VB_LCD 0x08
-#define VB_CRT2 0x10
-#define CRT1 0x20
-#define VB_HDTV 0x40
-
-/* ------------------- Global Variables ----------------------------- */
-
-struct video_info ivideo;
-
-struct GlyInfo {
- unsigned char ch;
- int fontwidth;
- int fontheight;
- u8 gmask[72];
- int ngmask;
-};
-
-/* Supported SiS Chips list */
-static struct board {
- u16 vendor, device;
- const char *name;
-} dev_list[] = {
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"},
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
- {0, 0, NULL}
-};
-
-/* card parameters */
-unsigned long rom_base;
-unsigned long rom_vbase;
-
-/* mode */
-static int video_type = FB_TYPE_PACKED_PIXELS;
-static int video_linelength;
-static int video_cmap_len;
-static int sisfb_off = 0;
-
-static struct fb_var_screeninfo default_var = {
- 0, 0, 0, 0,
- 0, 0,
- 0,
- 0,
- {0, 8, 0},
- {0, 8, 0},
- {0, 8, 0},
- {0, 0, 0},
- 0,
- FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,
- FB_VMODE_NONINTERLACED,
- {0, 0, 0, 0, 0, 0}
-};
-
-static struct display disp;
-static struct fb_info fb_info;
-
-static struct {
- u16 blue, green, red, pad;
-} palette[256];
-
-static union {
-#ifdef FBCON_HAS_CFB16
- u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB24
- u32 cfb24[16];
-#endif
-#ifdef FBCON_HAS_CFB32
- u32 cfb32[16];
-#endif
-} fbcon_cmap;
-
-static int inverse = 0;
-static int currcon = 0;
-
-static struct display_switch sisfb_sw;
-
-u8 caps = 0;
-
-/* ModeSet stuff */
-
-u16 P3c4, P3d4, P3c0, P3ce, P3c2, P3ca, P3c6, P3c7, P3c8, P3c9, P3da;
-u16 CRT1VCLKLen;
-u16 flag_clearbuffer;
-u16 CRT1VCLKLen;
-int ModeIDOffset, StandTable, CRT1Table, ScreenOffset;
-int REFIndex, ModeType;
-int VCLKData;
-int RAMType;
-
-int mode_idx = -1;
-u8 mode_no = 0;
-u8 rate_idx = 0;
-
-static const struct _sisbios_mode {
- char name[15];
- u8 mode_no;
- u16 xres;
- u16 yres;
- u16 bpp;
- u16 rate_idx;
- u16 cols;
- u16 rows;
-} sisbios_mode[] = {
- {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30},
- {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30},
- {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30},
- {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37},
- {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37},
- {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37},
- {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48},
- {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48},
- {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48},
- {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64},
- {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
- {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
- {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75},
- {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
- {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
- {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75},
- {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
- {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
- {"\0", 0x00, 0, 0, 0, 0, 0, 0}
-};
-
-static struct _vrate {
- u16 idx;
- u16 xres;
- u16 yres;
- u16 refresh;
-} vrate[] = {
- {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85},
- {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200},
- {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75},
- {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160},
- {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75},
- {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
- {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
- {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
- {5, 1600, 1200, 85},
- {1, 1920, 1440, 60},
- {0, 0, 0, 0}
-};
-
-u16 DRAMType[17][5] = {
- {0x0C, 0x0A, 0x02, 0x40, 0x39}, {0x0D, 0x0A, 0x01, 0x40, 0x48},
- {0x0C, 0x09, 0x02, 0x20, 0x35}, {0x0D, 0x09, 0x01, 0x20, 0x44},
- {0x0C, 0x08, 0x02, 0x10, 0x31}, {0x0D, 0x08, 0x01, 0x10, 0x40},
- {0x0C, 0x0A, 0x01, 0x20, 0x34}, {0x0C, 0x09, 0x01, 0x08, 0x32},
- {0x0B, 0x08, 0x02, 0x08, 0x21}, {0x0C, 0x08, 0x01, 0x08, 0x30},
- {0x0A, 0x08, 0x02, 0x04, 0x11}, {0x0B, 0x0A, 0x01, 0x10, 0x28},
- {0x09, 0x08, 0x02, 0x02, 0x01}, {0x0B, 0x09, 0x01, 0x08, 0x24},
- {0x0B, 0x08, 0x01, 0x04, 0x20}, {0x0A, 0x08, 0x01, 0x02, 0x10},
- {0x09, 0x08, 0x01, 0x01, 0x00}
-};
-
-u16 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
-};
-
-u16 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
-};
-
-u16 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
-};
-
-u16 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
-};
-
-#define Monitor1Sense 0x20
-
-unsigned char SRegsInit[] = {
- 0x03, 0x00, 0x03, 0x00, 0x02, 0xa1, 0x00, 0x13,
- 0x2f, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0f, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xa1, 0x76, 0xb2, 0xf6, 0x0d, 0x00, 0x00, 0x00,
- 0x37, 0x61, 0x80, 0x1b, 0xe1, 0x01, 0x55, 0x43,
- 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff,
- 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff
-};
-
-#ifdef CONFIG_FB_SIS_LINUXBIOS
-
-unsigned char SRegs[] = {
- 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13,
- 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x0B, 0x0F, 0x00, 0x00, 0x4F, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00,
- 0xA1, 0xB6, 0xB2, 0xF6, 0x0D, 0x00, 0xF8, 0xF0,
- 0x37, 0x61, 0x80, 0x1B, 0xE1, 0x80, 0x55, 0x43,
- 0x80, 0x00, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF,
- 0x8E, 0x40, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xFF
-};
-
-unsigned char CRegs[] = {
- 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xe9, 0x0b, 0xdf, 0x50, 0x40, 0xe7, 0x04, 0xa3,
- 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff
-}; // clear CR11[7]
-
-unsigned char GRegs[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, 0x00
-};
-
-unsigned char ARegs[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char MReg = 0x6f;
-
-#endif
-
-
-/* HEAP stuff */
-
-struct OH {
- struct OH *pohNext;
- struct OH *pohPrev;
- unsigned long ulOffset;
- unsigned long ulSize;
-};
-
-struct OHALLOC {
- struct OHALLOC *pohaNext;
- struct OH aoh[1];
-};
-
-struct HEAP {
- struct OH ohFree;
- struct OH ohUsed;
- struct OH *pohFreeList;
- struct OHALLOC *pohaChain;
-
- unsigned long ulMaxFreeSize;
-};
-
-struct HEAP heap;
-unsigned long heap_start;
-unsigned long heap_end;
-unsigned long heap_size;
-
-unsigned int tqueue_pos;
-unsigned long hwcursor_vbase;
-
-/* Draw Function stuff */
-u32 command_reg;
-
-/* -------------------- Macro definitions --------------------------- */
-
-#ifdef SISFBDEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#define vgawb(reg,data) \
- (outb(data, ivideo.vga_base+reg))
-#define vgaww(reg,data) \
- (outw(data, ivideo.vga_base+reg))
-#define vgawl(reg,data) \
- (outl(data, ivideo.vga_base+reg))
-#define vgarb(reg) \
- (inb(ivideo.vga_base+reg))
-
-/* ---------------------- Routine Prototype ------------------------- */
-
-/* Interface used by the world */
-int sisfb_setup(char *options);
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int sisfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info);
-
-/* Interface to the low level console driver */
-int sisfb_init(void);
-static int sisfb_update_var(int con, struct fb_info *info);
-static int sisfb_switch(int con, struct fb_info *info);
-static void sisfb_blank(int blank, struct fb_info *info);
-
-/* Internal routines */
-static void crtc_to_var(struct fb_var_screeninfo *var);
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
-static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *fb_info);
-static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *fb_info);
-static void do_install_cmap(int con, struct fb_info *info);
-static int do_set_var(struct fb_var_screeninfo *var, int isactive,
- struct fb_info *info);
-
-/* set-mode routines */
-static void set_reg1(u16 port, u16 index, u16 data);
-static void set_reg3(u16 port, u16 data);
-static void set_reg4(u16 port, unsigned long data);
-static u8 get_reg1(u16 port, u16 index);
-static u8 get_reg2(u16 port);
-//#ifndef CONFIG_FB_SIS_LINUXBIOS
-static u32 get_reg3(u16 port);
-static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo);
-static int search_modeID(unsigned long ROMAddr, u16 ModeNo);
-static int check_memory_size(unsigned long ROMAddr);
-static void get_mode_ptr(unsigned long ROMAddr, u16 ModeNo);
-static void set_seq_regs(unsigned long ROMAddr);
-static void set_misc_regs(unsigned long ROMAddr);
-static void set_crtc_regs(unsigned long ROMAddr);
-static void set_attregs(unsigned long ROMAddr);
-static void set_grc_regs(unsigned long ROMAddr);
-static void ClearExt1Regs(void);
-static u16 GetRefindexLength(unsigned long ROMAddr, u16 ModeNo);
-static int get_rate_ptr(unsigned long ROMAddr, u16 ModeNo);
-static void set_sync(unsigned long ROMAddr);
-static void set_crt1_crtc(unsigned long ROMAddr);
-static void set_crt1_offset(unsigned long ROMAddr);
-static u16 get_vclk_len(unsigned long ROMAddr);
-static void set_crt1_vclk(unsigned long ROMAddr);
-static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo);
-static u16 calc_delay2(unsigned long ROMAddr, u16 key);
-static u16 calc_delay(unsigned long ROMAddr, u16 key);
-static void set_crt1_FIFO(unsigned long ROMAddr);
-static void set_crt1_FIFO2(unsigned long ROMAddr);
-static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo);
-static void set_interlace(unsigned long ROMAddr, u16 ModeNo);
-//#endif
-static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh);
-static void load_DAC(unsigned long ROMAddr);
-static void display_on(void);
-
-static int SiSSetMode(u16 ModeNo);
-static void pre_setmode(void);
-static void post_setmode(void);
-static void search_mode(const char *name);
-static u8 search_refresh_rate(unsigned int rate);
-
-/* heap routines */
-static int sisfb_heap_init(void);
-static struct OH *poh_new_node(void);
-static struct OH *poh_allocate(unsigned long size);
-static struct OH *poh_free(unsigned long base);
-static void delete_node(struct OH *poh);
-static void insert_node(struct OH *pohList, struct OH *poh);
-static void free_node(struct OH *poh);
-
-/* ---------------------- Internal Routines ------------------------- */
-
-inline static u32 RD32(unsigned char *base, s32 off)
-{
- return readl(base + off);
-}
-
-inline static void WR32(unsigned char *base, s32 off, u32 v)
-{
- writel(v, base + off);
-}
-
-inline static void WR16(unsigned char *base, s32 off, u16 v)
-{
- writew(v, base + off);
-}
-
-inline static void WR8(unsigned char *base, s32 off, u8 v)
-{
- writeb(v, base + off);
-}
-
-inline static u32 regrl(s32 off)
-{
- return RD32(ivideo.mmio_vbase, off);
-}
-
-inline static void regwl(s32 off, u32 v)
-{
- WR32(ivideo.mmio_vbase, off, v);
-}
-
-inline static void regww(s32 off, u16 v)
-{
- WR16(ivideo.mmio_vbase, off, v);
-}
-
-inline static void regwb(s32 off, u8 v)
-{
- WR8(ivideo.mmio_vbase, off, v);
-}
-
-/*
- * Get CRTC registers to set var
- */
-static void crtc_to_var(struct fb_var_screeninfo *var)
-{
- u16 VRE, VBE, VRS, VBS, VDE, VT;
- u16 HRE, HBE, HRS, HBS, HDE, HT;
- u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;
- int A, B, C, D, E, F, temp;
- double hrate, drate;
-
- vgawb(SEQ_ADR, 0x6);
- uSRdata = vgarb(SEQ_DATA);
-
- if (uSRdata & 0x20)
- var->vmode = FB_VMODE_INTERLACED;
- else
- var->vmode = FB_VMODE_NONINTERLACED;
-
- switch ((uSRdata & 0x1c) >> 2) {
- case 0:
- var->bits_per_pixel = 8;
- break;
- case 2:
- var->bits_per_pixel = 16;
- break;
- case 4:
- var->bits_per_pixel = 32;
- break;
- }
-
- switch (var->bits_per_pixel) {
- case 8:
- var->red.length = 6;
- var->green.length = 6;
- var->blue.length = 6;
- video_cmap_len = 256;
- break;
- case 16: /* RGB 565 */
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- video_cmap_len = 16;
-
- break;
- case 24: /* RGB 888 */
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- video_cmap_len = 16;
- break;
- case 32:
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- video_cmap_len = 16;
- break;
- }
-
- vgawb(SEQ_ADR, 0xa);
- uSRdata = vgarb(SEQ_DATA);
-
- vgawb(CRTC_ADR, 0x6);
- uCRdata = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x7);
- uCRdata2 = vgarb(CRTC_DATA);
- VT =
- (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |
- ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<
- 10);
- A = VT + 2;
-
- vgawb(CRTC_ADR, 0x12);
- uCRdata = vgarb(CRTC_DATA);
- VDE =
- (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |
- ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);
- E = VDE + 1;
-
- vgawb(CRTC_ADR, 0x10);
- uCRdata = vgarb(CRTC_DATA);
- VRS =
- (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |
- ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);
- F = VRS + 1 - E;
-
- vgawb(CRTC_ADR, 0x15);
- uCRdata = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x9);
- uCRdata3 = vgarb(CRTC_DATA);
- VBS =
- (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |
- ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);
-
- vgawb(CRTC_ADR, 0x16);
- uCRdata = vgarb(CRTC_DATA);
- VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);
- temp = VBE - ((E - 1) & 511);
- B = (temp > 0) ? temp : (temp + 512);
-
- vgawb(CRTC_ADR, 0x11);
- uCRdata = vgarb(CRTC_DATA);
- VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);
- temp = VRE - ((E + F - 1) & 31);
- C = (temp > 0) ? temp : (temp + 32);
-
- D = B - F - C;
-
- var->yres = var->yres_virtual = E;
- var->upper_margin = D;
- var->lower_margin = F;
- var->vsync_len = C;
-
- vgawb(SEQ_ADR, 0xb);
- uSRdata = vgarb(SEQ_DATA);
-
- vgawb(CRTC_ADR, 0x0);
- uCRdata = vgarb(CRTC_DATA);
- HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);
- A = HT + 5;
-
- vgawb(CRTC_ADR, 0x1);
- uCRdata = vgarb(CRTC_DATA);
- HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);
- E = HDE + 1;
-
- vgawb(CRTC_ADR, 0x4);
- uCRdata = vgarb(CRTC_DATA);
- HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);
- F = HRS - E - 3;
-
- vgawb(CRTC_ADR, 0x2);
- uCRdata = vgarb(CRTC_DATA);
- HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);
-
- vgawb(SEQ_ADR, 0xc);
- uSRdata = vgarb(SEQ_DATA);
- vgawb(CRTC_ADR, 0x3);
- uCRdata = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x5);
- uCRdata2 = vgarb(CRTC_DATA);
- HBE =
- (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |
- ((u16) (uSRdata & 0x03) << 6);
- HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);
-
- temp = HBE - ((E - 1) & 255);
- B = (temp > 0) ? temp : (temp + 256);
-
- temp = HRE - ((E + F + 3) & 63);
- C = (temp > 0) ? temp : (temp + 64);
-
- D = B - F - C;
-
- var->xres = var->xres_virtual = E * 8;
- var->left_margin = D * 8;
- var->right_margin = F * 8;
- var->hsync_len = C * 8;
-
- var->activate = FB_ACTIVATE_NOW;
-
- var->sync = 0;
-
- uMRdata = vgarb(0x1C);
- if (uMRdata & 0x80)
- var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
- else
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
-
- if (uMRdata & 0x40)
- var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
- else
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
-
- VT += 2;
- VT <<= 1;
- HT = (HT + 5) * 8;
-
- hrate = (double) ivideo.refresh_rate * (double) VT / 2;
- drate = hrate * HT;
- var->pixclock = (u32) (1E12 / drate);
-}
-
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
-{
- struct fb_fix_screeninfo fix;
- struct display *display;
- struct display_switch *sw;
- u32 flags;
-
- if (con >= 0)
- display = &fb_display[con];
- else
- display = &disp; /* used during initialization */
-
- sisfb_get_fix(&fix, con, 0);
-
- display->screen_base = ivideo.video_vbase;
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->line_length = fix.line_length;
- display->next_line = fix.line_length;
- /*display->can_soft_blank = 1; */
- display->can_soft_blank = 0;
- display->inverse = inverse;
- display->var = *var;
-
- save_flags(flags);
- switch (ivideo.video_bpp) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- sw = &fbcon_cfb8;
- break;
-#endif
-
-#ifdef FBCON_HAS_CFB16
- case 15:
- case 16:
- sw = &fbcon_cfb16;
- display->dispsw_data = fbcon_cmap.cfb16;
- break;
-#endif
-
-#ifdef FBCON_HAS_CFB24
- case 24:
- sw = &fbcon_cfb24;
- display->dispsw_data = fbcon_cmap.cfb24;
- break;
-#endif
-
-#ifdef FBCON_HAS_CFB32
- case 32:
- sw = &fbcon_cfb32;
- display->dispsw_data = fbcon_cmap.cfb32;
- break;
-#endif
-
- default:
- sw = &fbcon_dummy;
- return;
- }
- memcpy(&sisfb_sw, sw, sizeof(*sw));
- display->dispsw = &sisfb_sw;
- restore_flags(flags);
-
- display->scrollmode = SCROLL_YREDRAW;
- sisfb_sw.bmove = fbcon_redraw_bmove;
-}
-
-/*
- * Read a single color register and split it into colors/transparent.
- * Return != 0 for invalid regno.
- */
-
-static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
- unsigned *transp, struct fb_info *fb_info)
-{
- if (regno >= video_cmap_len)
- return 1;
-
- *red = palette[regno].red;
- *green = palette[regno].green;
- *blue = palette[regno].blue;
- *transp = 0;
- return 0;
-}
-
-/*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
- unsigned transp, struct fb_info *fb_info)
-{
-
- if (regno >= video_cmap_len)
- return 1;
-
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
-
- switch (ivideo.video_bpp) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- vgawb(DAC_ADR, regno);
- vgawb(DAC_DATA, red >> 10);
- vgawb(DAC_DATA, green >> 10);
- vgawb(DAC_DATA, blue >> 10);
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 15:
- case 16:
- fbcon_cmap.cfb16[regno] =
- ((red & 0xf800)) |
- ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
- break;
-#endif
-#ifdef FBCON_HAS_CFB24
- case 24:
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- fbcon_cmap.cfb24[regno] =
- (red << 16) | (green << 8) | (blue);
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- fbcon_cmap.cfb32[regno] =
- (red << 16) | (green << 8) | (blue);
- break;
-#endif
- }
- return 0;
-}
-
-static void do_install_cmap(int con, struct fb_info *info)
-{
- if (con != currcon)
- return;
-
- if (fb_display[con].cmap.len)
- fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
- else
- fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
- sis_setcolreg, info);
-}
-
-static int do_set_var(struct fb_var_screeninfo *var, int isactive,
- struct fb_info *info)
-{
- unsigned int htotal =
- var->left_margin + var->xres + var->right_margin +
- var->hsync_len;
- unsigned int vtotal =
- var->upper_margin + var->yres + var->lower_margin +
- var->vsync_len;
- double drate = 0, hrate = 0;
- int found_mode = 0;
-
- if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
- vtotal <<= 1;
- else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
- vtotal <<= 2;
- else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
- var->yres <<= 1;
-
-
- if (!htotal || !vtotal) {
- DPRINTK("Invalid 'var' Information!\n");
- return 1;
- }
-
- drate = 1E12 / var->pixclock;
- hrate = drate / htotal;
- ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
-
- mode_idx = 0;
- while ((sisbios_mode[mode_idx].mode_no != 0)
- && (sisbios_mode[mode_idx].xres <= var->xres)) {
- if ((sisbios_mode[mode_idx].xres == var->xres)
- && (sisbios_mode[mode_idx].yres == var->yres)
- && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) {
- mode_no = sisbios_mode[mode_idx].mode_no;
- found_mode = 1;
- break;
- }
- mode_idx++;
- }
-
- if (!found_mode) {
- printk("sisfb does not support mode %dx%d-%d\n", var->xres,
- var->yres, var->bits_per_pixel);
- return 1;
- }
-
- if (search_refresh_rate(ivideo.refresh_rate) == 0) {
- /* not supported rate */
- rate_idx = sisbios_mode[mode_idx].rate_idx;
- ivideo.refresh_rate = 60;
- }
-
- if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
- pre_setmode();
-
- if (SiSSetMode(mode_no)) {
- DPRINTK("sisfb: set mode[0x%x]: failed\n",
- mode_no);
- return 1;
- }
-
- post_setmode();
-
- ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
- ivideo.video_width = sisbios_mode[mode_idx].xres;
- ivideo.video_height = sisbios_mode[mode_idx].yres;
- video_linelength =
- ivideo.video_width * (ivideo.video_bpp >> 3);
-
- DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
- ivideo.video_width, ivideo.video_height,
- ivideo.video_bpp, video_linelength);
- }
-
- return 0;
-}
-
-/* ---------------------- Draw Funtions ----------------------------- */
-
-static void sis_get_glyph(struct GlyInfo *gly)
-{
- struct display *p = &fb_display[currcon];
- u16 c;
- u8 *cdat;
- int widthb;
- u8 *gbuf = gly->gmask;
- int size;
-
-
- gly->fontheight = fontheight(p);
- gly->fontwidth = fontwidth(p);
- widthb = (fontwidth(p) + 7) / 8;
-
- c = gly->ch & p->charmask;
- if (fontwidth(p) <= 8)
- cdat = p->fontdata + c * fontheight(p);
- else
- cdat = p->fontdata + (c * fontheight(p) << 1);
-
- size = fontheight(p) * widthb;
- memcpy(gbuf, cdat, size);
- gly->ngmask = size;
-}
-
-
-/* ---------------------- HEAP Routines ----------------------------- */
-
-/*
- * Heap Initialization
- */
-
-static int sisfb_heap_init(void)
-{
- struct OH *poh;
- u8 jTemp, tq_state;
-
- if (ivideo.video_size > 0x800000)
- /* video ram is large than 8M */
- heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
- else
- heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
-
- heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
- heap_size = heap_end - heap_start;
-
-
- /* Setting for Turbo Queue */
- if (heap_size >= TURBO_QUEUE_AREA_SIZE) {
- tqueue_pos =
- (ivideo.video_size -
- TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
- jTemp = (u8) (tqueue_pos & 0xff);
- vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
- tq_state = vgarb(SEQ_DATA);
- tq_state |= 0xf0;
- tq_state &= 0xfc;
- tq_state |= (u8) (tqueue_pos >> 8);
- vgawb(SEQ_DATA, tq_state);
- vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
- vgawb(SEQ_DATA, jTemp);
-
- caps |= TURBO_QUEUE_CAP;
-
- heap_end -= TURBO_QUEUE_AREA_SIZE;
- heap_size -= TURBO_QUEUE_AREA_SIZE;
- }
-
- /* Setting for HW cursor(4K) */
- if (heap_size >= HW_CURSOR_AREA_SIZE) {
- heap_end -= HW_CURSOR_AREA_SIZE;
- heap_size -= HW_CURSOR_AREA_SIZE;
- hwcursor_vbase = heap_end;
-
- caps |= HW_CURSOR_CAP;
- }
-
- heap.pohaChain = NULL;
- heap.pohFreeList = NULL;
-
- poh = poh_new_node();
-
- if (poh == NULL)
- return 1;
-
- /* The first node describles the entire heap size */
- poh->pohNext = &heap.ohFree;
- poh->pohPrev = &heap.ohFree;
- poh->ulSize = heap_end - heap_start + 1;
- poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase;
-
- DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
- (char *) heap_start, (char *) heap_end,
- (unsigned int) poh->ulSize / 1024);
-
- DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
- (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024);
-
- /* The second node in our free list sentinel */
- heap.ohFree.pohNext = poh;
- heap.ohFree.pohPrev = poh;
- heap.ohFree.ulSize = 0;
- heap.ulMaxFreeSize = poh->ulSize;
-
- /* Initialize the discardable list */
- heap.ohUsed.pohNext = &heap.ohUsed;
- heap.ohUsed.pohPrev = &heap.ohUsed;
- heap.ohUsed.ulSize = SENTINEL;
-
- return 0;
-}
-
-/*
- * Allocates a basic memory unit in which we'll pack our data structures.
- */
-
-static struct OH *poh_new_node(void)
-{
- int i;
- unsigned long cOhs;
- struct OHALLOC *poha;
- struct OH *poh;
-
- if (heap.pohFreeList == NULL) {
- poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
-
- poha->pohaNext = heap.pohaChain;
- heap.pohaChain = poha;
-
- cOhs =
- (OH_ALLOC_SIZE -
- sizeof(struct OHALLOC)) / sizeof(struct OH) + 1;
-
- poh = &poha->aoh[0];
- for (i = cOhs - 1; i != 0; i--) {
- poh->pohNext = poh + 1;
- poh = poh + 1;
- }
-
- poh->pohNext = NULL;
- heap.pohFreeList = &poha->aoh[0];
- }
-
- poh = heap.pohFreeList;
- heap.pohFreeList = poh->pohNext;
-
- return (poh);
-}
-
-/*
- * Allocates space, return NULL when failed
- */
-
-static struct OH *poh_allocate(unsigned long size)
-{
- struct OH *pohThis;
- struct OH *pohRoot;
- int bAllocated = 0;
-
- if (size > heap.ulMaxFreeSize) {
- DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
- (unsigned int) size / 1024);
- return (NULL);
- }
-
- pohThis = heap.ohFree.pohNext;
-
- while (pohThis != &heap.ohFree) {
- if (size <= pohThis->ulSize) {
- bAllocated = 1;
- break;
- }
- pohThis = pohThis->pohNext;
- }
-
- if (!bAllocated) {
- DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
- (unsigned int) size / 1024);
- return (NULL);
- }
-
- if (size == pohThis->ulSize) {
- pohRoot = pohThis;
- delete_node(pohThis);
- } else {
- pohRoot = poh_new_node();
-
- if (pohRoot == NULL) {
- return (NULL);
- }
-
- pohRoot->ulOffset = pohThis->ulOffset;
- pohRoot->ulSize = size;
-
- pohThis->ulOffset += size;
- pohThis->ulSize -= size;
- }
-
- heap.ulMaxFreeSize -= size;
-
- pohThis = &heap.ohUsed;
- insert_node(pohThis, pohRoot);
-
- return (pohRoot);
-}
-
-/*
- * To remove a node from a list.
- */
-
-static void delete_node(struct OH *poh)
-{
- struct OH *pohPrev;
- struct OH *pohNext;
-
-
- pohPrev = poh->pohPrev;
- pohNext = poh->pohNext;
-
- pohPrev->pohNext = pohNext;
- pohNext->pohPrev = pohPrev;
-
- return;
-}
-
-/*
- * To insert a node into a list.
- */
-
-static void insert_node(struct OH *pohList, struct OH *poh)
-{
- struct OH *pohTemp;
-
- pohTemp = pohList->pohNext;
-
- pohList->pohNext = poh;
- pohTemp->pohPrev = poh;
-
- poh->pohPrev = pohList;
- poh->pohNext = pohTemp;
-}
-
-/*
- * Frees an off-screen heap allocation.
- */
-
-static struct OH *poh_free(unsigned long base)
-{
-
- struct OH *pohThis;
- struct OH *pohFreed;
- struct OH *pohPrev;
- struct OH *pohNext;
- unsigned long ulUpper;
- unsigned long ulLower;
- int foundNode = 0;
-
- pohFreed = heap.ohUsed.pohNext;
-
- while (pohFreed != &heap.ohUsed) {
- if (pohFreed->ulOffset == base) {
- foundNode = 1;
- break;
- }
-
- pohFreed = pohFreed->pohNext;
- }
-
- if (!foundNode)
- return (NULL);
-
- heap.ulMaxFreeSize += pohFreed->ulSize;
-
- pohPrev = pohNext = NULL;
- ulUpper = pohFreed->ulOffset + pohFreed->ulSize;
- ulLower = pohFreed->ulOffset;
-
- pohThis = heap.ohFree.pohNext;
-
- while (pohThis != &heap.ohFree) {
- if (pohThis->ulOffset == ulUpper) {
- pohNext = pohThis;
- }
- else if ((pohThis->ulOffset + pohThis->ulSize) ==
- ulLower) {
- pohPrev = pohThis;
- }
- pohThis = pohThis->pohNext;
- }
-
- delete_node(pohFreed);
-
- if (pohPrev && pohNext) {
- pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);
- delete_node(pohNext);
- free_node(pohFreed);
- free_node(pohNext);
- return (pohPrev);
- }
-
- if (pohPrev) {
- pohPrev->ulSize += pohFreed->ulSize;
- free_node(pohFreed);
- return (pohPrev);
- }
-
- if (pohNext) {
- pohNext->ulSize += pohFreed->ulSize;
- pohNext->ulOffset = pohFreed->ulOffset;
- free_node(pohFreed);
- return (pohNext);
- }
-
- insert_node(&heap.ohFree, pohFreed);
-
- return (pohFreed);
-}
-
-/*
- * Frees our basic data structure allocation unit by adding it to a free
- * list.
- */
-
-static void free_node(struct OH *poh)
-{
- if (poh == NULL) {
- return;
- }
-
- poh->pohNext = heap.pohFreeList;
- heap.pohFreeList = poh;
-
- return;
-}
-
-void sis_malloc(struct sis_memreq *req)
-{
- struct OH *poh;
-
- poh = poh_allocate(req->size);
-
- if (poh == NULL) {
- req->offset = 0;
- req->size = 0;
- DPRINTK("sisfb: VMEM Allocation Failed\n");
- } else {
- DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
- (char *) (poh->ulOffset +
- (unsigned long) ivideo.video_vbase));
-
- req->offset = poh->ulOffset;
- req->size = poh->ulSize;
- }
-
-}
-
-void sis_free(unsigned long base)
-{
- struct OH *poh;
-
- poh = poh_free(base);
-
- if (poh == NULL) {
- DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
- (unsigned int) base);
- }
-
-}
-
-
-
-/* ---------------------- SetMode Routines -------------------------- */
-
-static void set_reg1(u16 port, u16 index, u16 data)
-{
- outb((u8) (index & 0xff), port);
- port++;
- outb((u8) (data & 0xff), port);
-}
-
-static void set_reg3(u16 port, u16 data)
-{
- outb((u8) (data & 0xff), port);
-}
-
-static void set_reg4(u16 port, unsigned long data)
-{
- outl((u32) (data & 0xffffffff), port);
-}
-
-static u8 get_reg1(u16 port, u16 index)
-{
- u8 data;
-
- outb((u8) (index & 0xff), port);
- port += 1;
- data = inb(port);
- return (data);
-}
-
-static u8 get_reg2(u16 port)
-{
- u8 data;
-
- data = inb(port);
-
- return (data);
-}
-
-static u32 get_reg3(u16 port)
-{
- u32 data;
-
- data = inl(port);
- return (data);
-}
-
-static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo)
-{
- u16 modeidlength;
- u16 usModeIDOffset;
- unsigned short PreviousWord,CurrentWord;
-
- return(10);
-
- modeidlength=0;
- usModeIDOffset=*((unsigned short *)(ROMAddr+0x20A)); // Get EModeIDTable
-
- CurrentWord=*((unsigned short *)(ROMAddr+usModeIDOffset)); // Offset 0x20A
- PreviousWord=*((unsigned short *)(ROMAddr+usModeIDOffset-2)); // Offset 0x20A
- while((CurrentWord!=0x2E07)||(PreviousWord!=0x0801))
- {
- modeidlength++;
- usModeIDOffset=usModeIDOffset+1; // 10 <= ExtStructSize
- CurrentWord=*((unsigned short *)(ROMAddr+usModeIDOffset));
- PreviousWord=*((unsigned short *)(ROMAddr+usModeIDOffset-2));
- }
- modeidlength++;
-
- return(modeidlength);
-}
-
-static int search_modeID(unsigned long ROMAddr, u16 ModeNo)
-{
- unsigned char ModeID;
- u16 usIDLength;
- unsigned int count = 0;
-
- ModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
- ModeID = *((unsigned char *) (ROMAddr + ModeIDOffset));
- usIDLength = get_modeID_length(ROMAddr, ModeNo);
- while (ModeID != 0xff && ModeID != ModeNo) {
- ModeIDOffset = ModeIDOffset + usIDLength;
- ModeID = *((unsigned char *) (ROMAddr + ModeIDOffset));
- if (count++ >= 0xff)
- break;
- }
- if (ModeID == 0xff)
- return (FALSE);
- else
- return (TRUE);
-}
-
-static int check_memory_size(unsigned long ROMAddr)
-{
- u16 memorysize;
- u16 modeflag;
- u16 temp;
-
- modeflag = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- ModeType = modeflag & ModeInfoFlag;
-
- memorysize = modeflag & MemoryInfoFlag;
- memorysize = memorysize >> MemorySizeShift;
- memorysize++;
-
- temp = get_reg1(P3c4, 0x14);
- temp = temp & 0x3F;
- temp++;
-
- if (temp < memorysize)
- return (FALSE);
- else
- return (TRUE);
-}
-
-static void get_mode_ptr(unsigned long ROMAddr, u16 ModeNo)
-{
- unsigned char index;
-
- StandTable = *((u16 *) (ROMAddr + 0x202));
-
- if (ModeNo <= 13)
- index = *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03));
- else {
- if (ModeType <= 0x02)
- index = 0x1B;
- else
- index = 0x0F;
- }
-
- StandTable = StandTable + 64 * index;
-
-}
-
-static void set_seq_regs(unsigned long ROMAddr)
-{
- unsigned char SRdata;
- u16 i;
-
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- SRdata = SRegs[0x01];
-#else
- set_reg1(P3c4, 0x00, 0x03);
- StandTable = StandTable + 0x05;
- SRdata = *((unsigned char *) (ROMAddr + StandTable));
-#endif
-
- SRdata = SRdata | 0x20;
- set_reg1(P3c4, 0x01, SRdata);
-
-
- for (i = 02; i <= 04; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- SRdata = SRegs[i];
-#else
- StandTable++;
- SRdata = *((unsigned char *) (ROMAddr + StandTable));
-#endif
- set_reg1(P3c4, i, SRdata);
- }
-}
-
-static void set_misc_regs(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg3(P3c2, 0x23);
-#else
- unsigned char Miscdata;
-
- StandTable++;
- Miscdata = *((unsigned char *) (ROMAddr + StandTable));
- set_reg3(P3c2, Miscdata);
-#endif
-}
-
-static void set_crtc_regs(unsigned long ROMAddr)
-{
- unsigned char CRTCdata;
- u16 i;
-
- CRTCdata = (unsigned char) get_reg1(P3d4, 0x11);
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- CRTCdata = CRTCdata & 0x7f;
-#endif
- set_reg1(P3d4, 0x11, CRTCdata);
-
- for (i = 0; i <= 0x18; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3d4, i, CRegs[i]);
-#else
- StandTable++;
- CRTCdata = *((unsigned char *) (ROMAddr + StandTable));
- set_reg1(P3d4, i, CRTCdata);
-#endif
- }
-}
-
-static void set_attregs(unsigned long ROMAddr)
-{
- unsigned char ARdata;
- u16 i;
-
- for (i = 0; i <= 0x13; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- get_reg2(P3da);
- set_reg3(P3c0, i);
- set_reg3(P3c0, ARegs[i]);
-#else
- StandTable++;
- ARdata = *((unsigned char *) (ROMAddr + StandTable));
-
- get_reg2(P3da);
- set_reg3(P3c0, i);
- set_reg3(P3c0, ARdata);
-#endif
- }
-
- get_reg2(P3da);
- set_reg3(P3c0, 0x14);
- set_reg3(P3c0, 0x00);
- get_reg2(P3da);
- set_reg3(P3c0, 0x20);
-}
-
-static void set_grc_regs(unsigned long ROMAddr)
-{
- unsigned char GRdata;
- u16 i;
-
- for (i = 0; i <= 0x08; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3ce, i, GRegs[i]);
-#else
- StandTable++;
- GRdata = *((unsigned char *) (ROMAddr + StandTable));
- set_reg1(P3ce, i, GRdata);
-#endif
- }
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- if (ModeType > ModeVGA) {
- GRdata = (unsigned char) get_reg1(P3ce, 0x05);
- GRdata = GRdata & 0xBF;
- set_reg1(P3ce, 0x05, GRdata);
- }
-#endif
-}
-
-static void ClearExt1Regs(void)
-{
- u16 i;
-
- for (i = 0x0A; i <= 0x0E; i++)
- set_reg1(P3c4, i, 0x00);
-}
-
-static u16 GetRefindexLength(unsigned long ROMAddr, u16 ModeNo)
-{
- unsigned char ModeID;
- unsigned char temp;
- u16 refindexlength;
- u16 usModeIDOffset;
- u16 usREFIndex;
- u16 usIDLength;
-
- usModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
- ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
- usIDLength = get_modeID_length(ROMAddr, ModeNo);
- while (ModeID != 0x40) {
- usModeIDOffset = usModeIDOffset + usIDLength;
- ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
- }
-
- refindexlength = 1;
- usREFIndex = *((u16 *) (ROMAddr + usModeIDOffset + 0x04));
- usREFIndex++;
- temp = *((unsigned char *) (ROMAddr + usREFIndex));
- while (temp != 0xFF) {
- refindexlength++;
- usREFIndex++;
- temp = *((unsigned char *) (ROMAddr + usREFIndex));
- }
- return (refindexlength);
-}
-
-static int get_rate_ptr(unsigned long ROMAddr, u16 ModeNo)
-{
- short index;
- u16 temp;
- u16 ulRefIndexLength;
-
- if (ModeNo < 0x14)
- return (FALSE);
-
- index = get_reg1(P3d4, 0x33);
- index = index & 0x0F;
- if (index != 0)
- index--;
-
- REFIndex = *((u16 *) (ROMAddr + ModeIDOffset + 0x04));
-
- ulRefIndexLength = GetRefindexLength(ROMAddr, ModeNo);
-
- do {
- temp = *((u16 *) (ROMAddr + REFIndex));
- if (temp == 0xFFFF)
- break;
- temp = temp & ModeInfoFlag;
- if (temp < ModeType)
- break;
-
- REFIndex = REFIndex + ulRefIndexLength;
- index--;
- } while (index >= 0);
-
- REFIndex = REFIndex - ulRefIndexLength;
- return (TRUE);
-}
-
-static void set_sync(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg3(P3c2, MReg);
-#else
- u16 sync;
- u16 temp;
-
- sync = *((u16 *) (ROMAddr + REFIndex));
- sync = sync & 0xC0;
- temp = 0x2F;
- temp = temp | sync;
- set_reg3(P3c2, temp);
-#endif
-}
-
-static void set_crt1_crtc(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- unsigned char data;
- u16 i;
-
- data = (unsigned char) get_reg1(P3d4, 0x11);
- data = data & 0x7F;
- set_reg1(P3d4, 0x11, data);
-
- for (i = 0; i <= 0x07; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x10; i <= 0x12; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x15; i <= 0x16; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x0A; i <= 0x0C; i++)
- set_reg1(P3c4, i, SRegs[i]);
-
- data = SRegs[0x0E] & 0xE0;
- set_reg1(P3c4, 0x0E, data);
-
- set_reg1(P3d4, 0x09, CRegs[0x09]);
-#else
- unsigned char index;
- unsigned char data;
- u16 i;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x02));
- CRT1Table = *((u16 *) (ROMAddr + 0x204));
- CRT1Table = CRT1Table + index * CRT1Len;
-
- data = (unsigned char) get_reg1(P3d4, 0x11);
- data = data & 0x7F;
- set_reg1(P3d4, 0x11, data);
-
- CRT1Table--;
- for (i = 0; i <= 0x05; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3d4, i, data);
- }
- for (i = 0x06; i <= 0x07; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3d4, i, data);
- }
- for (i = 0x10; i <= 0x12; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3d4, i, data);
- }
- for (i = 0x15; i <= 0x16; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3d4, i, data);
- }
- for (i = 0x0A; i <= 0x0C; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3c4, i, data);
- }
-
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- data = data & 0xE0;
- set_reg1(P3c4, 0x0E, data);
-
- data = (unsigned char) get_reg1(P3d4, 0x09);
- data = data & 0xDF;
- i = *((unsigned char *) (ROMAddr + CRT1Table));
- i = i & 0x01;
- i = i << 5;
- data = data | i;
- i = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- i = i & DoubleScanMode;
- if (i)
- data = data | 0x80;
- set_reg1(P3d4, 0x09, data);
-
- if (ModeType > 0x03)
- set_reg1(P3d4, 0x14, 0x4F);
-#endif
-}
-
-
-static void set_crt1_offset(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, 0x0E, SRegs[0x0E]);
- set_reg1(P3c4, 0x10, SRegs[0x10]);
-#else
- u16 temp, ah, al;
- u16 temp2, i;
- u16 DisplayUnit;
-
- temp = *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03));
- temp = temp >> 4;
- ScreenOffset = *((u16 *) (ROMAddr + 0x206));
- temp = *((unsigned char *) (ROMAddr + ScreenOffset + temp));
-
- temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
- temp2 = temp2 & InterlaceMode;
- if (temp2)
- temp = temp << 1;
- temp2 = ModeType - ModeEGA;
- switch (temp2) {
- case 0:
- temp2 = 1;
- break;
- case 1:
- temp2 = 2;
- break;
- case 2:
- temp2 = 4;
- break;
- case 3:
- temp2 = 4;
- break;
- case 4:
- temp2 = 6;
- break;
- case 5:
- temp2 = 8;
- break;
- }
- temp = temp * temp2;
- DisplayUnit = temp;
-
- temp2 = temp;
- temp = temp >> 8;
- temp = temp & 0x0F;
- i = get_reg1(P3c4, 0x0E);
- i = i & 0xF0;
- i = i | temp;
- set_reg1(P3c4, 0x0E, i);
-
- temp = (unsigned char) temp2;
- temp = temp & 0xFF;
- set_reg1(P3d4, 0x13, temp);
-
- temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
- temp2 = temp2 & InterlaceMode;
- if (temp2)
- DisplayUnit >>= 1;
-
- DisplayUnit = DisplayUnit << 5;
- ah = (DisplayUnit & 0xff00) >> 8;
- al = DisplayUnit & 0x00ff;
- if (al == 0)
- ah = ah + 1;
- else
- ah = ah + 2;
- set_reg1(P3c4, 0x10, ah);
-#endif
-}
-
-static u16 get_vclk_len(unsigned long ROMAddr)
-{
- u16 VCLKDataStart, vclklabel, temp;
- VCLKDataStart = *((u16 *) (ROMAddr + 0x208));
- for (temp = 0;; temp++) {
- vclklabel = *((u16 *) (ROMAddr + VCLKDataStart + temp));
- if (vclklabel == VCLKStartFreq) {
- temp = temp + 2;
- return (temp);
- }
- }
- return (0);
-}
-
-static void set_crt1_vclk(unsigned long ROMAddr)
-{
- u16 i;
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- unsigned char index, data;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
- index &= 0x03F;
- CRT1VCLKLen = get_vclk_len(ROMAddr);
- data = index * CRT1VCLKLen;
- VCLKData = *((u16 *) (ROMAddr + 0x208));
- VCLKData = VCLKData + data;
-#endif
-
- set_reg1(P3c4, 0x31, 0);
-
- for (i = 0x2B; i <= 0x2C; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, i, SRegs[i]);
-#else
- data = *((unsigned char *) (ROMAddr + VCLKData));
- set_reg1(P3c4, i, data);
- VCLKData++;
-#endif
- }
- set_reg1(P3c4, 0x2D, 0x80);
-}
-static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, 0x32, SRegs[0x32]);
- set_reg1(P3c4, 0x07, SRegs[0x07]);
-#else
-
- u16 data, data2;
- u16 VCLK;
- unsigned char index;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
- index &= 0x3F;
- CRT1VCLKLen = get_vclk_len(ROMAddr);
- data = index * CRT1VCLKLen;
- VCLKData = *((u16 *) (ROMAddr + 0x208));
- VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
-
- VCLK = *((u16 *) (ROMAddr + VCLKData));
- if (ModeNo <= 0x13)
- VCLK = 0;
-
- data = get_reg1(P3c4, 0x07);
- data = data & 0x7B;
- if (VCLK >= 150)
- data = data | 0x80;
- set_reg1(P3c4, 0x07, data);
-
- data = get_reg1(P3c4, 0x32);
- data = data & 0xD7;
- if (VCLK >= 150)
- data = data | 0x08;
- set_reg1(P3c4, 0x32, data);
-
- data2 = 0x03;
- if (VCLK > 135)
- data2 = 0x02;
- if (VCLK > 160)
- data2 = 0x01;
- if (VCLK > 260)
- data2 = 0x00;
- data = get_reg1(P3c4, 0x07);
- data = data & 0xFC;
- data = data | data2;
- set_reg1(P3c4, 0x07, data);
-#endif
-}
-
-static u16 calc_delay2(unsigned long ROMAddr, u16 key)
-{
- u16 data, index;
- unsigned char LatencyFactor[] = {
- 88, 80, 78, 72, 70, 00,
- 00, 79, 77, 71, 69, 49,
- 88, 80, 78, 72, 70, 00,
- 00, 72, 70, 64, 62, 44
- };
- index = 0;
- data = get_reg1(P3c4, 0x14);
- if (data & 0x80)
- index = index + 12;
-
- data = get_reg1(P3c4, 0x15);
- data = (data & 0xf0) >> 4;
- if (data & 0x01)
- index = index + 6;
-
- data = data >> 1;
- index = index + data;
- data = LatencyFactor[index];
-
- return (data);
-}
-
-static u16 calc_delay(unsigned long ROMAddr, u16 key)
-{
- u16 data, data2, temp0, temp1;
- unsigned char ThLowA[] = {
- 61, 3, 52, 5, 68, 7, 100, 11,
- 43, 3, 42, 5, 54, 7, 78, 11,
- 34, 3, 37, 5, 47, 7, 67, 11
- };
- unsigned char ThLowB[] = {
- 81, 4, 72, 6, 88, 8, 120, 12,
- 55, 4, 54, 6, 66, 8, 90, 12,
- 42, 4, 45, 6, 55, 8, 75, 12
- };
- unsigned char ThTiming[] = { 1, 2, 2, 3, 0, 1, 1, 2 };
-
- data = get_reg1(P3c4, 0x16);
- data = data >> 6;
- data2 = get_reg1(P3c4, 0x14);
- data2 = (data2 >> 4) & 0x0C;
- data = data | data2;
- data = data < 1;
- if (key == 0) {
- temp0 = (u16) ThLowA[data];
- temp1 = (u16) ThLowA[data + 1];
- } else {
- temp0 = (u16) ThLowB[data];
- temp1 = (u16) ThLowB[data + 1];
- }
-
- data2 = 0;
- data = get_reg1(P3c4, 0x18);
- if (data & 0x02)
- data2 = data2 | 0x01;
- if (data & 0x20)
- data2 = data2 | 0x02;
- if (data & 0x40)
- data2 = data2 | 0x04;
-
- data = temp1 * ThTiming[data2] + temp0;
- return (data);
-}
-
-
-static void set_crt1_FIFO(unsigned long ROMAddr)
-{
- u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1;
- u16 ah, bl, A, B;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
- index &= 0x3F;
- CRT1VCLKLen = get_vclk_len(ROMAddr);
- data = index * CRT1VCLKLen;
- VCLKData = *((u16 *) (ROMAddr + 0x208));
- VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
- VCLK = *((u16 *) (ROMAddr + VCLKData));
-
- MCLKOffset = *((u16 *) (ROMAddr + 0x20C));
- index = get_reg1(P3c4, 0x3A);
- index = index & 07;
- MCLKOffset = MCLKOffset + index * 5;
- MCLK = *((unsigned char *) (ROMAddr + MCLKOffset + 0x03));
-
- data2 = ModeType - 0x02;
- switch (data2) {
- case 0:
- colorth = 1;
- break;
- case 1:
- colorth = 2;
- break;
- case 2:
- colorth = 4;
- break;
- case 3:
- colorth = 4;
- break;
- case 4:
- colorth = 6;
- break;
- case 5:
- colorth = 8;
- break;
- }
-
- do {
- B = (calc_delay(ROMAddr, 0) * VCLK * colorth);
- B = B / (16 * MCLK);
- B++;
-
- A = (calc_delay(ROMAddr, 1) * VCLK * colorth);
- A = A / (16 * MCLK);
- A++;
-
- if (A < 4)
- A = 0;
- else
- A = A - 4;
-
- if (A > B)
- bl = A;
- else
- bl = B;
-
- bl++;
- if (bl > 0x13) {
- data = get_reg1(P3c4, 0x16);
- data = data >> 6;
- if (data != 0) {
- data--;
- data = data << 6;
- data2 = get_reg1(P3c4, 0x16);
- data2 = (data2 & 0x3f) | data;
- set_reg1(P3c4, 0x16, data2);
- } else
- bl = 0x13;
- }
- } while (bl > 0x13);
-
- ah = bl;
- ah = ah << 4;
- ah = ah | 0x0f;
- set_reg1(P3c4, 0x08, ah);
-
- data = bl;
- data = data & 0x10;
- data = data << 1;
- data2 = get_reg1(P3c4, 0x0F);
- data2 = data2 & 0x9f;
- data2 = data2 | data;
- set_reg1(P3c4, 0x0F, data2);
-
- data = bl + 3;
- if (data > 0x0f)
- data = 0x0f;
- set_reg1(P3c4, 0x3b, 0x00);
- data2 = get_reg1(P3c4, 0x09);
- data2 = data2 & 0xF0;
- data2 = data2 | data;
- set_reg1(P3c4, 0x09, data2);
-}
-
-static void set_crt1_FIFO2(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, 0x15, SRegs[0x15]);
-
- set_reg4(0xcf8, 0x80000050);
- set_reg4(0xcfc, 0xc5041e04);
-
- set_reg1(P3c4, 0x08, SRegs[0x08]);
- set_reg1(P3c4, 0x0F, SRegs[0x0F]);
- set_reg1(P3c4, 0x3b, 0x00);
- set_reg1(P3c4, 0x09, SRegs[0x09]);
-#else
-
- u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1;
- u16 ah, bl, B;
- unsigned long eax;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
- index &= 0x3F;
- CRT1VCLKLen = get_vclk_len(ROMAddr);
- data = index * CRT1VCLKLen;
- VCLKData = *((u16 *) (ROMAddr + 0x208));
- VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
- VCLK = *((u16 *) (ROMAddr + VCLKData));
-
- MCLKOffset = *((u16 *) (ROMAddr + 0x20C));
- index = get_reg1(P3c4, 0x1A);
- index = index & 07;
- MCLKOffset = MCLKOffset + index * 5;
- MCLK = *((u16 *) (ROMAddr + MCLKOffset + 0x03));
-
- data2 = ModeType - 0x02;
- switch (data2) {
- case 0:
- colorth = 1;
- break;
- case 1:
- colorth = 1;
- break;
- case 2:
- colorth = 2;
- break;
- case 3:
- colorth = 2;
- break;
- case 4:
- colorth = 3;
- break;
- case 5:
- colorth = 4;
- break;
- }
-
- do {
- B = (calc_delay2(ROMAddr, 0) * VCLK * colorth);
- if (B % (16 * MCLK) == 0) {
- B = B / (16 * MCLK);
- bl = B + 1;
- } else {
- B = B / (16 * MCLK);
- bl = B + 2;
- }
-
- if (bl > 0x13) {
- data = get_reg1(P3c4, 0x15);
- data = data & 0xf0;
- if (data != 0xb0) {
- data = data + 0x20;
- if (data == 0xa0)
- data = 0x30;
- data2 = get_reg1(P3c4, 0x15);
- data2 = (data2 & 0x0f) | data;
- set_reg1(P3c4, 0x15, data2);
- } else
- bl = 0x13;
- }
- } while (bl > 0x13);
-
- data2 = get_reg1(P3c4, 0x15);
- data2 = (data2 & 0xf0) >> 4;
- data2 = data2 << 24;
-
- set_reg4(0xcf8, 0x80000050);
- eax = get_reg3(0xcfc);
- eax = eax & 0x0f0ffffff;
- eax = eax | data2;
- set_reg4(0xcfc, eax);
-
- ah = bl;
- ah = ah << 4;
- ah = ah | 0x0f;
- set_reg1(P3c4, 0x08, ah);
-
- data = bl;
- data = data & 0x10;
- data = data << 1;
- data2 = get_reg1(P3c4, 0x0F);
- data2 = data2 & 0x9f;
- data2 = data2 | data;
- set_reg1(P3c4, 0x0F, data2);
-
- data = bl + 3;
- if (data > 0x0f)
- data = 0x0f;
- set_reg1(P3c4, 0x3b, 0x00);
- data2 = get_reg1(P3c4, 0x09);
- data2 = data2 & 0xF0;
- data2 = data2 | data;
- set_reg1(P3c4, 0x09, data2);
-#endif
-}
-
-static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, 0x06, SRegs[0x06]);
- set_reg1(P3c4, 0x01, SRegs[0x01]);
- set_reg1(P3c4, 0x0F, SRegs[0x0F]);
- set_reg1(P3c4, 0x21, SRegs[0x21]);
-#else
-
- u16 data, data2, data3;
-
- if (ModeNo > 0x13)
- data = *((u16 *) (ROMAddr + REFIndex + 0x00));
- else
- data = 0;
-
- data2 = 0;
- if (ModeNo > 0x13)
- if (ModeType > 0x02) {
- data2 = data2 | 0x02;
- data3 = ModeType - ModeVGA;
- data3 = data3 << 2;
- data2 = data2 | data3;
- }
-
- data = data & InterlaceMode;
- if (data)
- data2 = data2 | 0x20;
- set_reg1(P3c4, 0x06, data2);
-
- data = get_reg1(P3c4, 0x01);
- data = data & 0xF7;
- data2 = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- data2 = data2 & HalfDCLK;
- if (data2)
- data = data | 0x08;
- set_reg1(P3c4, 0x01, data);
-
- data = get_reg1(P3c4, 0x0F);
- data = data & 0xF7;
- data2 = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- data2 = data2 & LineCompareOff;
- if (data2)
- data = data | 0x08;
- set_reg1(P3c4, 0x0F, data);
-
- data = get_reg1(P3c4, 0x21);
- data = data & 0x1F;
- if (ModeType == 0x00)
- data = data | 0x60;
- else if (ModeType <= 0x02)
- data = data | 0x00;
- else
- data = data | 0xA0;
- set_reg1(P3c4, 0x21, data);
-#endif
-}
-
-static void set_interlace(unsigned long ROMAddr, u16 ModeNo)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3d4, 0x19, CRegs[0x19]);
- set_reg1(P3d4, 0x1A, CRegs[0x1A]);
-#else
-
- unsigned long Temp;
- u16 data, Temp2;
-
- Temp = (unsigned long) get_reg1(P3d4, 0x01);
- Temp++;
- Temp = Temp * 8;
-
- if (Temp == 1024)
- data = 0x0035;
- else if (Temp == 1280)
- data = 0x0048;
- else
- data = 0x0000;
-
- Temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
- Temp2 &= InterlaceMode;
- if (Temp2 == 0)
- data = 0x0000;
-
- set_reg1(P3d4, 0x19, data);
-
- Temp = (unsigned long) get_reg1(P3d4, 0x1A);
- Temp2 = (u16) (Temp & 0xFC);
- set_reg1(P3d4, 0x1A, (u16) Temp);
-
- Temp = (unsigned long) get_reg1(P3c4, 0x0f);
- Temp2 = (u16) Temp & 0xBF;
- if (ModeNo == 0x37)
- Temp2 = Temp2 | 0x40;
- set_reg1(P3d4, 0x1A, (u16) Temp2);
-#endif
-}
-
-static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh)
-{
- u16 temp;
- u16 bh, bl;
-
- bh = ah;
- bl = al;
- if (dl != 0) {
- temp = bh;
- bh = dh;
- dh = temp;
- if (dl == 1) {
- temp = bl;
- bl = dh;
- dh = temp;
- } else {
- temp = bl;
- bl = bh;
- bh = temp;
- }
- }
- set_reg3(P3c9, (u16) dh);
- set_reg3(P3c9, (u16) bh);
- set_reg3(P3c9, (u16) bl);
-}
-
-
-static void load_DAC(unsigned long ROMAddr)
-{
- u16 data, data2;
- u16 time, i, j, k;
- u16 m, n, o;
- u16 si, di, bx, dl;
- u16 al, ah, dh;
- u16 *table = VGA_DAC;
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- data = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- data = data & DACInfoFlag;
- time = 64;
- if (data == 0x00)
- table = MDA_DAC;
- if (data == 0x08)
- table = CGA_DAC;
- if (data == 0x10)
- table = EGA_DAC;
- if (data == 0x18) {
- time = 256;
- table = VGA_DAC;
- }
-#else
- time = 256;
- table = VGA_DAC;
-#endif
-
- if (time == 256)
- j = 16;
- else
- j = time;
-
- set_reg3(P3c6, 0xFF);
- set_reg3(P3c8, 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 = data2 + 0x15;
- set_reg3(P3c9, data2);
- data = data >> 2;
- }
- }
-
- if (time == 256) {
- for (i = 16; i < 32; i++) {
- data = table[i];
- for (k = 0; k < 3; k++)
- set_reg3(P3c9, data);
- }
- si = 32;
- for (m = 0; m < 9; m++) {
- di = si;
- bx = si + 0x04;
- dl = 0;
- for (n = 0; n < 3; n++) {
- for (o = 0; o < 5; o++) {
- dh = table[si];
- ah = table[di];
- al = table[bx];
- si++;
- write_DAC(dl, ah, al, dh);
- }
- si = si - 2;
- for (o = 0; o < 3; o++) {
- dh = table[bx];
- ah = table[di];
- al = table[si];
- si--;
- write_DAC(dl, ah, al, dh);
- }
- dl++;
- }
- si = si + 5;
- }
- }
-}
-
-static void display_on(void)
-{
- u16 data;
-
- data = get_reg1(P3c4, 0x01);
- data = data & 0xDF;
- set_reg1(P3c4, 0x01, data);
-}
-
-void SetMemoryClock(void)
-{
- unsigned char i;
- int idx;
-
- u8 MCLK[] = {
- 0x5A, 0x64, 0x80, 0x66, 0x00, // SDRAM
- 0xB3, 0x45, 0x80, 0x83, 0x00, // SGRAM
- 0x37, 0x61, 0x80, 0x00, 0x01, // ESDRAM
- 0x37, 0x22, 0x80, 0x33, 0x01,
- 0x37, 0x61, 0x80, 0x00, 0x01,
- 0x37, 0x61, 0x80, 0x00, 0x01,
- 0x37, 0x61, 0x80, 0x00, 0x01,
- 0x37, 0x61, 0x80, 0x00, 0x01
- };
-
- u8 ECLK[] = {
- 0x54, 0x43, 0x80, 0x00, 0x01,
- 0x53, 0x43, 0x80, 0x00, 0x01,
- 0x55, 0x43, 0x80, 0x00, 0x01,
- 0x52, 0x43, 0x80, 0x00, 0x01,
- 0x3f, 0x42, 0x80, 0x00, 0x01,
- 0x54, 0x43, 0x80, 0x00, 0x01,
- 0x54, 0x43, 0x80, 0x00, 0x01,
- 0x54, 0x43, 0x80, 0x00, 0x01
- };
-
- idx = RAMType * 5;
-
- for (i = 0x28; i <= 0x2A; i++) { // Set MCLK
- set_reg1(P3c4, i, MCLK[idx]);
- idx++;
- }
-
- idx = RAMType * 5;
- for (i = 0x2E; i <= 0x30; i++) { // Set ECLK
- set_reg1(P3c4, i, ECLK[idx]);
- idx++;
- }
-}
-
-void ClearDAC(u16 port)
-{
- int i;
-
- set_reg3(P3c8, 0x00);
- for (i = 0; i < (256 * 3); i++)
- set_reg3(P3c9, 0x00);
-}
-
-void ClearALLBuffer(void)
-{
- unsigned long AdapterMemorySize;
-
- AdapterMemorySize = get_reg1(P3c4, 0x14);
- AdapterMemorySize = AdapterMemorySize & 0x3F;
- AdapterMemorySize++;
-
- memset((char *) ivideo.video_vbase, 0, AdapterMemorySize);
-}
-
-void LongWait(void)
-{
- unsigned long temp;
-
- for (temp = 1; temp > 0;) {
- temp = get_reg2(P3da);
- temp = temp & 0x08;
- }
- for (; temp == 0;) {
- temp = get_reg2(P3da);
- temp = temp & 0x08;
- }
-}
-
-void WaitDisplay(void)
-{
- unsigned short temp;
-
- for (temp = 0; temp == 0;) {
- temp = get_reg2(P3da);
- temp = temp & 0x01;
- }
- for (; temp == 1;) {
- temp = get_reg2(P3da);
- temp = temp & 0x01;
- }
-}
-
-int TestMonitorType(unsigned short d1, unsigned short d2, unsigned short d3)
-{
- unsigned short temp;
- set_reg3(P3c6, 0xFF);
- set_reg3(P3c8, 0x00);
- set_reg3(P3c9, d1);
- set_reg3(P3c9, d2);
- set_reg3(P3c9, d3);
- WaitDisplay(); //wait horizontal retrace
- temp = get_reg2(P3c2);
- if (temp & 0x10)
- return 1;
- else
- return 0;
-}
-
-void SetRegANDOR(unsigned short Port, unsigned short Index,
- unsigned short DataAND, unsigned short DataOR)
-{
- unsigned short temp1;
- temp1 = get_reg1(Port, Index); //part1port index 02
- temp1 = (temp1 & (DataAND)) | DataOR;
- set_reg1(Port, Index, temp1);
-}
-
-
-int DetectMonitor(void)
-{
- unsigned short flag1;
- unsigned short DAC_TEST_PARMS[3] = { 0x0F, 0x0F, 0x0F };
- unsigned short DAC_CLR_PARMS[3] = { 0x00, 0x00, 0x00 };
-
- flag1 = get_reg1(P3c4, 0x38); //call BridgeisOn
- if ((flag1 & 0x20)) {
- set_reg1(P3d4, 0x30, 0x41);
- }
-
- SiSSetMode(0x2E); //set mode to 0x2E instead of 0x3
-
- ClearDAC(P3c8);
- ClearALLBuffer();
-
- LongWait();
- LongWait();
-
- flag1 = TestMonitorType(DAC_TEST_PARMS[0], DAC_TEST_PARMS[1],
- DAC_TEST_PARMS[2]);
- if (flag1 == 0) {
- flag1 = TestMonitorType(DAC_TEST_PARMS[0], DAC_TEST_PARMS[1],
- DAC_TEST_PARMS[2]);
- }
-
- if (flag1 == 1) {
- SetRegANDOR(P3d4, 0x32, ~Monitor1Sense, Monitor1Sense);
- } else {
- SetRegANDOR(P3d4, 0x32, ~Monitor1Sense, 0x0);
- }
-
- TestMonitorType(DAC_CLR_PARMS[0], DAC_CLR_PARMS[1],
- DAC_CLR_PARMS[2]);
-
- set_reg1(P3d4, 0x34, 0x4A);
-
- return 1;
-}
-
-int SiSInit300(void)
-{
- //unsigned long ROMAddr = rom_vbase;
- u16 BaseAddr = (u16) ivideo.vga_base;
- unsigned char i, temp, AGP;
- unsigned long j, k, ulTemp;
- unsigned char SR11, SR19, SR1A, SR21, SR22;
- unsigned char SR14;
- unsigned long Temp;
-
- P3c4 = BaseAddr + 0x14;
- P3d4 = BaseAddr + 0x24;
- P3c0 = BaseAddr + 0x10;
- P3ce = BaseAddr + 0x1e;
- P3c2 = BaseAddr + 0x12;
- P3ca = BaseAddr + 0x1a;
- P3c6 = BaseAddr + 0x16;
- P3c7 = BaseAddr + 0x17;
- P3c8 = BaseAddr + 0x18;
- P3c9 = BaseAddr + 0x19;
- P3da = BaseAddr + 0x2A;
-
- set_reg1(P3c4, 0x05, 0x86); // 1.Openkey
-
- SR14 = (unsigned char) get_reg1(P3c4, 0x14);
- SR19 = (unsigned char) get_reg1(P3c4, 0x19);
- SR1A = (unsigned char) get_reg1(P3c4, 0x1A);
-
- for (i = 0x06; i < 0x20; i++)
- set_reg1(P3c4, i, 0); // 2.Reset Extended register
- for (i = 0x21; i <= 0x27; i++)
- set_reg1(P3c4, i, 0); // Reset Extended register
- for (i = 0x31; i <= 0x3D; i++)
- set_reg1(P3c4, i, 0);
- for (i = 0x30; i <= 0x37; i++)
- set_reg1(P3d4, i, 0);
-
-#if 0
- if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
- // 3.Set Define Extended register
- temp = (unsigned char) SR1A;
- else {
- temp = *((unsigned char *) (ROMAddr + SoftSettingAddr));
- if ((temp & SoftDRAMType) == 0) {
- // 3.Set Define Extended register
- temp = (unsigned char) get_reg1(P3c4, 0x3A);
- }
- }
-#endif
-
- // 3.Set Define Extended register
- temp = (unsigned char) SR1A;
-
- RAMType = temp & 0x07;
- SetMemoryClock();
- for (k = 0; k < 5; k++)
- for (j = 0; j < 0xffff; j++)
- ulTemp = (unsigned long) get_reg1(P3c4, 0x05);
-
- Temp = (unsigned long) get_reg1(P3c4, 0x3C);
- Temp = Temp | 0x01;
- set_reg1(P3c4, 0x3C, (unsigned short) Temp);
- for (k = 0; k < 5; k++)
- for (j = 0; j < 0xffff; j++)
- Temp = (unsigned long) get_reg1(P3c4, 0x05);
-
- Temp = (unsigned long) get_reg1(P3c4, 0x3C);
- Temp = Temp & 0xFE;
- set_reg1(P3c4, 0x3C, (unsigned short) Temp);
- for (k = 0; k < 5; k++)
- for (j = 0; j < 0xffff; j++)
- Temp = (unsigned long) get_reg1(P3c4, 0x05);
-
- //SR07=*((unsigned char *)(ROMAddr+0xA4)); // todo
- set_reg1(P3c4, 0x07, SRegsInit[0x07]);
-#if 0
- if (HwDeviceExtension->jChipID == SIS_Glamour)
- for (i = 0x15; i <= 0x1C; i++) {
- temp = *((unsigned char *) (ROMAddr + 0xA5 + ((i - 0x15) * 8) + RAMType));
- set_reg1(P3c4, i, temp);
- }
-#endif
-
- //SR1F=*((unsigned char *)(ROMAddr+0xE5));
- set_reg1(P3c4, 0x1F, SRegsInit[0x1F]);
-
- // Get AGP
- AGP = 1;
- temp = (unsigned char) get_reg1(P3c4, 0x3A);
- temp = temp & 0x30;
- if (temp == 0x30)
- // PCI
- AGP = 0;
-
- //SR21=*((unsigned char *)(ROMAddr+0xE6));
- SR21 = SRegsInit[0x21];
- if (AGP == 0)
- SR21 = SR21 & 0xEF; // PCI
- set_reg1(P3c4, 0x21, SR21);
-
- //SR22=*((unsigned char *)(ROMAddr+0xE7));
- SR22 = SRegsInit[0x22];
- if (AGP == 1)
- SR22 = SR22 & 0x20; // AGP
- set_reg1(P3c4, 0x22, SR22);
-
- //SR23=*((unsigned char *)(ROMAddr+0xE8));
- set_reg1(P3c4, 0x23, SRegsInit[0x23]);
-
- //SR24=*((unsigned char *)(ROMAddr+0xE9));
- set_reg1(P3c4, 0x24, SRegsInit[0x24]);
-
- //SR25=*((unsigned char *)(ROMAddr+0xEA));
- set_reg1(P3c4, 0x25, SRegsInit[0x25]);
-
- //SR32=*((unsigned char *)(ROMAddr+0xEB));
- set_reg1(P3c4, 0x32, SRegsInit[0x32]);
-
- SR11 = 0x0F;
- set_reg1(P3c4, 0x11, SR11);
-
-#if 0
- if (IF_DEF_LVDS == 1) {
- //LVDS
- temp = ExtChipLVDS;
- } else if (IF_DEF_TRUMPION == 1) {
- //Trumpion
- temp = ExtChipTrumpion;
- } else {
- //301
- temp = ExtChip301;
- }
-#endif
-
- // 301;
- temp = 0x02;
- set_reg1(P3d4, 0x37, temp);
-
-#if 0
- //09/07/99 modify by domao for 630/540 MM
- if (HwDeviceExtension->jChipID == SIS_Glamour) {
- //For SiS 300 Chip
- SetDRAMSize(HwDeviceExtension);
- SetDRAMSize(HwDeviceExtension);
- } else {
- //For SiS 630/540 Chip
- //Restore SR14, SR19 and SR1A
- set_reg1(P3c4, 0x14, SR14);
- set_reg1(P3c4, 0x19, SR19);
- set_reg1(P3c4, 0x1A, SR1A);
- }
-#endif
-
- set_reg1(P3c4, 0x14, SR14);
- set_reg1(P3c4, 0x19, SR19);
- set_reg1(P3c4, 0x1A, SR1A);
- set_reg3(P3c6, 0xff);
- ClearDAC(P3c8);
- DetectMonitor();
-
-#if 0
- //sense CRT2
- GetSenseStatus(HwDeviceExtension, BaseAddr, ROMAddr);
-#endif
-
- return (TRUE);
-}
-
-static int SiSSetMode(u16 ModeNo)
-{
- //#ifndef CONFIG_FB_SIS_LINUXBIOS
- unsigned long temp;
- //#endif
-
- u16 cr30flag, cr31flag;
- unsigned long ROMAddr = rom_vbase;
- u16 BaseAddr = (u16) ivideo.vga_base;
-
- P3c4 = BaseAddr + 0x14;
- P3d4 = BaseAddr + 0x24;
- P3c0 = BaseAddr + 0x10;
- P3ce = BaseAddr + 0x1e;
- P3c2 = BaseAddr + 0x12;
- P3ca = BaseAddr + 0x1a;
- P3c6 = BaseAddr + 0x16;
- P3c7 = BaseAddr + 0x17;
- P3c8 = BaseAddr + 0x18;
- P3c9 = BaseAddr + 0x19;
- P3da = BaseAddr + 0x2A;
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- temp = search_modeID(ROMAddr, ModeNo);
-
- if (temp == 0)
- return (0);
-
- temp = check_memory_size(ROMAddr);
- if (temp == 0)
- return (0);
-#endif
-
-#if 1
- cr30flag = (unsigned char) get_reg1(P3d4, 0x30);
- if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) {
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- get_mode_ptr(ROMAddr, ModeNo);
-#endif
- set_seq_regs(ROMAddr);
- set_misc_regs(ROMAddr);
- set_crtc_regs(ROMAddr);
- set_attregs(ROMAddr);
- set_grc_regs(ROMAddr);
- ClearExt1Regs();
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- temp = get_rate_ptr(ROMAddr, ModeNo);
- if (temp) {
-#endif
- set_sync(ROMAddr);
- set_crt1_crtc(ROMAddr);
- set_crt1_offset(ROMAddr);
- set_crt1_vclk(ROMAddr);
- set_vclk_state(ROMAddr, ModeNo);
-
- if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
- set_crt1_FIFO2(ROMAddr);
- else /* SiS 300 */
- set_crt1_FIFO(ROMAddr);
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- }
-#endif
- set_crt1_mode_regs(ROMAddr, ModeNo);
- if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
- set_interlace(ROMAddr, ModeNo);
- load_DAC(ROMAddr);
-
- /* clear OnScreen */
- memset((char *) ivideo.video_vbase, 0,
- video_linelength * ivideo.video_height);
- }
-#else
- cr30flag = (unsigned char) get_reg1(P3d4, 0x30);
- if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) {
- //set_seq_regs(ROMAddr);
- {
- unsigned char SRdata;
- SRdata = SRegs[0x01] | 0x20;
- set_reg1(P3c4, 0x01, SRdata);
-
- for (i = 02; i <= 04; i++)
- set_reg1(P3c4, i, SRegs[i]);
- }
-
- //set_misc_regs(ROMAddr);
- {
- set_reg3(P3c2, 0x23);
- }
-
- //set_crtc_regs(ROMAddr);
- {
- unsigned char CRTCdata;
-
- CRTCdata = (unsigned char) get_reg1(P3d4, 0x11);
- set_reg1(P3d4, 0x11, CRTCdata);
-
- for (i = 0; i <= 0x18; i++)
- set_reg1(P3d4, i, CRegs[i]);
- }
-
- //set_attregs(ROMAddr);
- {
- for (i = 0; i <= 0x13; i++) {
- get_reg2(P3da);
- set_reg3(P3c0, i);
- set_reg3(P3c0, ARegs[i]);
- }
- get_reg2(P3da);
- set_reg3(P3c0, 0x14);
- set_reg3(P3c0, 0x00);
- get_reg2(P3da);
- set_reg3(P3c0, 0x20);
- }
-
- //set_grc_regs(ROMAddr);
- {
- for (i = 0; i <= 0x08; i++)
- set_reg1(P3ce, i, GRegs[i]);
- }
-
- //ClearExt1Regs();
- {
- for (i = 0x0A; i <= 0x0E; i++)
- set_reg1(P3c4, i, 0x00);
- }
-
- //set_sync(ROMAddr);
- {
- set_reg3(P3c2, MReg);
- }
-
- //set_crt1_crtc(ROMAddr);
- {
- unsigned char data;
-
- data = (unsigned char) get_reg1(P3d4, 0x11);
- data = data & 0x7F;
- set_reg1(P3d4, 0x11, data);
-
- for (i = 0; i <= 0x07; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x10; i <= 0x12; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x15; i <= 0x16; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x0A; i <= 0x0C; i++)
- set_reg1(P3c4, i, SRegs[i]);
-
- data = SRegs[0x0E] & 0xE0;
- set_reg1(P3c4, 0x0E, data);
-
- set_reg1(P3d4, 0x09, CRegs[0x09]);
-
- }
-
- //set_crt1_offset(ROMAddr);
- {
- set_reg1(P3c4, 0x0E, SRegs[0x0E]);
- set_reg1(P3c4, 0x10, SRegs[0x10]);
- }
-
- //set_crt1_vclk(ROMAddr);
- {
- set_reg1(P3c4, 0x31, 0);
-
- for (i = 0x2B; i <= 0x2C; i++)
- set_reg1(P3c4, i, SRegs[i]);
- set_reg1(P3c4, 0x2D, 0x80);
- }
-
- //set_vclk_state(ROMAddr, ModeNo);
- {
- set_reg1(P3c4, 0x32, SRegs[0x32]);
- set_reg1(P3c4, 0x07, SRegs[0x07]);
- }
-
- if ((ivideo.chip_id == SIS_Trojan)
- || (ivideo.chip_id == SIS_Spartan)) {
- //set_crt1_FIFO2(ROMAddr);
- set_reg1(P3c4, 0x15, SRegs[0x15]);
-
- set_reg4(0xcf8, 0x80000050);
- set_reg4(0xcfc, 0xc5041e04);
-
- set_reg1(P3c4, 0x08, SRegs[0x08]);
- set_reg1(P3c4, 0x0F, SRegs[0x0F]);
- set_reg1(P3c4, 0x3b, 0x00);
- set_reg1(P3c4, 0x09, SRegs[0x09]);
- }
-
- //set_crt1_mode_regs(ROMAddr, ModeNo);
- {
- set_reg1(P3c4, 0x06, SRegs[0x06]);
- set_reg1(P3c4, 0x01, SRegs[0x01]);
- set_reg1(P3c4, 0x0F, SRegs[0x0F]);
- set_reg1(P3c4, 0x21, SRegs[0x21]);
- }
-
- if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan)) {
- //set_interlace(ROMAddr, ModeNo);
- set_reg1(P3d4, 0x19, CRegs[0x19]);
- set_reg1(P3d4, 0x1A, CRegs[0x1A]);
- }
- load_DAC(ROMAddr);
-
- /* clear OnScreen */
- memset((char *) ivideo.video_vbase, 0,
- video_linelength * ivideo.video_height);
- }
-#endif
- cr31flag = (unsigned char) get_reg1(P3d4, 0x31);
-
- display_on();
-
- return (0);
-}
-
-static void pre_setmode(void)
-{
- vgawb(CRTC_ADR, 0x30);
- vgawb(CRTC_DATA, 0x00);
-
- vgawb(CRTC_ADR, 0x31);
- vgawb(CRTC_DATA, 0x60);
-
- DPRINTK("Setting CR33 = 0x%x\n", rate_idx & 0x0f);
-
- /* set CRT1 refresh rate */
- vgawb(CRTC_ADR, 0x33);
- vgawb(CRTC_DATA, rate_idx & 0x0f);
-}
-
-static void post_setmode(void)
-{
- u8 uTemp;
-
- /* turn on CRT1 */
- vgawb(CRTC_ADR, 0x17);
- uTemp = vgarb(CRTC_DATA);
- uTemp |= 0x80;
- vgawb(CRTC_DATA, uTemp);
-
- /* disable 24-bit palette RAM and Gamma correction */
- vgawb(SEQ_ADR, 0x07);
- uTemp = vgarb(SEQ_DATA);
- uTemp &= ~0x04;
- vgawb(SEQ_DATA, uTemp);
-}
-
-static void search_mode(const char *name)
-{
- int i = 0;
-
- if (name == NULL)
- return;
-
- while (sisbios_mode[i].mode_no != 0) {
- if (!strcmp(name, sisbios_mode[i].name)) {
- mode_idx = i;
- break;
- }
- i++;
- }
- if (mode_idx < 0)
- DPRINTK("Invalid user mode : %s\n", name);
-}
-
-static u8 search_refresh_rate(unsigned int rate)
-{
- u16 xres, yres;
- int i = 0;
-
- xres = sisbios_mode[mode_idx].xres;
- yres = sisbios_mode[mode_idx].yres;
-
- while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {
- if ((vrate[i].xres == xres) && (vrate[i].yres == yres)
- && (vrate[i].refresh == rate)) {
- rate_idx = vrate[i].idx;
- return rate_idx;
- }
- i++;
- }
-
- DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,
- yres);
-
- return 0;
-}
-
-
-
-/* ------------------ Public Routines ------------------------------- */
-
-/*
- * Get the Fixed Part of the Display
- */
-
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);
-
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, fb_info.modename);
-
- fix->smem_start = ivideo.video_base;
- if(ivideo.video_size > 0x800000)
- fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */
- else
- fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */
-
- fix->type = video_type;
- fix->type_aux = 0;
- if (ivideo.video_bpp == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_TRUECOLOR;
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = video_linelength;
- fix->mmio_start = ivideo.mmio_base;
- fix->mmio_len = MMIO_SIZE;
- fix->accel = FB_ACCEL_SIS_GLAMOUR;
- fix->reserved[0] = ivideo.video_size & 0xFFFF;
- fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
- fix->reserved[2] = caps; /* capabilities */
-
- return 0;
-}
-
-/*
- * Get the User Defined Part of the Display
- */
-
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);
-
- if (con == -1)
- memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
- else
- *var = fb_display[con].var;
- return 0;
-}
-
-/*
- * Set the User Defined Part of the Display
- */
-
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- int err;
- unsigned int cols, rows;
-
- fb_display[con].var.activate = FB_ACTIVATE_NOW;
-
- /* Set mode */
- if (do_set_var(var, con == currcon, info)) {
- crtc_to_var(var); /* return current mode to user */
- return -EINVAL;
- }
-
- /* get actual setting value */
- crtc_to_var(var);
-
- /* update display of current console */
- sisfb_set_disp(con, var);
-
- if (info->changevar)
- (*info->changevar) (con);
-
- if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
- return err;
-
- do_install_cmap(con, info);
-
- /* inform console to update struct display */
- cols = sisbios_mode[mode_idx].cols;
- rows = sisbios_mode[mode_idx].rows;
- vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
-
- return 0;
-}
-
-
-/*
- * Get the Colormap
- */
-
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);
-
- if (con == currcon)
- return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
- else if (fb_display[con].cmap.len) /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
-
- return 0;
-}
-
-/*
- * Set the Colormap
- */
-
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- int err;
-
- if (!fb_display[con].cmap.len) { /* no colormap allocated */
- err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
- if (err)
- return err;
- }
- if (con == currcon) /* current console */
- return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
- else
- fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
- return 0;
-}
-
-static int sisfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info)
-{
- switch (cmd) {
- case FBIO_ALLOC:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- sis_malloc((struct sis_memreq *) arg);
- break;
- case FBIO_FREE:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- sis_free(*(unsigned long *) arg);
- break;
- case FBIOGET_GLYPH:
- sis_get_glyph((struct GlyInfo *) arg);
- break;
- case FBIOGET_HWCINFO:
- {
- unsigned long *hwc_offset = (unsigned long *) arg;
-
- if (caps | HW_CURSOR_CAP)
- *hwc_offset = hwcursor_vbase -
- (unsigned long) ivideo.video_vbase;
- else
- *hwc_offset = 0;
-
- break;
- }
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int sisfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma)
-{
- struct fb_var_screeninfo var;
- unsigned long start;
- unsigned long off;
- u32 len;
-
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
- off = vma->vm_pgoff << PAGE_SHIFT;
-
- /* frame buffer memory */
- start = (unsigned long) ivideo.video_base;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
-
- if (off >= len) {
- /* memory mapped io */
- off -= len;
- sisfb_get_var(&var, currcon, info);
- if (var.accel_flags)
- return -EINVAL;
- start = (unsigned long) ivideo.mmio_base;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE);
- }
-
- start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
- off += start;
- vma->vm_pgoff = off >> PAGE_SHIFT;
-
-#if defined(__i386__)
- if (boot_cpu_data.x86 > 3)
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
- if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
- return 0;
-}
-
-static struct fb_ops sisfb_ops = {
- owner: THIS_MODULE,
- fb_get_fix: sisfb_get_fix,
- fb_get_var: sisfb_get_var,
- fb_set_var: sisfb_set_var,
- fb_get_cmap: sisfb_get_cmap,
- fb_set_cmap: sisfb_set_cmap,
- fb_ioctl: sisfb_ioctl,
- fb_mmap: sisfb_mmap,
-};
-
-int __init sisfb_setup(char *options)
-{
- char *this_opt;
-
- fb_info.fontname[0] = '\0';
- ivideo.refresh_rate = 0;
-
- if (!options || !*options)
- return 0;
-
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
- if (!*this_opt)
- continue;
-
- if (!strcmp(this_opt, "inverse")) {
- inverse = 1;
- fb_invert_cmaps();
- } else if (!strncmp(this_opt, "font:", 5)) {
- strcpy(fb_info.fontname, this_opt + 5);
- } else if (!strncmp(this_opt, "mode:", 5)) {
- search_mode(this_opt + 5);
- } else if (!strncmp(this_opt, "vrate:", 6)) {
- ivideo.refresh_rate =
- simple_strtoul(this_opt + 6, NULL, 0);
- } else if (!strncmp(this_opt, "off", 3)) {
- sisfb_off = 1;
- } else
- DPRINTK("invalid parameter %s\n", this_opt);
- }
- return 0;
-}
-
-static int sisfb_update_var(int con, struct fb_info *info)
-{
- return 0;
-}
-
-/*
- * Switch Console (called by fbcon.c)
- */
-
-static int sisfb_switch(int con, struct fb_info *info)
-{
- int cols, rows;
-
- DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);
-
- /* update colormap of current console */
- if (fb_display[currcon].cmap.len)
- fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
-
- fb_display[con].var.activate = FB_ACTIVATE_NOW;
-
- /* same mode, needn't change mode actually */
-
- if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo)))
- {
- currcon = con;
- return 1;
- }
-
- currcon = con;
-
- do_set_var(&fb_display[con].var, 1, info);
-
- sisfb_set_disp(con, &fb_display[con].var);
-
- /* Install new colormap */
- do_install_cmap(con, info);
-
- cols = sisbios_mode[mode_idx].cols;
- rows = sisbios_mode[mode_idx].rows;
- vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
-
- sisfb_update_var(con, info);
-
- return 1;
-
-}
-
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-
-static void sisfb_blank(int blank, struct fb_info *info)
-{
- u8 CRData;
-
- vgawb(CRTC_ADR, 0x17);
- CRData = vgarb(CRTC_DATA);
-
- if (blank > 0) /* turn off CRT1 */
- CRData &= 0x7f;
- else /* turn on CRT1 */
- CRData |= 0x80;
-
- vgawb(CRTC_ADR, 0x17);
- vgawb(CRTC_DATA, CRData);
-}
-
-int __init sisfb_init(void)
-{
- struct pci_dev *pdev = NULL;
- struct board *b;
- int pdev_valid = 0;
- unsigned char jTemp;
-
- outb(0x77, 0x80);
-
- if (sisfb_off)
- return -ENXIO;
-
- pci_for_each_dev(pdev) {
- for (b = dev_list; b->vendor; b++)
- {
- if ((b->vendor == pdev->vendor)
- && (b->device == pdev->device))
- {
- pdev_valid = 1;
- strcpy(fb_info.modename, b->name);
- ivideo.chip_id = pdev->device;
- break;
- }
- }
-
- if (pdev_valid)
- break;
- }
-
- if (!pdev_valid)
- return -1;
-
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- if (pci_enable_device(pdev))
- return -EIO;
-#endif
-
- ivideo.video_base = pci_resource_start(pdev, 0);
- if (!request_mem_region(ivideo.video_base, pci_resource_len(pdev, 0),
- "sisfb FB")) {
- printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n");
- return -ENODEV;
- }
- ivideo.mmio_base = pci_resource_start(pdev, 1);
- if (!request_mem_region(ivideo.mmio_base, pci_resource_len(pdev, 1),
- "sisfb MMIO")) {
- printk(KERN_ERR "sisfb: cannot reserve MMIO region\n");
- release_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1));
- return -ENODEV;
- }
- ivideo.vga_base = pci_resource_start(pdev, 2);
- if (!request_region(ivideo.vga_base, pci_resource_len(pdev, 2),
- "sisfb IO")) {
- printk(KERN_ERR "sisfb: cannot reserve I/O ports\n");
- release_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1));
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- return -ENODEV;
- }
- ivideo.vga_base += 0x30;
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- rom_base = 0x000C0000;
- request_region(rom_base, 32, "sisfb");
-#else
- rom_base = 0x0;
-#endif
-
- /* set passwd */
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
-
- /* Enable MMIO & PCI linear address */
- vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
- jTemp = vgarb(SEQ_DATA);
- jTemp |= SIS_PCI_ADDR_ENABLE;
- jTemp |= SIS_MEM_MAP_IO_ENABLE;
- vgawb(SEQ_DATA, jTemp);
-
- /* get video ram size by SR14 */
- vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
- ivideo.video_size = ((int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20);
-
- if (mode_idx < 0)
- mode_idx = DEFAULT_MODE; /* 0:640x480x8 */
-
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- mode_idx = DEFAULT_MODE;
- rate_idx = sisbios_mode[mode_idx].rate_idx;
- /* set to default refresh rate 60MHz */
- ivideo.refresh_rate = 60;
-#endif
-
- mode_no = sisbios_mode[mode_idx].mode_no;
-
- if (ivideo.refresh_rate != 0)
- search_refresh_rate(ivideo.refresh_rate);
-
- if (rate_idx == 0) {
- rate_idx = sisbios_mode[mode_idx].rate_idx;
- /* set to default refresh rate 60MHz */
- ivideo.refresh_rate = 60;
- }
-
- ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
- ivideo.video_width = sisbios_mode[mode_idx].xres;
- ivideo.video_height = sisbios_mode[mode_idx].yres;
- video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
-
- ivideo.video_vbase = ioremap(ivideo.video_base, ivideo.video_size);
- ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE);
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- rom_vbase = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN);
-#endif
-
- SiSInit300();
-
- printk(KERN_INFO
- "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
- ivideo.video_base, ivideo.video_vbase,
- ivideo.video_size / 1024);
- printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n",
- ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
- video_linelength);
-
- /* enable 2D engine */
- vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
- jTemp = vgarb(SEQ_DATA);
- jTemp |= SIS_2D_ENABLE;
- vgawb(SEQ_DATA, jTemp);
-
- pre_setmode();
-
- if (SiSSetMode(mode_no)) {
- DPRINTK("sisfb: set mode[0x%x]: failed\n", 0x30);
- return -1;
- }
-
- post_setmode();
-
- crtc_to_var(&default_var);
-
- fb_info.changevar = NULL;
- fb_info.node = -1;
- fb_info.fbops = &sisfb_ops;
- fb_info.disp = &disp;
- fb_info.switch_con = &sisfb_switch;
- fb_info.updatevar = &sisfb_update_var;
- fb_info.blank = &sisfb_blank;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
-
- sisfb_set_disp(-1, &default_var);
-
- if (sisfb_heap_init()) {
- DPRINTK("sisfb: Failed to enable offscreen heap\n");
- }
-
- /* to avoid the inversed bgcolor bug of the initial state */
- vc_resize_con(1, 1, 0);
-
- if (register_framebuffer(&fb_info) < 0)
- return -EINVAL;
-
- ivideo.status = CRT1;
-
- printk(KERN_INFO "fb%d: %s frame buffer device\n",
- GET_FB_IDX(fb_info.node), fb_info.modename);
-
- return 0;
-}
-
-#ifdef MODULE
-
-static char *mode = NULL;
-static unsigned int rate = 0;
-
-MODULE_PARM(mode, "s");
-MODULE_PARM(rate, "i");
-
-int init_module(void)
-{
- if (mode)
- search_mode(mode);
-
- ivideo.refresh_rate = rate;
-
- sisfb_init();
-
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_framebuffer(&fb_info);
-}
-#endif /* MODULE */
-
-
-EXPORT_SYMBOL(sis_malloc);
-EXPORT_SYMBOL(sis_free);
-
-EXPORT_SYMBOL(ivideo);
else
# for fs/nls/Config.in
define_bool CONFIG_NCPFS_NLS n
+ define_bool CONFIG_SMB_FS n
fi
mainmenu_option next_comment
{
struct buffer_head *bh;
struct inode *inode = (struct inode*)page->mapping->host;
- char *link = (char*)kmap(page);
+ char *link = kmap(page);
struct slink_front *lf;
int err;
int i, j;
int err = 0;
unsigned blocksize, bbits;
struct buffer_head *bh, *head, *wait[2], **wait_bh=wait;
- char *kaddr = (char *)kmap(page);
+ char *kaddr = kmap(page);
blocksize = inode->i_sb->s_blocksize;
if (!page->buffers)
unsigned long iblock, lblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
- unsigned long kaddr = 0;
+ char *kaddr = NULL;
int nr, i;
if (!PageLocked(page))
if (!buffer_mapped(bh)) {
if (!kaddr)
kaddr = kmap(page);
- memset((char *)(kaddr + i*blocksize), 0, blocksize);
+ memset(kaddr + i*blocksize, 0, blocksize);
flush_dcache_page(page);
set_bit(BH_Uptodate, &bh->b_state);
continue;
goto unlock;
}
- memset((char *) kmap(page) + offset, 0, length);
+ memset(kmap(page) + offset, 0, length);
flush_dcache_page(page);
kunmap(page);
int error;
struct coda_inode_info *cnp;
unsigned int len = PAGE_SIZE;
- char *p = (char*)kmap(page);
+ char *p = kmap(page);
lock_kernel();
cnp = ITOC(inode);
write_lock(&dn_lock);
prev = &inode->i_dnotify;
while ((dn = *prev) != NULL) {
- if ((dn->dn_mask & event) == 0) {
- prev = &dn->dn_next;
- continue;
- }
if (dn->dn_magic != DNOTIFY_MAGIC) {
printk(KERN_ERR "__inode_dir_notify: bad magic "
"number in dnotify_struct!\n");
- return;
+ goto out;
+ }
+ if ((dn->dn_mask & event) == 0) {
+ prev = &dn->dn_next;
+ continue;
}
fown = &dn->dn_filp->f_owner;
if (fown->pid)
}
if (changed)
redo_inode_mask(inode);
+out:
write_unlock(&dn_lock);
}
static int efs_symlink_readpage(struct file *file, struct page *page)
{
- char *link = (char*)kmap(page);
+ char *link = kmap(page);
struct buffer_head * bh;
struct inode * inode = (struct inode*)page->mapping->host;
efs_block_t size = inode->i_size;
return -ENOMEM;
new = 1;
}
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
if (new && offset)
memset(kaddr, 0, offset);
kunmap(page);
inside:
page = bprm->page[bprm->p/PAGE_SIZE];
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
}
kunmap(page);
bprm->argc--;
int hpfs_symlink_readpage(struct file *file, struct page *page)
{
- char *link = (char*)kmap(page);
+ char *link = kmap(page);
struct inode *i = (struct inode*)page->mapping->host;
struct fnode *fnode;
struct buffer_head *bh;
static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
{
struct inode *inode = (struct inode*)page->mapping->host;
- char *link = (char*)kmap(page);
+ char *link = kmap(page);
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
struct buffer_head *bh;
if (!Page_Uptodate(page))
goto async_fail;
*ppage = page;
- return (char*) kmap(page);
+ return kmap(page);
async_fail:
page_cache_release(page);
if (!page)
goto read_really;
- ctl.cache = cache = (union ncp_dir_cache *) kmap(page);
+ ctl.cache = cache = kmap(page);
ctl.head = cache->head;
if (!Page_Uptodate(page) || !ctl.head.eof)
ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
if (!ctl.page)
goto invalid_cache;
- ctl.cache = (union ncp_dir_cache *) kmap(ctl.page);
+ ctl.cache = kmap(ctl.page);
if (!Page_Uptodate(ctl.page))
goto invalid_cache;
}
ctl.ofs += 1;
ctl.page = grab_cache_page(&inode->i_data, ctl.ofs);
if (ctl.page)
- ctl.cache = (union ncp_dir_cache *) kmap(ctl.page);
+ ctl.cache = kmap(ctl.page);
}
if (ctl.cache) {
ctl.cache->dentry[ctl.idx] = newdent;
struct inode *inode = (struct inode*)page->mapping->host;
int error, length, len, cnt;
char *link;
- char *buf = (char*)kmap(page);
+ char *buf = kmap(page);
error = -ENOMEM;
for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) {
{
struct file *file = desc->file;
struct inode *inode = file->f_dentry->d_inode;
- void *buffer = (void *)kmap(page);
+ void *buffer = kmap(page);
int plus = NFS_USE_READDIRPLUS(inode);
int error;
int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page)
{
struct nfs_entry *entry = desc->entry;
- char *start = (char *)kmap(page),
+ char *start = kmap(page),
*p = start;
int loop_count = 0,
status = 0;
{
struct file *file = desc->file;
struct nfs_entry *entry = desc->entry;
- char *start = (char *)kmap(desc->page),
+ char *start = kmap(desc->page),
*p = start + desc->page_offset;
unsigned long fileid;
int loop_count = 0,
status = -ENOMEM;
goto out;
}
- p = (u32 *)kmap(page);
+ p = kmap(page);
status = NFS_PROTO(inode)->readdir(file, desc->target, p,
NFS_SERVER(inode)->dtsize, 0);
if (status >= 0) {
* This works now because the socket layer never tries to DMA
* into this buffer directly.
*/
- buffer = (char *) kmap(page);
+ buffer = kmap(page);
do {
if (count < rsize)
rsize = count;
struct nfs_page *req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
- iov->iov_base = (void *)(kmap(req->wb_page) + req->wb_offset);
+ iov->iov_base = kmap(req->wb_page) + req->wb_offset;
iov->iov_len = req->wb_bytes;
count += req->wb_bytes;
iov++;
static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
{
struct inode *inode = dentry->d_inode;
- void *buffer = (void *)kmap(page);
+ void *buffer = kmap(page);
int error;
/* We place the length at the beginning of the page,
if (!Page_Uptodate(page))
goto getlink_read_error;
*ppage = page;
- p = (u32 *) kmap(page);
+ p = kmap(page);
return (char*)(p+1);
getlink_read_error:
dentry->d_parent->d_name.name, dentry->d_name.name,
count, (long long)(page_offset(page) + offset));
- buffer = (u8 *) kmap(page) + offset;
+ buffer = kmap(page) + offset;
base = page_offset(page) + offset;
flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
struct nfs_page *req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
- iov->iov_base = (void *)(kmap(req->wb_page) + req->wb_offset);
+ iov->iov_base = kmap(req->wb_page) + req->wb_offset;
iov->iov_len = req->wb_bytes;
count += req->wb_bytes;
iov++;
return -EACCES;
}
-static int proc_permission(struct inode *inode, int mask)
+static int proc_check_root(struct inode *inode)
{
struct dentry *de, *base, *root;
struct vfsmount *our_vfsmnt, *vfsmnt, *mnt;
int res = 0;
- if (standard_permission(inode, mask) != 0)
- return -EACCES;
-
if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
return -ENOENT;
read_lock(¤t->fs->lock);
goto exit;
}
+static int proc_permission(struct inode *inode, int mask)
+{
+ if (standard_permission(inode, mask) != 0)
+ return -EACCES;
+ return proc_check_root(inode);
+}
+
static ssize_t pid_maps_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
- int error;
+ int error = -EACCES;
/* We don't need a base pointer in the /proc filesystem */
path_release(nd);
- error = proc_permission(inode, MAY_EXEC);
+ if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
+ goto out;
+ error = proc_check_root(inode);
if (error)
goto out;
static int proc_pid_readlink(struct dentry * dentry, char * buffer, int buflen)
{
- int error;
+ int error = -EACCES;
struct inode *inode = dentry->d_inode;
struct dentry *de;
struct vfsmount *mnt = NULL;
- error = proc_permission(inode, MAY_EXEC);
+ if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
+ goto out;
+ error = proc_check_root(inode);
if (error)
goto out;
static int ramfs_readpage(struct file *file, struct page * page)
{
if (!Page_Uptodate(page)) {
- memset(page_address(page), 0, PAGE_CACHE_SIZE);
+ memset(kmap(page), 0, PAGE_CACHE_SIZE);
+ kunmap(page);
flush_dcache_page(page);
SetPageUptodate(page);
}
static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
- void *addr;
-
- addr = (void *) kmap(page);
+ void *addr = kmap(page);
if (!Page_Uptodate(page)) {
memset(addr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page);
page = grab_cache_page(mapping, 0);
if (!page)
goto out;
- cachep = (struct cache_head *)kmap(page);
+ cachep = kmap(page);
memset((char*)cachep, 0, PAGE_SIZE);
goto out;
}
- cachep = (struct cache_head *)kmap(page);
+ cachep = kmap(page);
if (cachep->valid) {
/*
* OK, at least the page 0 survived and seems to be promising.
cachep->valid = 0;
goto out;
}
- index->block = (struct cache_block *) kmap(page);
+ index->block = kmap(page);
}
}
out:
page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
page = grab_cache_page(mapping, page_off>>PAGE_CACHE_SHIFT);
if (page) {
- block = (struct cache_block *)kmap(page);
+ block = kmap(page);
index->block = block;
index->space = PAGE_SIZE;
goto add_entry;
if (!PageLocked(page))
PAGE_BUG(page);
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
memset(kaddr, 0, PAGE_CACHE_SIZE);
block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
if (!PageLocked(page))
PAGE_BUG(page);
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
memcpy(bh->b_data + udf_ext0_offset(inode), kaddr, inode->i_size);
struct buffer_head *bh = NULL;
char *symlink;
int err = -EIO;
- char *p = (char *)kmap(page);
+ char *p = kmap(page);
lock_kernel();
if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
if (path == NULL)
goto out_release;
- memcpy(path, (char*)kmap(page), hlink->d_inode->i_size);
+ memcpy(path, kmap(page), hlink->d_inode->i_size);
kunmap(page);
page_cache_release(page);
wait_on_page(page);
if (!Page_Uptodate(page))
goto async_fail;
- p = (struct umsdos_dirent*)((char*)kmap(page)+offs);
+ p = (struct umsdos_dirent*)(kmap(page)+offs);
/* if this is an invalid entry (invalid name length), ignore it */
if( p->name_len > UMSDOS_MAXNAME )
goto async_fail;
}
memcpy(entry->spare,p->spare,part);
- memcpy(entry->spare+part,(char*)kmap(page2),
+ memcpy(entry->spare+part,kmap(page2),
recsize+offs-PAGE_CACHE_SIZE);
kunmap(page2);
page_cache_release(page2);
wait_on_page(page);
if (!Page_Uptodate(page))
goto async_fail;
- p = (char*)kmap(page);
+ p = kmap(page);
}
rentry = (struct umsdos_dirent *)(p+offs);
page = next_page;
goto async_fail;
}
- q = (char*)kmap(next_page);
+ q = kmap(next_page);
if (memcmp(entry->name, rentry->name, len) ||
memcmp(entry->name+len, q, entry->name_len-len)) {
kunmap(next_page);
#define MAXHOSTNAMELEN 64 /* max length of hostname */
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC HZ /* frequency at which times() counts */
+#endif
+
#endif /* _ASM_ALPHA_PARAM_H */
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
-extern unsigned long FASTCALL(kmap_high(struct page *page));
+extern void * FASTCALL(kmap_high(struct page *page));
extern void FASTCALL(kunmap_high(struct page *page));
-extern inline unsigned long kmap(struct page *page)
+static inline void *kmap(struct page *page)
{
if (in_interrupt())
BUG();
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
return kmap_high(page);
}
-extern inline void kunmap(struct page *page)
+static inline void kunmap(struct page *page)
{
if (in_interrupt())
BUG();
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic(struct page *page, enum km_type type)
{
enum fixed_addresses idx;
unsigned long vaddr;
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
__flush_tlb_one(vaddr);
- return vaddr;
+ return (void*) vaddr;
}
-extern inline void kunmap_atomic(unsigned long vaddr, enum km_type type)
+static inline void kunmap_atomic(void *kvaddr, enum km_type type)
{
#if HIGHMEM_DEBUG
+ unsigned long vaddr = (unsigned long) kvaddr;
enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
if (vaddr < FIXADDR_START) // FIXME
#define KMAP_FIX_BEGIN (0xfe400000UL)
-extern unsigned long kmap_high(struct page *page);
+extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
-extern inline unsigned long kmap(struct page *page)
+static inline void *kmap(struct page *page)
{
if (in_interrupt())
BUG();
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
return kmap_high(page);
}
-extern inline void kunmap(struct page *page)
+static inline void kunmap(struct page *page)
{
if (in_interrupt())
BUG();
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic(struct page *page, enum km_type type)
{
unsigned int idx;
unsigned long vaddr;
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = KMAP_FIX_BEGIN + idx * PAGE_SIZE;
set_pte(kmap_pte+idx, mk_pte(page, kmap_prot));
flush_hash_page(0, vaddr);
- return vaddr;
+ return (void*) vaddr;
}
-extern inline void kunmap_atomic(unsigned long vaddr, enum km_type type)
+static inline void kunmap_atomic(void *kvaddr, enum km_type type)
{
#if HIGHMEM_DEBUG
+ unsigned long vaddr = (unsigned long) kvaddr;
unsigned int idx = type + KM_TYPE_NR*smp_processor_id();
if (vaddr < KMAP_FIX_BEGIN) // FIXME
# define BPP_GP_Select 0x0800
# define BPP_GP_nFault 0x1000
-
-/*
- * Prototype for the initialization routine.
- */
-
-#ifdef __KERNEL__
-extern int bpp_init(void);
-#endif
-
#endif
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
-extern unsigned long kmap_high(struct page *page);
+extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
-extern inline unsigned long kmap(struct page *page)
+static inline void *kmap(struct page *page)
{
if (in_interrupt())
BUG();
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
return kmap_high(page);
}
-extern inline void kunmap(struct page *page)
+static inline void kunmap(struct page *page)
{
if (in_interrupt())
BUG();
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic(struct page *page, enum km_type type)
{
unsigned long idx;
unsigned long vaddr;
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = FIX_KMAP_BEGIN + idx * PAGE_SIZE;
flush_tlb_all();
#endif
- return vaddr;
+ return (void*) vaddr;
}
-extern inline void kunmap_atomic(unsigned long vaddr, enum km_type type)
+static inline void kunmap_atomic(void *kvaddr, enum km_type type)
{
#if HIGHMEM_DEBUG
+ unsigned long vaddr = (unsigned long) kvaddr;
unsigned long idx = type + KM_TYPE_NR*smp_processor_id();
#if 0
#define OPIOCGETNEXT _IOWR('O', 5, int)
#define OPIOCGETCHILD _IOWR('O', 6, int)
-
-#ifdef __KERNEL__
-int openprom_init(void);
-#endif
-
-
#endif /* _SPARC_OPENPROMIO_H */
-/* $Id: pgtable.h,v 1.105 2000/10/30 21:01:41 davem Exp $ */
+/* $Id: pgtable.h,v 1.106 2000/11/08 04:49:24 davem Exp $ */
#ifndef _SPARC_PGTABLE_H
#define _SPARC_PGTABLE_H
# define BPP_GP_Select 0x0800
# define BPP_GP_nFault 0x1000
-
-/*
- * Prototype for the initialization routine.
- */
-
-#ifdef __KERNEL__
-extern int bpp_init(void);
-#endif
-
#endif
-/* $Id: envctrl.h,v 1.2 2000/10/17 16:20:36 davem Exp $
+/* $Id: envctrl.h,v 1.3 2000/11/03 00:37:40 davem Exp $
*
* envctrl.h: Definitions for access to the i2c environment
* monitoring on Ultrasparc systems.
#define ENVCTRL_RD_ETHERNET_TEMPERATURE _IOR('p', 0x47, int)
#define ENVCTRL_RD_MTHRBD_TEMPERATURE _IOR('p', 0x48, int)
+#define ENVCTRL_RD_GLOBALADDRESS _IOR('p', 0x49, int)
+
/* Read return values for a voltage status request. */
#define ENVCTRL_VOLTAGE_POWERSUPPLY_GOOD 0x01
#define ENVCTRL_VOLTAGE_BAD 0x02
extern void * module_map (unsigned long size);
extern void module_unmap (void *addr);
-#define module_arch_init (x) (0)
+#define module_arch_init(x) (0)
#endif /* _ASM_SPARC64_MODULE_H */
#define OPIOCGETNEXT _IOWR('O', 5, int)
#define OPIOCGETCHILD _IOWR('O', 6, int)
-
-#ifdef __KERNEL__
-int openprom_init(void);
-#endif
-
-
#endif /* _SPARC64_OPENPROMIO_H */
-/* $Id */
+/* $Id: pgalloc.h,v 1.13 2000/11/06 06:59:04 davem Exp $ */
#ifndef _SPARC64_PGALLOC_H
#define _SPARC64_PGALLOC_H
/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
#define flush_icache_range(start, end) do { } while (0)
#define flush_page_to_ram(page) do { } while (0)
-extern void __flush_dcache_page(void *addr);
-#define flush_dcache_page(page) __flush_dcache_page((page)->virtual)
+
+extern void __flush_dcache_page(void *addr, int flush_icache);
+#define flush_dcache_page(page) \
+do { if ((page)->mapping && !(page)->mapping->i_mmap && !(page)->mapping->i_mmap_shared) \
+ set_bit(PG_dcache_dirty, &(page)->flags); \
+ else \
+ __flush_dcache_page((page)->virtual, \
+ (page)->mapping != NULL); \
+} while(0)
extern void __flush_dcache_range(unsigned long start, unsigned long end);
-/* $Id: pgtable.h,v 1.132 2000/10/19 00:50:16 davem Exp $
+/* $Id: pgtable.h,v 1.135 2000/11/08 04:49:24 davem Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
#ifndef __ASSEMBLY__
+#define PG_dcache_dirty PG_arch_1
+
/* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following
* hook is made available.
#define mmu_lockarea(vaddr, len) (vaddr)
#define mmu_unlockarea(vaddr, len) do { } while(0)
-extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte);
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
#define flush_icache_page(vma, pg) do { } while(0)
/* ram disk */
#define DEVICE_NAME "ramdisk"
-#define DEVICE_REQUEST rd_request
#define DEVICE_NR(device) (MINOR(device))
#define DEVICE_NO_RANDOM
#define FBIO_FREE 0x4614
#define FBIOGET_GLYPH 0x4615
#define FBIOGET_HWCINFO 0x4616
+#define FBIOPUT_MODEINFO 0x4617
+#define FBIOGET_DISPINFO 0x4618
+
#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
#define FB_TYPE_PLANES 1 /* Non interleaved planes */
#define prepare_highmem_swapout(page) page
#define replace_with_highmem(page) page
-static __inline__ unsigned long kmap(struct page * page) {
- return (unsigned long) page_address(page);
-}
+static inline void *kmap(struct page *page) { return page_address(page); }
#define kunmap(page) do { } while (0)
/* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
{
- unsigned long kaddr;
-
- kaddr = kmap(page);
- clear_user_page((void *)kaddr, vaddr);
+ clear_user_page(kmap(page), vaddr);
kunmap(page);
}
static inline void clear_highpage(struct page *page)
{
- unsigned long kaddr;
-
- kaddr = kmap(page);
- clear_page((void *)kaddr);
+ clear_page(kmap(page));
kunmap(page);
}
static inline void memclear_highpage(struct page *page, unsigned int offset, unsigned int size)
{
- unsigned long kaddr;
+ char *kaddr;
if (offset + size > PAGE_SIZE)
BUG();
kaddr = kmap(page);
- memset((void *)(kaddr + offset), 0, size);
+ memset(kaddr + offset, 0, size);
kunmap(page);
}
*/
static inline void memclear_highpage_flush(struct page *page, unsigned int offset, unsigned int size)
{
- unsigned long kaddr;
+ char *kaddr;
if (offset + size > PAGE_SIZE)
BUG();
kaddr = kmap(page);
- memset((void *)(kaddr + offset), 0, size);
+ memset(kaddr + offset, 0, size);
flush_page_to_ram(page);
kunmap(page);
}
static inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr)
{
- unsigned long vfrom, vto;
+ char *vfrom, *vto;
vfrom = kmap(from);
vto = kmap(to);
- copy_user_page((void *)vto, (void *)vfrom, vaddr);
+ copy_user_page(vto, vfrom, vaddr);
kunmap(from);
kunmap(to);
}
static inline void copy_highpage(struct page *to, struct page *from)
{
- unsigned long vfrom, vto;
+ char *vfrom, *vto;
vfrom = kmap(from);
vto = kmap(to);
- copy_page((void *)vto, (void *)vfrom);
+ copy_page(vto, vfrom);
kunmap(from);
kunmap(to);
}
#define PG_skip 10
#define PG_inactive_clean 11
#define PG_highmem 12
- /* bits 21-30 unused */
+ /* bits 21-29 unused */
+#define PG_arch_1 30
#define PG_reserved 31
* parts of the address space.
*
* PG_error is set to indicate that an I/O error occurred on this page.
+ *
+ * PG_arch_1 is an architecture specific page state bit. The generic
+ * code guarentees that this bit is cleared for a page when it first
+ * is entered into the page cache.
*/
extern mem_map_t * mem_map;
/* generic vm_area_ops exported for stackable file systems */
extern int filemap_swapout(struct page * page, struct file *file);
-extern pte_t filemap_swapin(struct vm_area_struct * vma,
- unsigned long offset, unsigned long entry);
extern int filemap_sync(struct vm_area_struct * vma, unsigned long address,
size_t size, unsigned int flags);
extern struct page *filemap_nopage(struct vm_area_struct * area,
#define PCI_DEVICE_ID_SI_620 0x0620
#define PCI_DEVICE_ID_SI_630 0x0630
#define PCI_DEVICE_ID_SI_630_VGA 0x6300
+#define PCI_DEVICE_ID_SI_730_VGA 0x7300
#define PCI_DEVICE_ID_SI_5107 0x5107
#define PCI_DEVICE_ID_SI_5300 0x5300
#define PCI_DEVICE_ID_SI_5511 0x5511
#ifndef _LINUX_SISFB
#define _LINUX_SISFB
+/* CRT2 connection */
+#define MASK_DISPTYPE_CRT2 0x04 /* Connect CRT2 */
+#define MASK_DISPTYPE_LCD 0x02 /* Connect LCD */
+#define MASK_DISPTYPE_TV 0x01 /* Connect TV */
+#define MASK_DISPTYPE_DISP2 (MASK_DISPTYPE_LCD | MASK_DISPTYPE_TV | MASK_DISPTYPE_CRT2)
+
+#define DISPTYPE_CRT1 0x00000008L
+#define DISPTYPE_CRT2 0x00000004L
+#define DISPTYPE_LCD 0x00000002L
+#define DISPTYPE_TV 0x00000001L
+#define DISPTYPE_DISP1 DISPTYPE_CRT1
+#define DISPTYPE_DISP2 (DISPTYPE_CRT2 | DISPTYPE_LCD | DISPTYPE_TV)
+#define DISPMODE_SINGLE 0x00000020L
+#define DISPMODE_MIRROR 0x00000010L
+#define DISPMODE_DUALVIEW 0x00000040L
+
+#define HASVB_NONE 0
+#define HASVB_301 1
+#define HASVB_LVDS 2
+#define HASVB_TRUMPION 3
+#define HASVB_LVDS_CHRONTEL 4
+#define HASVB_LVDS_ALL (HASVB_LVDS | HASVB_TRUMPION | HASVB_LVDS_CHRONTEL)
+
+enum _TVMODE
+{
+ TVMODE_NTSC = 0,
+ TVMODE_PAL,
+ TVMODE_HIVISION,
+ TVMODE_TOTAL
+};
+
+enum _TVPLUGTYPE
+{
+ TVPLUG_UNKNOWN = 0,
+ TVPLUG_COMPOSITE,
+ TVPLUG_SVIDEO,
+ TVPLUG_SCART,
+ TVPLUG_TOTAL
+};
+
+enum CHIPTYPE
+{
+ SiS_UNKNOWN = 0,
+ SiS_300,
+ SiS_540,
+ SiS_630,
+ SiS_630S,
+ SiS_730
+};
+
struct sis_memreq
{
unsigned long offset;
unsigned long size;
};
+/* Data for AP */
+struct mode_info
+{
+ int bpp;
+ int xres;
+ int yres;
+ int v_xres;
+ int v_yres;
+ int org_x;
+ int org_y;
+ unsigned int vrate;
+};
+
+struct ap_data
+{
+ struct mode_info minfo;
+ unsigned long iobase;
+ unsigned int mem_size;
+ unsigned long disp_state;
+ enum CHIPTYPE chip;
+};
+
+
+/* Data for kernel */
struct video_info
{
/* card parameters */
int chip_id;
- int video_size;
+ unsigned int video_size;
unsigned long video_base;
char *video_vbase;
unsigned long mmio_base;
int video_bpp;
int video_width;
int video_height;
- unsigned int refresh_rate;
- u8 status;
+ int video_vwidth;
+ int video_vheight;
+ int org_x;
+ int org_y;
+ unsigned int refresh_rate;
+
+ /* VB functions */
+ unsigned long disp_state;
+ unsigned char hasVB;
+ unsigned char TV_type;
+ unsigned char TV_plug;
};
#ifdef __KERNEL__
*/
if (nr_threads >= max_threads)
goto bad_fork_cleanup_count;
+
+ get_exec_domain(p->exec_domain);
- if (p->exec_domain && p->exec_domain->module)
- __MOD_INC_USE_COUNT(p->exec_domain->module);
if (p->binfmt && p->binfmt->module)
__MOD_INC_USE_COUNT(p->binfmt->module);
pgd_t * pgdir;
pmd_t * pgmiddle;
pte_t * pgtable;
- unsigned long maddr;
+ char *maddr;
struct page *page;
repeat:
if (write) {
maddr = kmap(page);
- memcpy((char *)maddr + (addr & ~PAGE_MASK), buf, len);
+ memcpy(maddr + (addr & ~PAGE_MASK), buf, len);
flush_page_to_ram(page);
flush_icache_page(vma, page);
kunmap(page);
} else {
maddr = kmap(page);
- memcpy(buf, (char *)maddr + (addr & ~PAGE_MASK), len);
+ memcpy(buf, maddr + (addr & ~PAGE_MASK), len);
flush_page_to_ram(page);
kunmap(page);
}
}
p = &res->sibling;
}
- printk("Trying to free nonexistent resource <%04lx-%04lx>\n", start, end);
+ printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
}
/*
fs = init_task.fs;
current->fs = fs;
atomic_inc(&fs->count);
-
+ exit_files(current);
+ current->files = init_task.files;
+ atomic_inc(¤t->files->count);
}
void __init init_idle(void)
if (PageLocked(page))
BUG();
- flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced));
+ flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced) | (1 << PG_arch_1));
page->flags = flags | (1 << PG_locked);
page_cache_get(page);
page->index = offset;
static int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
{
- unsigned long kaddr;
+ char *kaddr;
unsigned long left, count = desc->count;
if (size > count)
size = count;
kaddr = kmap(page);
- left = __copy_to_user(desc->buf, (void *)(kaddr + offset), size);
+ left = __copy_to_user(desc->buf, kaddr + offset, size);
kunmap(page);
if (left) {
static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset , unsigned long size)
{
- unsigned long kaddr;
+ char *kaddr;
ssize_t written;
unsigned long count = desc->count;
struct file *file = (struct file *) desc->buf;
set_fs(KERNEL_DS);
kaddr = kmap(page);
- written = file->f_op->write(file, (char *)kaddr + offset,
- size, &file->f_pos);
+ written = file->f_op->write(file, kaddr + offset, size, &file->f_pos);
kunmap(page);
set_fs(old_fs);
if (written < 0) {
{
struct page *new_page;
unsigned long regular_page;
- unsigned long vaddr;
+
/*
* If this is a highmem page so it can't be swapped out directly
* otherwise the b_data buffer addresses will break
if (!regular_page)
return NULL;
- vaddr = kmap(page);
- copy_page((void *)regular_page, (void *)vaddr);
+ copy_page((void *)regular_page, kmap(page));
kunmap(page);
/*
struct page * replace_with_highmem(struct page * page)
{
struct page *highpage;
- unsigned long vaddr;
if (PageHighMem(page) || !nr_free_highpages())
return page;
return page;
}
- vaddr = kmap(highpage);
- copy_page((void *)vaddr, page_address(page));
+ copy_page(kmap(highpage), page_address(page));
kunmap(highpage);
if (page->mapping)
return vaddr;
}
-unsigned long kmap_high(struct page *page)
+void *kmap_high(struct page *page)
{
unsigned long vaddr;
if (pkmap_count[PKMAP_NR(vaddr)] < 2)
BUG();
spin_unlock(&kmap_lock);
- return vaddr;
+ return (void*) vaddr;
}
void kunmap_high(struct page *page)
struct buffer_head *from)
{
struct page *p_from;
- unsigned long vfrom;
+ char *vfrom;
unsigned long flags;
p_from = from->b_page;
__save_flags(flags);
__cli();
vfrom = kmap_atomic(p_from, KM_BOUNCE_WRITE);
- memcpy(to->b_data, (char *)vfrom + bh_offset(from), to->b_size);
+ memcpy(to->b_data, vfrom + bh_offset(from), to->b_size);
kunmap_atomic(vfrom, KM_BOUNCE_WRITE);
__restore_flags(flags);
}
struct buffer_head *from)
{
struct page *p_to;
- unsigned long vto;
+ char *vto;
unsigned long flags;
p_to = to->b_page;
__save_flags(flags);
__cli();
vto = kmap_atomic(p_to, KM_BOUNCE_READ);
- memcpy((char *)vto + bh_offset(to), from->b_data, to->b_size);
+ memcpy(vto + bh_offset(to), from->b_data, to->b_size);
kunmap_atomic(vto, KM_BOUNCE_READ);
__restore_flags(flags);
}
BUG();
if (page->mapping)
BUG();
- flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced));
+ flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced) | (1 << PG_arch_1));
page->flags = flags | (1 << PG_uptodate);
add_to_page_cache_locked(page, &swapper_space, entry.val);
}
#include <linux/malloc.h>
#include <linux/vmalloc.h>
#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
{
pgd_t * dir;
unsigned long end = address + size;
+ int ret;
dir = pgd_offset_k(address);
flush_cache_all();
+ lock_kernel();
do {
pmd_t *pmd;
pmd = pmd_alloc_kernel(dir, address);
+ ret = -ENOMEM;
if (!pmd)
- return -ENOMEM;
+ break;
+ ret = -ENOMEM;
if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot))
- return -ENOMEM;
+ break;
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
+
+ ret = 0;
} while (address && (address < end));
+ unlock_kernel();
flush_tlb_all();
- return 0;
+ return ret;
}
struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
+ size += PAGE_SIZE;
addr = VMALLOC_START;
write_lock(&vmlist_lock);
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+ if ((size + addr) < addr) {
+ write_unlock(&vmlist_lock);
+ kfree(area);
+ return NULL;
+ }
if (size + addr < (unsigned long) tmp->addr)
break;
addr = tmp->size + (unsigned long) tmp->addr;
}
area->flags = flags;
area->addr = (void *)addr;
- area->size = size + PAGE_SIZE;
+ area->size = size;
area->next = *p;
*p = area;
write_unlock(&vmlist_lock);
O_TARGET := network.o
-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink
+mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched
export-objs := netsyms.o
subdir-y := core ethernet
[token ring ] p.norton@computer.org
appletalk jschlst@turbolinux.com
ax25 g4klx@g4klx.demon.co.uk
-bridge buytenh@openrock.net
+bridge buytenh@gnu.org
core alan@lxorguk.ukuu.org.uk
decnet SteveW@ACM.org
ethernet alan@lxorguk.ukuu.org.uk
error = sock_register(&pvc_family_ops);
if (error < 0) {
printk(KERN_ERR "ATMPVC: can't register (%d)",error);
- return;
+ return -EINVAL;
}
#ifdef CONFIG_ATM_CLIP
atm_clip_init();
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_fdb.c,v 1.4 2000/02/24 06:16:45 davem Exp $
+ * $Id: br_fdb.c,v 1.5 2000/11/08 05:16:40 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
static __inline__ void copy_fdb(struct __fdb_entry *ent, struct net_bridge_fdb_entry *f)
{
+ memset(ent, 0, sizeof(struct __fdb_entry));
memcpy(ent->mac_addr, f->addr.addr, ETH_ALEN);
ent->port_no = f->dst?f->dst->port_no:0;
ent->is_local = f->is_local;
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_if.c,v 1.4 2000/10/05 01:58:16 davem Exp $
+ * $Id: br_if.c,v 1.5 2000/11/08 05:16:40 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/* called under ioctl_lock */
void br_get_port_ifindices(struct net_bridge *br, int *ifindices)
{
- int i;
struct net_bridge_port *p;
- for (i=0;i<256;i++)
- ifindices[i] = 0;
-
p = br->port_list;
while (p != NULL) {
ifindices[p->port_no] = p->dev->ifindex;
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_ioctl.c,v 1.3 2000/10/05 01:58:16 davem Exp $
+ * $Id: br_ioctl.c,v 1.4 2000/11/08 05:16:40 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
{
struct __bridge_info b;
+ memset(&b, 0, sizeof(struct __bridge_info));
memcpy(&b.designated_root, &br->designated_root, 8);
memcpy(&b.bridge_id, &br->bridge_id, 8);
b.root_path_cost = br->root_path_cost;
case BRCTL_GET_PORT_LIST:
{
+ int i;
int indices[256];
+ for (i=0;i<256;i++)
+ indices[i] = 0;
+
br_get_port_ifindices(br, indices);
if (copy_to_user((void *)arg0, indices, 256*sizeof(int)))
return -EFAULT;
if ((pt = br_get_port(br, arg1)) == NULL)
return -EINVAL;
+ memset(&p, 0, sizeof(struct __port_info));
memcpy(&p.designated_root, &pt->designated_root, 8);
memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
p.port_id = pt->port_id;
case BRCTL_GET_BRIDGES:
{
+ int i;
int indices[64];
+ for (i=0;i<64;i++)
+ indices[i] = 0;
+
if (arg1 > 64)
arg1 = 64;
arg1 = br_get_bridge_ifindices(indices, arg1);
{
struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control;
- int fdmax = (msg->msg_controllen - sizeof(struct cmsghdr))/sizeof(int);
+ int fdmax = 0;
int fdnum = scm->fp->count;
struct file **fp = scm->fp->fp;
int *cmfptr;
int err = 0, i;
+ if (msg->msg_controllen > sizeof(struct cmsghdr))
+ fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr))
+ / sizeof(int));
+
if (fdnum < fdmax)
fdmax = fdnum;
msg->msg_controllen -= cmlen;
}
}
- if (i < fdnum)
+ if (i < fdnum || (fdnum && fdmax <= 0))
msg->msg_flags |= MSG_CTRUNC;
/*
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.48 2000/08/10 01:17:13 davem Exp $
+ * $Id: route.c,v 1.49 2000/11/03 01:11:58 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
&proc_dointvec},
{NET_IPV6_ROUTE_GC_MIN_INTERVAL, "gc_min_interval",
&ip6_rt_gc_min_interval, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_GC_TIMEOUT, "gc_timeout",
&ip6_rt_gc_timeout, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_GC_INTERVAL, "gc_interval",
&ip6_rt_gc_interval, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_GC_ELASTICITY, "gc_elasticity",
&ip6_rt_gc_elasticity, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_MTU_EXPIRES, "mtu_expires",
&ip6_rt_mtu_expires, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_MIN_ADVMSS, "min_adv_mss",
&ip6_rt_min_advmss, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{0}
};
#
bool ' IPX: Full internal IPX network' CONFIG_IPX_INTERN
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' IPX: SPX networking (EXPERIMENTAL)' CONFIG_SPX $CONFIG_IPX
-fi
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+# dep_tristate ' IPX: SPX networking (EXPERIMENTAL)' CONFIG_SPX $CONFIG_IPX
+#fi
static int sock_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
{
int written;
- unsigned long kaddr;
+ char *kaddr;
unsigned long count = desc->count;
struct socket *sock = (struct socket *) desc->buf;
mm_segment_t old_fs;
set_fs(KERNEL_DS);
kaddr = kmap(page);
- written = SendBuffer_async(sock,(char *)kaddr + offset,size);
+ written = SendBuffer_async(sock, kaddr + offset, size);
kunmap(page);
set_fs(old_fs);
if (written < 0) {