From c55a7913d7d7206883c5f0bbd4d26c2a5d1818d8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:39:52 -0500 Subject: [PATCH] - pre2: - Stephen Rothwell: directory notify could return with the lock held - Richard Henderson: CLOCKS_PER_SEC on alpha. - Jeff Garzik: ramfs and highmem: kmap() the page to clear it - Asit Mallick: enable the APIC in the official order - Neil Brown: avoid rd deadlock on io_request_lock by using a private rd-request function. This also avoids unnecessary request merging at this level. - Ben LaHaise: vmalloc threadign and overflow fix - Randy Dunlap: USB updates (plusb driver). PCI cacheline size. - Neil Brown: fix a raid1 on top of lvm bug that crept in in pre1 - Alan Cox: various (Athlon mmx copy, NULL ptr checks for scsi_register etc). - Al Viro: fix /proc permission check security hole. - Can-Ru Yeou: SiS301 fbcon driver - Andrew Morton: NMI oopser and kernel page fault punch through both console_lock and timerlist_lock to make sure it prints out.. - Jeff Garzik: clean up "kmap()" return type (it returns a kernel virtual address, ie a "void *"). - Jeff Garzik: network driver docs, various one-liners. - David Miller: add generic "special" flag to page flags, to be used by architectures as they see fit. Like keeping track of cache coherency issues. - David Miller: sparc64 updates, make sparc32 boot again - Davdi Millner: spel "synchronous" correctly - David Miller: networking - fix some bridge issues, and correct IPv6 sysctl entries. - Dan Aloni: make fork.c use proper macro rather than doing get_exec_domain() by hand. --- CREDITS | 3 +- Documentation/Configure.help | 17 + Documentation/cachetlb.txt | 30 +- Documentation/networking/bridge.txt | 22 +- Documentation/networking/ip-sysctl.txt | 4 +- Documentation/networking/netdevices.txt | 42 + MAINTAINERS | 12 +- Makefile | 8 +- arch/i386/Makefile | 2 +- arch/i386/kernel/apic.c | 69 +- arch/i386/kernel/bluesmoke.c | 2 +- arch/i386/kernel/entry.S | 7 +- arch/i386/kernel/setup.c | 12 +- arch/i386/kernel/traps.c | 18 +- arch/i386/lib/mmx.c | 70 +- arch/i386/mm/fault.c | 3 + arch/mips64/kernel/linux32.c | 2 +- arch/ppc/mm/init.c | 2 +- arch/sparc/kernel/ebus.c | 24 +- arch/sparc/kernel/pcic.c | 2 +- arch/sparc/mm/init.c | 5 +- arch/sparc/mm/srmmu.c | 4 +- arch/sparc/mm/sun4c.c | 7 +- arch/sparc/vmlinux.lds | 3 + arch/sparc64/kernel/ebus.c | 29 +- arch/sparc64/kernel/ioctl32.c | 20 +- arch/sparc64/kernel/pci.c | 2 +- arch/sparc64/kernel/process.c | 17 +- arch/sparc64/kernel/sparc64_ksyms.c | 3 +- arch/sparc64/kernel/sys_sparc32.c | 4 +- arch/sparc64/lib/Makefile | 5 +- arch/sparc64/lib/U3copy_from_user.S | 500 +++++ arch/sparc64/lib/U3copy_in_user.S | 531 +++++ arch/sparc64/lib/U3copy_to_user.S | 528 +++++ arch/sparc64/lib/U3memcpy.S | 409 ++++ arch/sparc64/lib/VIScopy.S | 34 +- arch/sparc64/mm/init.c | 16 +- arch/sparc64/mm/ultra.S | 67 +- arch/sparc64/vmlinux.lds | 3 + drivers/acpi/driver.c | 2 +- drivers/block/loop.c | 2 +- drivers/block/rd.c | 52 +- drivers/i2o/i2o_block.c | 2 +- drivers/i2o/i2o_core.c | 2 - drivers/ide/Makefile | 2 +- drivers/isdn/act2000/module.c | 31 - drivers/isdn/hisax/hfc_pci.c | 46 +- drivers/isdn/pcbit/drv.c | 12 +- drivers/isdn/sc/debug.c | 7 +- drivers/md/lvm.c | 2 +- drivers/md/md.c | 5 +- drivers/md/raid1.c | 2 +- drivers/net/8139too.c | 2 +- drivers/net/de4x5.c | 39 +- drivers/net/fc/iph5526.c | 3 + drivers/net/rrunner.c | 59 +- drivers/net/sis900.c | 99 +- drivers/net/sis900.h | 7 +- drivers/pcmcia/cardbus.c | 2 +- drivers/sbus/char/aurora.c | 19 +- drivers/sbus/char/bpp.c | 13 +- drivers/sbus/char/display7seg.c | 15 +- drivers/sbus/char/envctrl.c | 131 +- drivers/sbus/char/flash.c | 15 +- drivers/sbus/char/openprom.c | 13 +- drivers/sbus/char/uctrl.c | 16 +- drivers/sbus/sbus.c | 29 +- drivers/scsi/3w-xxxx.c | 9 +- drivers/scsi/aha152x.c | 4 +- drivers/scsi/esp.c | 6 +- drivers/scsi/ips.c | 2 + drivers/scsi/megaraid.c | 20 +- drivers/scsi/scsi_error.c | 3 - drivers/scsi/scsi_obsolete.c | 2 +- drivers/scsi/sr_ioctl.c | 2 +- drivers/sound/i810_audio.c | 103 +- drivers/usb/hub.c | 4 +- drivers/usb/plusb.c | 794 +++++-- drivers/usb/plusb.h | 48 - drivers/usb/usb.c | 11 +- drivers/video/Makefile | 11 +- drivers/video/sis/Makefile | 12 + drivers/video/sis/initdef.h | 138 ++ drivers/video/sis/sis.h | 64 + drivers/video/sis/sis_300.c | 1523 +++++++++++++ drivers/video/sis/sis_300.h | 162 ++ drivers/video/sis/sis_301.c | 2867 ++++++++++++++++++++++++ drivers/video/sis/sis_301.h | 223 ++ drivers/video/sis/sis_main.c | 2373 ++++++++++++++++++++ drivers/video/sisfb.c | 3619 ------------------------------- fs/Config.in | 1 + fs/affs/symlink.c | 2 +- fs/buffer.c | 8 +- fs/coda/symlink.c | 2 +- fs/dnotify.c | 11 +- fs/efs/symlink.c | 2 +- fs/exec.c | 4 +- fs/hpfs/namei.c | 2 +- fs/isofs/rock.c | 2 +- fs/namei.c | 2 +- fs/ncpfs/dir.c | 6 +- fs/ncpfs/symlink.c | 2 +- fs/nfs/dir.c | 8 +- fs/nfs/read.c | 4 +- fs/nfs/symlink.c | 4 +- fs/nfs/write.c | 4 +- fs/proc/base.c | 24 +- fs/ramfs/inode.c | 7 +- fs/smbfs/cache.c | 8 +- fs/udf/file.c | 4 +- fs/udf/symlink.c | 2 +- fs/umsdos/dir.c | 2 +- fs/umsdos/emd.c | 8 +- include/asm-alpha/param.h | 4 + include/asm-i386/highmem.h | 17 +- include/asm-ppc/highmem.h | 17 +- include/asm-sparc/bpp.h | 9 - include/asm-sparc/highmem.h | 17 +- include/asm-sparc/openpromio.h | 6 - include/asm-sparc/pgtable.h | 2 +- include/asm-sparc64/bpp.h | 9 - include/asm-sparc64/envctrl.h | 4 +- include/asm-sparc64/module.h | 2 +- include/asm-sparc64/openpromio.h | 6 - include/asm-sparc64/pgalloc.h | 13 +- include/asm-sparc64/pgtable.h | 6 +- include/linux/blk.h | 1 - include/linux/fb.h | 3 + include/linux/highmem.h | 30 +- include/linux/mm.h | 9 +- include/linux/pci_ids.h | 1 + include/linux/sisfb.h | 89 +- kernel/fork.c | 4 +- kernel/ptrace.c | 6 +- kernel/resource.c | 2 +- kernel/sched.c | 4 +- mm/filemap.c | 11 +- mm/highmem.c | 21 +- mm/swap_state.c | 2 +- mm/vmalloc.c | 22 +- net/Makefile | 2 +- net/README | 2 +- net/atm/pvc.c | 2 +- net/bridge/br_fdb.c | 3 +- net/bridge/br_if.c | 6 +- net/bridge/br_ioctl.c | 12 +- net/core/scm.c | 8 +- net/ipv6/route.c | 14 +- net/ipx/Config.in | 6 +- net/khttpd/datasending.c | 4 +- 150 files changed, 11071 insertions(+), 4591 deletions(-) rewrite Documentation/networking/bridge.txt (78%) create mode 100644 Documentation/networking/netdevices.txt create mode 100644 arch/sparc64/lib/U3copy_from_user.S create mode 100644 arch/sparc64/lib/U3copy_in_user.S create mode 100644 arch/sparc64/lib/U3copy_to_user.S create mode 100644 arch/sparc64/lib/U3memcpy.S delete mode 100644 drivers/usb/plusb.h create mode 100644 drivers/video/sis/Makefile create mode 100644 drivers/video/sis/initdef.h create mode 100644 drivers/video/sis/sis.h create mode 100644 drivers/video/sis/sis_300.c create mode 100644 drivers/video/sis/sis_300.h create mode 100644 drivers/video/sis/sis_301.c create mode 100644 drivers/video/sis/sis_301.h create mode 100644 drivers/video/sis/sis_main.c delete mode 100644 drivers/video/sisfb.c diff --git a/CREDITS b/CREDITS index db47eeb14..dc9c00be9 100644 --- a/CREDITS +++ b/CREDITS @@ -2240,11 +2240,12 @@ S: D-68789 St.Leon-Rot 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 diff --git a/Documentation/Configure.help b/Documentation/Configure.help index eace57a6c..f0da27c5b 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -2052,6 +2052,23 @@ CONFIG_IP_NF_COMPAT_IPFWADM 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 diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt index 952dbc652..5201a2f54 100644 --- a/Documentation/cachetlb.txt +++ b/Documentation/cachetlb.txt @@ -305,19 +305,23 @@ Here is the new interface: 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. diff --git a/Documentation/networking/bridge.txt b/Documentation/networking/bridge.txt dissimilarity index 78% index 043a14b16..66ffb4c1f 100644 --- a/Documentation/networking/bridge.txt +++ b/Documentation/networking/bridge.txt @@ -1,11 +1,11 @@ -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. - - - -Lennert Buytenhek - +In order to use the ethernet bridging functionality you'll need the +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 + diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index aade6928c..419906891 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -203,7 +203,7 @@ tcp_fack - BOOLEAN tcp_dsack - BOOLEAN Allows TCP to send "duplicate" SACKs. -tcp_ecn - BOOLEN +tcp_ecn - BOOLEAN Enable Explicit Congestion Notification in TCP. tcp_reordering - INTEGER @@ -376,4 +376,4 @@ kuznet@ms2.inr.ac.ru 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 $ diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt new file mode 100644 index 000000000..8769040b3 --- /dev/null +++ b/Documentation/networking/netdevices.txt @@ -0,0 +1,42 @@ + +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 + + diff --git a/MAINTAINERS b/MAINTAINERS index 4682b40e2..2b7cfc0a6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -353,6 +353,12 @@ W: http://www.dgii.com/linux,http://lameter.com/digi 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 @@ -411,9 +417,9 @@ S: Maintained 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 diff --git a/Makefile b/Makefile index ccd736426..8b4b7d0af 100644 --- a/Makefile +++ b/Makefile @@ -356,9 +356,8 @@ endif 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 @@ -392,8 +391,7 @@ mrproper: clean archmrproper 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 diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 96da8d33b..0a2d802a3 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -63,7 +63,7 @@ CFLAGS += $(shell if $(CC) -march=athlon -S -o /dev/null -xc /dev/null >/dev/nul endif ifdef CONFIG_MCRUSOE -CFLAGS += -march=i586 +CFLAGS += -march=i686 -malign-functions=0 -malign-jumps=0 -malign-loops=0 endif ifdef CONFIG_MWINCHIPC6 diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 4e5df4681..fc54896f8 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -219,39 +219,6 @@ void __init setup_local_APIC (void) 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: * @@ -323,6 +290,42 @@ void __init setup_local_APIC (void) * 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) diff --git a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c index ee6966d5f..79ab9a5ff 100644 --- a/arch/i386/kernel/bluesmoke.c +++ b/arch/i386/kernel/bluesmoke.c @@ -10,7 +10,7 @@ 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; diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 4ae0ed2ee..5e3c91019 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -383,11 +383,6 @@ ENTRY(coprocessor_segment_overrun) 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 @@ -418,7 +413,7 @@ ENTRY(page_fault) ENTRY(machine_check) pushl $0 - pushl $ SYMBOL_NAME(mcheck_fault) + pushl $ SYMBOL_NAME(do_machine_check) jmp error_code ENTRY(spurious_interrupt_bug) diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 7ac7fdb36..b22adbd47 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -971,6 +971,16 @@ static int __init amd_model(struct cpuinfo_x86 *c) 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); +} /* @@ -1548,7 +1558,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) /* Pentium IV. */ if (c->x86 == 15) { - get_model_name(c); + intel_model(c); return; } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index ae87ded92..aa2deb8ae 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -92,7 +92,6 @@ asmlinkage void general_protection(void); 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); @@ -312,7 +311,6 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) 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) { @@ -396,9 +394,20 @@ static int __init setup_nmi_watchdog(char *str) __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) { /* @@ -439,8 +448,7 @@ 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"); diff --git a/arch/i386/lib/mmx.c b/arch/i386/lib/mmx.c index 0314041f9..4aca07e72 100644 --- a/arch/i386/lib/mmx.c +++ b/arch/i386/lib/mmx.c @@ -16,6 +16,9 @@ * 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) @@ -104,28 +107,26 @@ static void fast_clear_page(void *page) " 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(); } @@ -140,6 +141,9 @@ static void fast_copy_page(void *to, void *from) 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" @@ -162,21 +166,21 @@ static void fast_copy_page(void *to, void *from) __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" @@ -189,6 +193,12 @@ static void fast_copy_page(void *to, void *from) from+=64; to+=64; } + /* since movntq is weakly-ordered, a "sfence" is needed to become + * ordered again. + */ + __asm__ __volatile__ ( + " sfence \n" : : + ); stts(); } diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 946d1f40a..96b67925f 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -24,6 +24,7 @@ #include extern void die(const char *,struct pt_regs *,long); +extern void bust_spinlocks(void); /* * Ugly, ugly, but the goto's result in better assembly.. @@ -251,6 +252,8 @@ no_context: * terminate things with extreme prejudice. */ + bust_spinlocks(); + if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else diff --git a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c index 8d6bc8c45..810ef9202 100644 --- a/arch/mips64/kernel/linux32.c +++ b/arch/mips64/kernel/linux32.c @@ -241,7 +241,7 @@ int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm) return -ENOMEM; new = 1; } - kaddr = (char *)kmap(page); + kaddr = kmap(page); if (new && offset) memset(kaddr, 0, offset); diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index cc8d2290a..2c17e7bcb 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -630,7 +630,7 @@ mmu_context_overflow(void) 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); } diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c index f61be9932..00c465b10 100644 --- a/arch/sparc/kernel/ebus.c +++ b/arch/sparc/kernel/ebus.c @@ -1,4 +1,4 @@ -/* $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) @@ -24,18 +24,9 @@ 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); @@ -367,20 +358,7 @@ void __init ebus_init(void) ++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 } diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index ba86e3d64..e7b4e96de 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -1,4 +1,4 @@ -/* $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 diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 9cbbb1c9c..a8f5fb9c2 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -579,8 +579,7 @@ void si_meminfo(struct sysinfo *val) 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); } diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index a91809d03..b32199c13 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $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) @@ -1163,7 +1163,7 @@ extern int linux_num_cpus; 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) diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index a416ecf19..edba89672 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $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) @@ -2509,7 +2509,7 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p 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); @@ -2524,7 +2524,8 @@ void __init sun4c_paging_init(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 diff --git a/arch/sparc/vmlinux.lds b/arch/sparc/vmlinux.lds index bba19d4c5..e449e26fa 100644 --- a/arch/sparc/vmlinux.lds +++ b/arch/sparc/vmlinux.lds @@ -31,6 +31,9 @@ SECTIONS __start___ksymtab = .; __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; . = ALIGN(4096); __init_begin = .; diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 5872046b1..e175fac27 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -1,4 +1,4 @@ -/* $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) @@ -22,21 +22,9 @@ 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) { @@ -372,24 +360,9 @@ void __init ebus_init(void) ++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(); } diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 9f7cd59e9..10e7ccc9c 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $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) @@ -73,6 +73,7 @@ #include #include #include +#include #include #include @@ -3230,6 +3231,7 @@ COMPATIBLE_IOCTL(ENVCTRL_RD_SCSI_TEMPERATURE) 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) @@ -3467,6 +3469,14 @@ COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN) 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 */ @@ -3492,6 +3502,14 @@ COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN) 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 */ diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 626615da0..1abef824f 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -1,4 +1,4 @@ -/* $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) diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 1f3386d53..4534ad59b 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $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) @@ -647,14 +647,21 @@ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { 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. */ @@ -662,7 +669,7 @@ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) "=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; } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 6e7f59309..20d8a1a43 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,4 +1,4 @@ -/* $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) @@ -87,7 +87,6 @@ extern long sparc32_open(const char * filename, int flags, int mode); 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); diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 24c8cd593..71676e05d 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -2952,7 +2952,7 @@ static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm) return -ENOMEM; new = 1; } - kaddr = (char *)kmap(page); + kaddr = kmap(page); if (new && offset) memset(kaddr, 0, offset); @@ -2967,7 +2967,7 @@ static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm) 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; diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index fa057936a..77531321d 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -1,4 +1,4 @@ -# $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.. # @@ -8,7 +8,8 @@ OBJS = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ 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) diff --git a/arch/sparc64/lib/U3copy_from_user.S b/arch/sparc64/lib/U3copy_from_user.S new file mode 100644 index 000000000..b1003e607 --- /dev/null +++ b/arch/sparc64/lib/U3copy_from_user.S @@ -0,0 +1,500 @@ +/* $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 +#include +#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 diff --git a/arch/sparc64/lib/U3copy_in_user.S b/arch/sparc64/lib/U3copy_in_user.S new file mode 100644 index 000000000..0fc169b9d --- /dev/null +++ b/arch/sparc64/lib/U3copy_in_user.S @@ -0,0 +1,531 @@ +/* $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 +#include +#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) */ diff --git a/arch/sparc64/lib/U3copy_to_user.S b/arch/sparc64/lib/U3copy_to_user.S new file mode 100644 index 000000000..e08b1290b --- /dev/null +++ b/arch/sparc64/lib/U3copy_to_user.S @@ -0,0 +1,528 @@ +/* $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 +#include +#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) */ diff --git a/arch/sparc64/lib/U3memcpy.S b/arch/sparc64/lib/U3memcpy.S new file mode 100644 index 000000000..d38289145 --- /dev/null +++ b/arch/sparc64/lib/U3memcpy.S @@ -0,0 +1,409 @@ +/* $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 +#include +#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) */ diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S index 56634f83f..b944a0ae7 100644 --- a/arch/sparc64/lib/VIScopy.S +++ b/arch/sparc64/lib/VIScopy.S @@ -1,4 +1,4 @@ -/* $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. * @@ -361,6 +361,38 @@ bcopy: or %o0, 0, %g3 ! IEU0 Group 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: diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 65fbd6e37..6da2d0b85 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $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) @@ -99,6 +99,20 @@ int do_check_pgt_cache(int low, int high) 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 diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 7940218d2..daaf580a0 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,4 +1,4 @@ -/* $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) @@ -208,27 +208,58 @@ iflush2:sub %o1, 0x20, %g3 .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: @@ -250,8 +281,8 @@ __prefill_itlb: 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 */ diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds index f686decfb..91d4575d0 100644 --- a/arch/sparc64/vmlinux.lds +++ b/arch/sparc64/vmlinux.lds @@ -35,6 +35,9 @@ SECTIONS __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; __kstrtab : { *(.kstrtab) } + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; . = ALIGN(8192); __init_begin = .; .text.init : { *(.text.init) } diff --git a/drivers/acpi/driver.c b/drivers/acpi/driver.c index 58da76eb0..411e07fcb 100644 --- a/drivers/acpi/driver.c +++ b/drivers/acpi/driver.c @@ -284,7 +284,7 @@ acpi_thread(void *context) /* * initialize */ - exit_files(current); + daemonize(); strcpy(current->comm, "acpi"); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 329d10c9c..ae8489380 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -235,7 +235,7 @@ static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned l 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", diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 6f583c3de..6a2352281 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -194,50 +194,47 @@ __setup("ramdisk_blocksize=", ramdisk_blocksize); * 19-JAN-1998 Richard Gooch 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) @@ -378,7 +375,6 @@ static void __exit rd_cleanup (void) 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; @@ -403,7 +399,7 @@ int __init rd_init (void) 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 */ diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c index 76ddf7c38..8389039d6 100644 --- a/drivers/i2o/i2o_block.c +++ b/drivers/i2o/i2o_block.c @@ -584,7 +584,6 @@ static int i2ob_evt(void *dummy) int i; lock_kernel(); - exit_files(current); daemonize(); unlock_kernel(); @@ -593,6 +592,7 @@ static int i2ob_evt(void *dummy) while(1) { +#warning "RACE" interruptible_sleep_on(&i2ob_evt_wait); if(signal_pending(current)) { evt_running = 0; diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c index 87871fa15..e9942c614 100644 --- a/drivers/i2o/i2o_core.c +++ b/drivers/i2o/i2o_core.c @@ -842,7 +842,6 @@ static int i2o_core_evt(void *reply_data) int flags; lock_kernel(); - exit_files(current); daemonize(); unlock_kernel(); @@ -1005,7 +1004,6 @@ static int i2o_dyn_lct(void *foo) char name[16]; lock_kernel(); - exit_files(current); daemonize(); unlock_kernel(); diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index d5b4b637e..f85ab2aa4 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -31,7 +31,7 @@ ide-obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o 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 diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c index 158d9463e..2e9eb02df 100644 --- a/drivers/isdn/act2000/module.c +++ b/drivers/isdn/act2000/module.c @@ -563,37 +563,6 @@ act2000_readstatus(u_char * buf, int len, int user, act2000_card * card) 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 */ diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index b61f397d2..ac0392251 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -31,6 +31,7 @@ #include "isdnl1.h" #include #include +#include extern const char *CardType[]; @@ -1631,11 +1632,9 @@ static struct pci_dev *dev_hfcpci __initdata = NULL; #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; @@ -1645,15 +1644,11 @@ __initfunc(int #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, @@ -1686,41 +1681,6 @@ __initfunc(int 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); diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index cd58e0d3b..125742e6a 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -114,9 +114,9 @@ int pcbit_init_dev(int board, int mem_base, int irq) 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; } @@ -124,9 +124,9 @@ int pcbit_init_dev(int board, int mem_base, int irq) 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; } @@ -148,9 +148,9 @@ int pcbit_init_dev(int board, int mem_base, int irq) { 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; } @@ -170,9 +170,9 @@ int pcbit_init_dev(int board, int mem_base, int irq) 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; } @@ -201,9 +201,9 @@ int pcbit_init_dev(int board, int mem_base, int irq) 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; } @@ -239,9 +239,9 @@ void pcbit_terminate(int board) 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 diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c index b1bdf57af..7d24ed731 100644 --- a/drivers/isdn/sc/debug.c +++ b/drivers/isdn/sc/debug.c @@ -27,11 +27,6 @@ */ #include -#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; @@ -61,7 +56,7 @@ inline char *strcpy(char *dest, const char *src) *i = *j; i++; j++; } - *(++i) = NULL; + *(++i) = 0; return dest; } diff --git a/drivers/md/lvm.c b/drivers/md/lvm.c index 239ed99aa..5aa88df9e 100644 --- a/drivers/md/lvm.c +++ b/drivers/md/lvm.c @@ -1928,7 +1928,7 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) { 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; diff --git a/drivers/md/md.c b/drivers/md/md.c index c89314c78..a20e2d9d0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2836,14 +2836,13 @@ int md_thread(void * arg) 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(); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 3f68a8e0a..85073b564 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -374,7 +374,7 @@ static void raid1_end_bh_io (struct raid1_bh *r1_bh, int uptodate) { 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); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index f47ee2462..b26b06302 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -72,7 +72,7 @@ Jean-Jacques Michel - bug fix - Tobias - Rx interrupt status checking suggestion + Tobias Ringström - Rx interrupt status checking suggestion Submitting bug reports: diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index b749908bd..b8e1e297d 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -766,6 +766,20 @@ struct de4x5_desc { #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 */ @@ -779,19 +793,7 @@ struct de4x5_private { 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 */ @@ -5639,6 +5641,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 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; @@ -5650,12 +5653,16 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 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); diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c index 8d4ebe1a3..5cdad9da4 100644 --- a/drivers/net/fc/iph5526.c +++ b/drivers/net/fc/iph5526.c @@ -3791,6 +3791,9 @@ struct pci_dev *pdev = NULL; 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++) diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index d12a9e150..e705868d6 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -1550,7 +1550,6 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rrpriv = (struct rr_private *)dev->priv; - spin_lock(&rrpriv->lock); switch(cmd){ case SIOCRRGFW: @@ -1559,12 +1558,6 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 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 " @@ -1572,51 +1565,63 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 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); @@ -1629,6 +1634,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 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", @@ -1637,16 +1643,15 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } 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; } diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index bf64b5e1a..3fc785761 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1,6 +1,6 @@ /* 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. @@ -18,6 +18,8 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.07.06 Nov. 7 2000 Jeff Garzik some bug fix and cleaning + Rev 1.07.05 Nov. 6 2000 metapirat 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 @@ -56,7 +58,7 @@ #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; @@ -169,6 +171,7 @@ static u16 sis900_compute_hashtable_index(u8 *addr); 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) @@ -288,6 +291,7 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_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; @@ -1311,6 +1315,96 @@ sis900_get_stats(struct net_device *net_dev) 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) @@ -1448,3 +1542,4 @@ static void __exit sis900_cleanup_module(void) module_init(sis900_init_module); module_exit(sis900_cleanup_module); + diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h index e905f09a6..740b72dc8 100644 --- a/drivers/net/sis900.h +++ b/drivers/net/sis900.h @@ -10,7 +10,10 @@ * 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 @@ -259,7 +262,7 @@ enum sis630_revision_id { #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 */ diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 3383f3e73..3a83b10c8 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -383,7 +383,7 @@ void cb_enable(socket_info_t * s) 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) { diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index 44566c0a9..f2ee5ccc3 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c @@ -1,4 +1,4 @@ -/* $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) @@ -2387,7 +2387,6 @@ static void aurora_release_drivers(void) #endif } -#ifndef MODULE /* * Called at boot time. * @@ -2406,10 +2405,7 @@ void __init aurora_setup(char *str, int *ints) } } -int __init aurora_init(void) -#else -int aurora_init(void) -#endif +static int __init aurora_real_init(void) { int found; int i; @@ -2439,7 +2435,6 @@ int aurora_init(void) return 0; } -#ifdef MODULE int irq = 0; int irq1 = 0; int irq2 = 0; @@ -2449,16 +2444,16 @@ MODULE_PARM(irq1, "i"); 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; @@ -2473,4 +2468,6 @@ printk("cleanup_module: aurora_release_drivers\n"); aurora_release_io_range(&aurora_board[i]); } } -#endif /* MODULE */ + +module_init(aurora_init); +module_exit(aurora_cleanup); diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index 4579404e3..c96a141a5 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -1017,11 +1017,7 @@ static inline void freeLptPort(int idx) 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; @@ -1046,8 +1042,7 @@ int __init bpp_init(void) return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit bpp_cleanup(void) { unsigned idx; @@ -1059,4 +1054,6 @@ void cleanup_module(void) freeLptPort(idx); } } -#endif + +module_init(bpp_init); +module_exit(bpp_cleanup); diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 2ee0aee37..091152a1c 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -1,4 +1,4 @@ -/* $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 @@ -172,11 +172,7 @@ static struct file_operations d7s_fops = { 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; @@ -222,8 +218,7 @@ ebus_done: return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit d7s_cleanup(void) { int regs = readb(d7s_regs); @@ -237,4 +232,6 @@ void cleanup_module(void) misc_deregister(&d7s_miscdev); d7s_free(); } -#endif + +module_init(d7s_init); +module_exit(d7s_cleanup); diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 31c9de932..e1de7a680 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1,4 +1,4 @@ -/* $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) @@ -11,7 +11,9 @@ * 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 */ #include @@ -72,15 +74,16 @@ * 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 */ @@ -88,6 +91,7 @@ #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. @@ -109,6 +113,15 @@ #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; @@ -317,7 +330,6 @@ static unsigned char envctrl_i2c_read_8574(unsigned char addr) /* Do a single byte read and send stop. */ rd = envctrl_i2c_read_data(); envctrl_i2c_stop(); - return rd; } @@ -462,7 +474,32 @@ static int envctrl_i2c_fan_status(struct i2c_child_t *pchild, 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, @@ -587,10 +624,20 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) 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); @@ -621,6 +668,7 @@ envctrl_ioctl(struct inode *inode, struct file *file, 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; @@ -714,9 +762,6 @@ static void envctrl_set_mon(struct i2c_child_t *pchild, 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, @@ -770,6 +815,39 @@ static void envctrl_init_fanstat(struct i2c_child_t *pchild) 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) { @@ -822,6 +900,27 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, } } + /* 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, @@ -835,6 +934,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, 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; @@ -865,7 +969,7 @@ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type) 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])); } } } @@ -932,8 +1036,7 @@ done: * 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")), diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 8690638b3..71809b59d 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -1,4 +1,4 @@ -/* $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) @@ -149,11 +149,7 @@ static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; 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; @@ -236,9 +232,10 @@ int __init flash_init(void) 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); diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 26e5ae8d9..f565ef6d2 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -626,11 +626,7 @@ static struct miscdevice openprom_dev = { 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; @@ -655,9 +651,10 @@ int __init openprom_init(void) 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); diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 6294d0e37..2740c62f3 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -1,4 +1,4 @@ -/* $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) @@ -363,11 +363,7 @@ void uctrl_get_external_status() } -#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; @@ -419,9 +415,7 @@ int __init ts102_uctrl_init(void) return 0; } - -#ifdef MODULE -void cleanup_module(void) +static void __exit ts102_uctrl_cleanup(void) { struct uctrl_driver *driver = &drv; @@ -433,4 +427,6 @@ void cleanup_module(void) if (driver->regs) driver->regs = 0; } -#endif + +module_init(ts102_uctrl_init); +module_exit(ts102_uctrl_cleanup); diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 35865dd70..942a6c59b 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -1,4 +1,4 @@ -/* $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) @@ -165,21 +165,9 @@ no_ranges: 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, @@ -520,25 +508,10 @@ void __init sbus_init(void) 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); diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index cb70168a3..0a3db13f8 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -696,8 +696,13 @@ int tw_findcards(Scsi_Host_Template *tw_host) /* 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); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index c22be78c0..25636b008 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -2566,7 +2566,7 @@ static void datai_run(struct Scsi_Host *shpnt) * 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(); @@ -2735,7 +2735,7 @@ static void datao_run(struct Scsi_Host *shpnt) 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(); diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 8dce8b2cf..828c9e290 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -1,4 +1,4 @@ -/* $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) @@ -400,7 +400,7 @@ extern inline void esp_cmd(struct esp *esp, u8 cmd) * * 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 @@ -2661,7 +2661,7 @@ static int esp_do_data_finale(struct esp *esp) * 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. diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 8630e8ddf..d98c57686 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -4552,6 +4552,8 @@ ips_allocatescbs(ips_ha_t *ha) { /* 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)); diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index fea2a9b4f..0e1dec169 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1491,21 +1491,6 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl, 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; @@ -1517,6 +1502,8 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl, /* 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)); @@ -1543,12 +1530,11 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl, 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 */ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index e7b8bbe19..3d6e45fcd 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1861,9 +1861,6 @@ void scsi_error_handler(void *data) * Flush resources */ - exit_files(current); - current->files = init_task.files; - atomic_inc(¤t->files->count); daemonize(); /* diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c index 0b25bd4e2..55adb72af 100644 --- a/drivers/scsi/scsi_obsolete.c +++ b/drivers/scsi/scsi_obsolete.c @@ -370,7 +370,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt) * 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) { diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 82869fb81..444802652 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -274,7 +274,7 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed) /* ----------------------------------------------------------------------- */ /* 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. */ diff --git a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c index 54b50bb1e..c4d2c50ce 100644 --- a/drivers/sound/i810_audio.c +++ b/drivers/sound/i810_audio.c @@ -14,6 +14,11 @@ * 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 @@ -96,7 +101,7 @@ #endif static int ftsodell=0; -static int clocking=48000; +static unsigned int clocking=48000; #define ADC_RUNNING 1 @@ -377,7 +382,7 @@ static void i810_free_pcm_channel(struct i810_card *card, int channel) 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)) @@ -403,22 +408,18 @@ static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int ra 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); @@ -431,7 +432,7 @@ static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int ra 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)) @@ -457,30 +458,23 @@ static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int ra 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 */ @@ -1726,10 +1720,37 @@ static int __init i810_ac97_init(struct i810_card *card) 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) diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c index 8b9b0bfbc..144cea36c 100644 --- a/drivers/usb/hub.c +++ b/drivers/usb/hub.c @@ -751,9 +751,7 @@ static int usb_hub_thread(void *__hub) * 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 */ diff --git a/drivers/usb/plusb.c b/drivers/usb/plusb.c index d3d1b4e6a..d247c0b28 100644 --- a/drivers/usb/plusb.c +++ b/drivers/usb/plusb.c @@ -1,9 +1,11 @@ /*****************************************************************************/ /* - * 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 @@ -20,9 +22,100 @@ * 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. + * + * */ /*****************************************************************************/ @@ -40,23 +133,102 @@ #include #include #include -//#define DEBUG +//#define DEBUG 1 #include -#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; @@ -76,126 +248,227 @@ static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_he } /*-------------------------------------------------------------------*/ -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; @@ -204,31 +477,69 @@ static void plusb_bulk_complete(urb_t *purb) 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; @@ -237,67 +548,95 @@ static void plusb_int_complete(urb_t *purb) 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; @@ -310,20 +649,34 @@ static void plusb_free_all(plusb_t *s) 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) { @@ -341,47 +694,63 @@ static int plusb_alloc(plusb_t *s) 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; @@ -404,8 +773,11 @@ static int plusb_net_open(struct net_device *dev) return -ENOMEM; s->opened=1; - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; + + netif_start_queue(dev); + dbg("plusb_net_open: success"); return 0; @@ -417,11 +789,14 @@ static int plusb_net_open(struct net_device *dev) 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; @@ -459,7 +834,6 @@ static void plusb_disconnect (struct usb_device *usbdev, void *ptr) plusb_t *s = ptr; dbg("plusb_disconnect"); - s->connected = 0; plusb_free_all(s); @@ -467,6 +841,11 @@ static void plusb_disconnect (struct usb_device *usbdev, void *ptr) 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"); @@ -475,6 +854,22 @@ static void plusb_disconnect (struct usb_device *usbdev, void *ptr) /* --------------------------------------------------------------------- */ +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"); @@ -484,7 +879,14 @@ int plusb_net_init(struct net_device *dev) 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; @@ -524,6 +926,42 @@ static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum) 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; inet_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; @@ -535,7 +973,8 @@ static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum) s->net_dev.name[0] = '\0'; } } - +#endif + s->connected = 1; if(s->opened) { @@ -567,8 +1006,6 @@ static int __init plusb_init (void) 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); @@ -591,10 +1028,21 @@ static void __exit plusb_cleanup (void) 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"); diff --git a/drivers/usb/plusb.h b/drivers/usb/plusb.h deleted file mode 100644 index a77ae0f01..000000000 --- a/drivers/usb/plusb.h +++ /dev/null @@ -1,48 +0,0 @@ -#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 diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 7e59346aa..a37a71f75 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -968,6 +968,11 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, } /*-------------------------------------------------------------------*/ +/* 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) { @@ -993,8 +998,10 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u } /*-------------------------------------------------------------------*/ -/* 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) diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 688f576cf..331343d15 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -89,7 +89,6 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o 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 @@ -110,6 +109,16 @@ else 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 diff --git a/drivers/video/sis/Makefile b/drivers/video/sis/Makefile new file mode 100644 index 000000000..2e657f107 --- /dev/null +++ b/drivers/video/sis/Makefile @@ -0,0 +1,12 @@ +# +# 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 + + diff --git a/drivers/video/sis/initdef.h b/drivers/video/sis/initdef.h new file mode 100644 index 000000000..e0ab914ec --- /dev/null +++ b/drivers/video/sis/initdef.h @@ -0,0 +1,138 @@ +#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 + diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h new file mode 100644 index 000000000..3f4843a77 --- /dev/null +++ b/drivers/video/sis/sis.h @@ -0,0 +1,64 @@ +#ifndef _SISFB_LOCAL +#define _SISFB_LOCAL +#include + +#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 diff --git a/drivers/video/sis/sis_300.c b/drivers/video/sis/sis_300.c new file mode 100644 index 000000000..3a3a2232b --- /dev/null +++ b/drivers/video/sis/sis_300.c @@ -0,0 +1,1523 @@ +/* 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>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 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=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>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 diff --git a/drivers/video/sis/sis_300.h b/drivers/video/sis/sis_300.h new file mode 100644 index 000000000..7200365f2 --- /dev/null +++ b/drivers/video/sis/sis_300.h @@ -0,0 +1,162 @@ +#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 diff --git a/drivers/video/sis/sis_301.c b/drivers/video/sis/sis_301.c new file mode 100644 index 000000000..b24998342 --- /dev/null +++ b/drivers/video/sis/sis_301.c @@ -0,0 +1,2867 @@ +/* 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=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(LCDResInfo0x07){ //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>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 <> 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>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>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<>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 diff --git a/drivers/video/sis/sis_301.h b/drivers/video/sis/sis_301.h new file mode 100644 index 000000000..0f38590b4 --- /dev/null +++ b/drivers/video/sis/sis_301.h @@ -0,0 +1,223 @@ +#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); diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c new file mode 100644 index 000000000..0f24d4fb9 --- /dev/null +++ b/drivers/video/sis/sis_main.c @@ -0,0 +1,2373 @@ +/* + * 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 + * + */ + +#define EXPORT_SYMTAB +#undef SISFBDEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include