From a8a2069f432c5597bdf9c83ab3045b9ef32ab5e3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 4 Feb 2002 20:32:43 -0800 Subject: [PATCH] v2.4.14.1 -> v2.4.14.2 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - Ivan Kokshaysky: fix alpha dec_and_lock with modules, for alpha config entry - Kai Germaschewski: ISDN updates - Jeff Garzik: network driver updates, sysv fs update - Kai Mäkisara: SCSI tape update - Alan Cox: large drivers merge - Nikita Danilov: reiserfs procfs information - Andrew Morton: ext3 merge - Christoph Hellwig: vxfs livelock fix - Trond Myklebust: NFS updates - Jens Axboe: cpqarray + cciss dequeue fix - Tim Waugh: parport_serial base_baud setting - Matthew Dharm: usb-storage Freecom driver fixes - Dave McCracken: wait4() thread group race fix --- Documentation/Configure.help | 37 +- Documentation/DocBook/via-audio.tmpl | 38 +- Documentation/memory.txt | 2 +- Documentation/networking/8139too.txt | 27 +- Documentation/parport.txt | 4 + MAINTAINERS | 4 +- Makefile | 2 +- arch/alpha/config.in | 4 + arch/alpha/kernel/entry.S | 3 + arch/alpha/kernel/signal.c | 1 + arch/alpha/kernel/sys_miata.c | 13 + arch/alpha/lib/dec_and_lock.c | 11 +- arch/alpha/lib/io.c | 44 +- arch/arm/Makefile | 19 +- arch/arm/config.in | 47 +- arch/arm/lib/gcclib.h | 2 +- arch/arm/mm/Makefile | 1 + arch/arm/mm/proc-arm1020.S | 762 +++ arch/arm/mm/proc-arm926.S | 667 ++ arch/arm/tools/mach-types | 5 +- arch/cris/defconfig | 5 +- arch/cris/drivers/Config.in | 8 + arch/cris/drivers/axisflashmap.c | 7 +- arch/cris/drivers/gpio.c | 104 +- arch/cris/drivers/serial.c | 831 ++- arch/cris/drivers/serial.h | 9 + arch/cris/kernel/Makefile | 5 +- arch/cris/kernel/entry.S | 10 +- arch/cris/kernel/head.S | 9 +- arch/cris/kernel/kgdb.c | 231 +- arch/cris/kernel/ksyms.c | 14 + arch/cris/kernel/process.c | 1 + arch/cris/kernel/setup.c | 76 +- arch/cris/kernel/time.c | 15 +- arch/cris/kernel/traps.c | 4 +- arch/i386/boot/bootsect.S | 6 + arch/i386/boot/setup.S | 155 +- arch/i386/defconfig | 4 + arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/acpitable.c | 897 +++ arch/i386/kernel/apic.c | 5 +- arch/i386/kernel/apm.c | 2 +- arch/i386/kernel/dmi_scan.c | 2 +- arch/i386/kernel/mpparse.c | 161 +- arch/i386/kernel/mtrr.c | 2 + arch/i386/kernel/pci-pc.c | 90 +- arch/i386/kernel/semaphore.c | 6 +- arch/i386/lib/usercopy.c | 4 + arch/ia64/Makefile | 19 +- arch/ia64/config.in | 78 +- arch/ia64/defconfig | 742 +- arch/ia64/ia32/binfmt_elf32.c | 170 +- arch/ia64/ia32/ia32_entry.S | 283 +- arch/ia64/ia32/ia32_ioctl.c | 355 +- arch/ia64/ia32/ia32_ldt.c | 39 +- arch/ia64/ia32/ia32_signal.c | 871 ++- arch/ia64/ia32/ia32_support.c | 109 +- arch/ia64/ia32/ia32_traps.c | 27 +- arch/ia64/ia32/sys_ia32.c | 4573 ++++++------- arch/ia64/kernel/Makefile | 2 +- arch/ia64/kernel/acpi.c | 244 +- arch/ia64/kernel/efi.c | 27 +- arch/ia64/kernel/efi_stub.S | 12 +- arch/ia64/kernel/efivars.c | 6 +- arch/ia64/kernel/entry.S | 124 +- arch/ia64/kernel/entry.h | 11 +- arch/ia64/kernel/fw-emu.c | 42 +- arch/ia64/kernel/gate.S | 76 +- arch/ia64/kernel/head.S | 63 +- arch/ia64/kernel/ia64_ksyms.c | 3 +- arch/ia64/kernel/iosapic.c | 129 +- arch/ia64/kernel/irq.c | 234 +- arch/ia64/kernel/irq_ia64.c | 13 +- arch/ia64/kernel/ivt.S | 78 +- arch/ia64/kernel/mca.c | 1648 ++++- arch/ia64/kernel/mca_asm.S | 134 +- arch/ia64/kernel/pal.S | 29 +- arch/ia64/kernel/palinfo.c | 25 +- arch/ia64/kernel/pci.c | 44 + arch/ia64/kernel/perfmon.c | 1117 +-- arch/ia64/kernel/process.c | 51 +- arch/ia64/kernel/ptrace.c | 28 +- arch/ia64/kernel/sal.c | 29 +- arch/ia64/kernel/setup.c | 7 +- arch/ia64/kernel/sigframe.h | 11 +- arch/ia64/kernel/signal.c | 37 +- arch/ia64/kernel/smp.c | 116 +- arch/ia64/kernel/smpboot.c | 22 +- arch/ia64/kernel/sys_ia64.c | 45 +- arch/ia64/kernel/time.c | 3 + arch/ia64/kernel/traps.c | 123 +- arch/ia64/kernel/unaligned.c | 60 +- arch/ia64/kernel/unwind.c | 2 +- arch/ia64/lib/clear_page.S | 2 +- arch/ia64/lib/clear_user.S | 20 +- arch/ia64/lib/copy_page.S | 2 +- arch/ia64/lib/copy_user.S | 136 +- arch/ia64/lib/do_csum.S | 21 +- arch/ia64/lib/idiv32.S | 2 +- arch/ia64/lib/idiv64.S | 2 +- arch/ia64/lib/memcpy.S | 40 +- arch/ia64/lib/memset.S | 12 +- arch/ia64/lib/strlen.S | 16 +- arch/ia64/lib/strlen_user.S | 18 +- arch/ia64/lib/strncpy_from_user.S | 2 +- arch/ia64/lib/strnlen_user.S | 4 +- arch/ia64/lib/swiotlb.c | 8 +- arch/ia64/mm/fault.c | 42 +- arch/ia64/mm/init.c | 32 +- arch/ia64/mm/tlb.c | 121 +- arch/ia64/sn/sn1/llsc4.c | 11 - arch/ia64/tools/print_offsets.c | 10 +- arch/s390/config.in | 1 + arch/s390/defconfig | 14 +- arch/s390/kernel/entry.S | 17 +- arch/s390/kernel/head.S | 6 +- arch/s390/kernel/init_task.c | 1 + arch/s390/kernel/s390_ksyms.c | 1 - arch/s390/kernel/traps.c | 41 +- arch/s390/mm/fault.c | 22 +- arch/s390x/defconfig | 11 +- arch/s390x/kernel/entry.S | 12 +- arch/s390x/kernel/head.S | 6 +- arch/s390x/kernel/init_task.c | 1 + arch/s390x/kernel/traps.c | 23 + arch/s390x/kernel/wrapper32.S | 6 +- arch/s390x/mm/fault.c | 14 +- arch/s390x/mm/init.c | 2 +- drivers/acpi/os.c | 8 +- drivers/acpi/ospm/processor/pr_osl.c | 17 +- drivers/atm/eni.c | 2 +- drivers/atm/firestream.c | 5 +- drivers/block/acsi.c | 10 +- drivers/block/cciss.c | 16 +- drivers/block/cpqarray.c | 9 +- drivers/block/loop.c | 19 +- drivers/block/paride/pd.c | 10 +- drivers/block/ps2esdi.c | 15 +- drivers/block/rd.c | 3 - drivers/block/xd.c | 7 +- drivers/char/acpi_serial.c | 194 + drivers/char/agp/agp.h | 67 +- drivers/char/agp/agpgart_be.c | 378 +- drivers/char/drm/drm_agpsupport.h | 2 + drivers/char/esp.c | 15 +- drivers/char/hp_keyb.c | 519 ++ drivers/char/hp_psaux.c | 551 ++ drivers/char/isicom.c | 45 +- drivers/char/joystick/cs461x.c | 4 +- drivers/char/joystick/emu10k1-gp.c | 4 +- drivers/char/joystick/pcigame.c | 4 +- drivers/char/pc_keyb.c | 40 +- drivers/char/random.c | 8 +- drivers/char/rtc.c | 8 +- drivers/char/serial.c | 40 +- drivers/char/serial_tx3912.c | 2 +- drivers/char/specialix.c | 5 +- drivers/char/sx.c | 5 + drivers/hotplug/Config.in | 12 + drivers/hotplug/Makefile | 34 + drivers/hotplug/cpqphp.h | 751 +++ drivers/hotplug/cpqphp_core.c | 1439 ++++ drivers/hotplug/cpqphp_ctrl.c | 3047 +++++++++ drivers/hotplug/cpqphp_nvram.c | 652 ++ drivers/hotplug/cpqphp_nvram.h | 57 + drivers/hotplug/cpqphp_pci.c | 1726 +++++ drivers/hotplug/cpqphp_proc.c | 192 + drivers/hotplug/pci_hotplug.h | 160 + drivers/hotplug/pci_hotplug_core.c | 1132 ++++ drivers/hotplug/pci_hotplug_util.c | 403 ++ drivers/ide/ide-geometry.c | 4 +- drivers/isdn/eicon/eicon_idi.c | 12 +- drivers/isdn/eicon/eicon_isa.c | 20 +- drivers/isdn/hysdn/boardergo.c | 2 +- drivers/isdn/hysdn/hysdn_sched.c | 2 +- drivers/isdn/isdn_common.c | 18 +- drivers/isdn/isdn_net.c | 24 +- drivers/isdn/isdn_ppp.c | 37 +- drivers/isdn/isdn_tty.c | 10 +- drivers/isdn/tpam/tpam.h | 6 +- drivers/isdn/tpam/tpam_commands.c | 12 +- drivers/isdn/tpam/tpam_hdlc.c | 22 +- drivers/media/radio/Config.in | 2 +- drivers/media/video/Config.in | 3 + drivers/media/video/Makefile | 5 +- drivers/media/video/saa7110.c | 1 + drivers/media/video/zr36067.c | 7 + drivers/media/video/zr36120.c | 7 + drivers/mtd/chips/jedec.c | 15 +- drivers/mtd/chips/jedec_probe.c | 2 +- drivers/mtd/redboot.c | 12 +- drivers/net/3c59x.c | 4 +- drivers/net/8139too.c | 271 +- drivers/net/Config.in | 3 + drivers/net/appletalk/Config.in | 8 +- drivers/net/arcnet/com20020-pci.c | 4 +- drivers/net/arlan.c | 4 + drivers/net/bsd_comp.c | 2 +- drivers/net/dmfe.c | 388 +- drivers/net/eepro.c | 350 +- drivers/net/eepro100.c | 33 + drivers/net/fealnx.c | 2 +- drivers/net/irda/irda-usb.c | 102 +- drivers/net/irda/vlsi_ir.c | 8 +- drivers/net/natsemi.c | 136 +- drivers/net/ns83820.c | 2 +- drivers/net/pcmcia/xircom_cb.c | 2 +- drivers/net/pcmcia/xircom_tulip_cb.c | 6 +- drivers/net/pppoe.c | 18 +- drivers/net/pppox.c | 4 + drivers/net/rrunner.c | 97 +- drivers/net/rrunner.h | 1 + drivers/net/slhc.c | 2 +- drivers/net/strip.c | 2 +- drivers/net/tokenring/ibmtr.c | 1 + drivers/net/tokenring/lanstreamer.c | 8 +- drivers/net/tokenring/olympic.c | 6 +- drivers/net/tulip/21142.c | 21 - drivers/net/tulip/ChangeLog | 21 + drivers/net/tulip/Makefile | 2 +- drivers/net/tulip/interrupt.c | 32 +- drivers/net/tulip/pnic.c | 4 +- drivers/net/tulip/pnic2.c | 407 ++ drivers/net/tulip/tulip.h | 8 +- drivers/net/tulip/tulip_core.c | 120 +- drivers/net/via-rhine.c | 112 +- drivers/net/wan/dscc4.c | 1 - drivers/net/wan/farsync.c | 4 +- drivers/net/wan/z85230.c | 237 +- drivers/net/wan/z85230.h | 3 + drivers/net/wireless/airo.c | 12 +- drivers/parport/ChangeLog | 5 + drivers/parport/parport_serial.c | 1 + drivers/pci/names.c | 2 +- drivers/pci/pci.ids | 8 + drivers/pcmcia/Config.in | 2 +- drivers/pcmcia/i82092.c | 5 +- drivers/pcmcia/pci_socket.c | 12 +- drivers/s390/block/dasd.c | 85 +- drivers/s390/block/dasd_3990_erp.c | 22 +- drivers/s390/block/dasd_eckd.c | 4 +- drivers/s390/char/tape34xx.c | 9 +- drivers/s390/char/tapechar.c | 10 +- drivers/s390/misc/chandev.c | 4 +- drivers/s390/s390mach.c | 2 +- drivers/scsi/3w-xxxx.c | 243 +- drivers/scsi/3w-xxxx.h | 92 +- drivers/scsi/README.st | 23 +- drivers/scsi/advansys.c | 2 +- drivers/scsi/aha152x.c | 4 + drivers/scsi/aic7xxx/aic7xxx_linux_pci.c | 4 +- drivers/scsi/dpt_i2o.c | 7 + drivers/scsi/eata.c | 2 +- drivers/scsi/gdth.c | 11 + drivers/scsi/i60uscsi.c | 112 +- drivers/scsi/i60uscsi.h | 4 - drivers/scsi/ips.c | 2 + drivers/scsi/pci2000.c | 2 +- drivers/scsi/pci2220i.c | 2 +- drivers/scsi/scsi.c | 79 +- drivers/scsi/scsi.h | 4 +- drivers/scsi/sd.c | 9 +- drivers/scsi/st.c | 403 +- drivers/scsi/st.h | 10 +- drivers/sound/ac97_codec.c | 3 +- drivers/sound/aci.c | 94 +- drivers/sound/cmpci.c | 13 +- drivers/sound/i810_audio.c | 16 +- drivers/sound/maestro3.c | 6 +- drivers/sound/trident.c | 10 +- drivers/sound/trident.h | 2 +- drivers/sound/via82cxxx_audio.c | 467 +- drivers/sound/vwsnd.c | 1 + drivers/usb/storage/freecom.c | 84 +- drivers/usb/storage/scsiglue.c | 2 +- drivers/usb/storage/sddr09.c | 2 +- drivers/usb/storage/transport.c | 2 +- drivers/usb/storage/usb.c | 2 +- drivers/usb/uhci.c | 10 +- drivers/usb/usb-ohci.c | 10 +- drivers/usb/usb-uhci.c | 8 +- drivers/video/hgafb.c | 22 +- drivers/video/imsttfb.c | 4 +- drivers/video/matrox/i2c-matroxfb.c | 18 +- drivers/video/matrox/matroxfb_DAC1064.c | 3 +- drivers/video/matrox/matroxfb_DAC1064.h | 4 +- drivers/video/matrox/matroxfb_base.c | 48 +- drivers/video/matrox/matroxfb_base.h | 16 +- drivers/video/matrox/matroxfb_crtc2.c | 47 +- drivers/video/matrox/matroxfb_g450.c | 92 +- drivers/video/matrox/matroxfb_g450.h | 1 + drivers/video/matrox/matroxfb_maven.c | 15 +- drivers/video/matrox/matroxfb_misc.c | 4 + drivers/video/radeonfb.c | 4 +- drivers/video/sgivwfb.c | 3 + drivers/video/sis/300vtbl.h | 1522 +++++ drivers/video/sis/310vtbl.h | 2604 +++++++ drivers/video/sis/325vtbl.h | 2318 +++++++ drivers/video/sis/Makefile | 2 +- drivers/video/sis/init.c | 3784 +++++++++++ drivers/video/sis/init.h | 227 + drivers/video/sis/init301.c | 6001 +++++++++++++++++ drivers/video/sis/init301.h | 223 + drivers/video/sis/initdef.h | 366 +- drivers/video/sis/oem300.h | 397 ++ drivers/video/sis/oem310.h | 204 + drivers/video/sis/osdef.h | 37 + drivers/video/sis/sis.h | 64 - drivers/video/sis/sis_300.c | 1524 ----- drivers/video/sis/sis_300.h | 163 - drivers/video/sis/sis_301.c | 2868 -------- drivers/video/sis/sis_301.h | 224 - drivers/video/sis/sis_main.c | 3796 ++++++----- drivers/video/sis/sis_main.h | 693 ++ drivers/video/sis/vgatypes.h | 275 + drivers/video/sis/vstruct.h | 324 + fs/Config.in | 8 + fs/Makefile | 4 +- fs/autofs4/inode.c | 4 +- fs/buffer.c | 61 +- fs/ext3/Makefile | 16 + fs/ext3/acl.c | 17 + fs/ext3/balloc.c | 995 +++ fs/ext3/bitmap.c | 26 + fs/ext3/dir.c | 190 + fs/ext3/file.c | 97 + fs/ext3/fsync.c | 69 + fs/ext3/ialloc.c | 664 ++ fs/ext3/inode.c | 2672 ++++++++ fs/ext3/ioctl.c | 170 + fs/ext3/namei.c | 1125 +++ fs/ext3/super.c | 1745 +++++ fs/ext3/symlink.c | 39 + fs/freevxfs/vxfs_subr.c | 3 +- fs/jbd/Makefile | 15 + fs/jbd/checkpoint.c | 608 ++ fs/jbd/commit.c | 701 ++ fs/jbd/journal.c | 1813 +++++ fs/jbd/recovery.c | 586 ++ fs/jbd/revoke.c | 631 ++ fs/jbd/transaction.c | 2070 ++++++ fs/nfs/Makefile | 4 +- fs/nfs/flushd.c | 149 +- fs/nfs/inode.c | 12 + fs/nfs/pagelist.c | 498 ++ fs/nfs/read.c | 178 +- fs/nfs/write.c | 577 +- fs/reiserfs/Makefile | 2 +- fs/reiserfs/bitmap.c | 12 +- fs/reiserfs/buffer2.c | 12 +- fs/reiserfs/do_balan.c | 3 + fs/reiserfs/fix_node.c | 19 +- fs/reiserfs/ibalance.c | 2 + fs/reiserfs/journal.c | 14 + fs/reiserfs/namei.c | 3 + fs/reiserfs/objectid.c | 4 +- fs/reiserfs/prints.c | 11 +- fs/reiserfs/procfs.c | 711 ++ fs/reiserfs/stree.c | 16 +- fs/reiserfs/super.c | 32 +- fs/sysv/ChangeLog | 13 + fs/sysv/dir.c | 38 +- fs/sysv/file.c | 1 - fs/sysv/ialloc.c | 1 + fs/sysv/inode.c | 32 +- fs/sysv/namei.c | 1 - fs/sysv/super.c | 1 - include/asm-alpha/core_apecs.h | 30 +- include/asm-alpha/core_cia.h | 56 +- include/asm-alpha/core_irongate.h | 30 +- include/asm-alpha/core_lca.h | 30 +- include/asm-alpha/core_mcpcia.h | 30 +- include/asm-alpha/core_polaris.h | 30 +- include/asm-alpha/core_t2.h | 28 +- include/asm-alpha/core_titan.h | 30 +- include/asm-alpha/core_tsunami.h | 28 +- include/asm-alpha/core_wildfire.h | 30 +- include/asm-alpha/io.h | 54 +- include/asm-alpha/jensen.h | 32 +- include/asm-alpha/machvec.h | 30 +- include/asm-alpha/unistd.h | 3 + include/asm-arm/arch-epxa10db/hardware.h | 1 - include/asm-arm/arch-integrator/hardware.h | 2 +- include/asm-arm/arch-sa1100/hardware.h | 6 +- include/asm-arm/pci.h | 3 + include/asm-arm/proc-fns.h | 8 + include/asm-arm/{arch-integrator => }/sizes.h | 0 include/asm-cris/etraxgpio.h | 11 + include/asm-cris/pgtable.h | 5 + include/asm-cris/system.h | 2 +- include/asm-cris/timex.h | 13 + include/asm-cris/uaccess.h | 5 +- include/asm-cris/unistd.h | 3 + include/asm-i386/hardirq.h | 2 +- include/asm-i386/keyboard.h | 4 +- include/asm-i386/mpspec.h | 33 + include/asm-i386/pci.h | 42 +- include/asm-i386/system.h | 1 + include/asm-ia64/acpi-ext.h | 9 +- include/asm-ia64/ia32.h | 111 +- include/asm-ia64/io.h | 12 +- include/asm-ia64/iosapic.h | 9 + include/asm-ia64/ipc.h | 31 - include/asm-ia64/keyboard.h | 9 +- include/asm-ia64/kregs.h | 3 +- include/asm-ia64/machvec.h | 12 +- include/asm-ia64/machvec_sn1.h | 2 + include/asm-ia64/mca.h | 18 +- include/asm-ia64/mca_asm.h | 29 +- include/asm-ia64/mmu_context.h | 1 - include/asm-ia64/module.h | 40 +- include/asm-ia64/msgbuf.h | 2 +- include/asm-ia64/namei.h | 25 +- include/asm-ia64/offsets.h | 20 +- include/asm-ia64/page.h | 3 + include/asm-ia64/pal.h | 465 +- include/asm-ia64/pci.h | 23 +- include/asm-ia64/perfmon.h | 11 +- include/asm-ia64/pgalloc.h | 7 +- include/asm-ia64/pgtable.h | 22 +- include/asm-ia64/processor.h | 97 +- include/asm-ia64/sal.h | 566 +- include/asm-ia64/scatterlist.h | 6 +- include/asm-ia64/semaphore.h | 2 - include/asm-ia64/sembuf.h | 2 +- include/asm-ia64/shmbuf.h | 2 +- include/asm-ia64/sigcontext.h | 23 +- include/asm-ia64/signal.h | 20 +- include/asm-ia64/smp.h | 10 +- include/asm-ia64/smplock.h | 8 +- include/asm-ia64/spinlock.h | 24 +- include/asm-ia64/system.h | 29 +- include/asm-ia64/unistd.h | 7 +- include/asm-ia64/user.h | 5 +- include/asm-s390/atomic.h | 2 +- include/asm-s390/fcntl.h | 2 +- include/asm-s390/gdb-stub.h | 2 +- include/asm-s390/irq.h | 2 +- include/asm-s390/sigcontext.h | 4 +- include/asm-s390/vtoc.h | 2 +- include/asm-s390x/atomic.h | 2 +- include/asm-s390x/fcntl.h | 2 +- include/asm-s390x/irq.h | 2 +- include/asm-s390x/s390-regs-common.h | 115 - include/asm-s390x/sigcontext.h | 4 +- include/asm-s390x/spinlock.h | 2 +- include/asm-s390x/vtoc.h | 131 +- include/linux/acpi_serial.h | 103 + include/linux/agp_backend.h | 3 + include/linux/atm.h | 1 + include/linux/atmapi.h | 4 +- include/linux/atmdev.h | 11 + include/linux/atmioc.h | 4 +- include/linux/atmppp.h | 24 + include/linux/blk.h | 4 +- include/linux/capability.h | 2 + include/linux/ethtool.h | 29 +- include/linux/ext3_fs.h | 715 ++ include/linux/ext3_fs_i.h | 78 + include/linux/ext3_fs_sb.h | 77 + include/linux/ext3_jbd.h | 290 + include/linux/fs.h | 18 +- include/linux/i2o.h | 3 +- include/linux/irda.h | 1 + include/linux/jbd.h | 881 +++ include/linux/journal-head.h | 70 + include/linux/malloc.h | 2 + include/linux/module.h | 16 +- include/linux/mtd/jedec.h | 4 +- include/linux/mtio.h | 5 +- include/linux/nfs_flushd.h | 8 +- include/linux/nfs_fs.h | 12 +- include/linux/nfs_fs_sb.h | 6 + include/linux/nfs_page.h | 86 +- include/linux/parport.h | 4 +- include/linux/pci_ids.h | 26 +- include/linux/reiserfs_fs.h | 66 +- include/linux/reiserfs_fs_sb.h | 70 + include/linux/sched.h | 7 +- include/linux/serial.h | 6 + include/linux/sisfb.h | 151 +- include/linux/soundcard.h | 2 +- include/linux/sysv_fs.h | 48 - include/linux/sysv_fs_i.h | 1 + include/linux/sysv_fs_sb.h | 2 - include/linux/videodev.h | 2 +- include/linux/watchdog.h | 1 + include/net/dn.h | 1 + include/net/irda/irda-usb.h | 5 + include/net/irda/irda.h | 6 + include/net/irda/irlap_event.h | 2 + include/net/irda/irlmp.h | 2 +- include/net/irda/irlmp_event.h | 5 +- include/net/irda/irmod.h | 108 +- include/net/irda/parameters.h | 7 +- include/net/irda/timer.h | 5 +- init/main.c | 2 +- init/version.c | 2 +- kernel/exit.c | 4 + lib/brlock.c | 1 + mm/filemap.c | 15 +- mm/vmscan.c | 13 +- net/802/cl2llc.pre | 2 +- net/atm/Makefile | 1 + net/atm/common.c | 12 + net/atm/pppoatm.c | 365 + net/atm/resources.c | 7 +- net/bluetooth/hci_core.c | 2 +- net/decnet/af_decnet.c | 10 +- net/decnet/dn_nsp_in.c | 3 + net/decnet/dn_route.c | 2 +- net/decnet/sysctl_net_decnet.c | 7 + net/ipv4/ipconfig.c | 15 +- net/irda/af_irda.c | 57 +- net/irda/ircomm/ircomm_param.c | 46 +- net/irda/irda_device.c | 14 +- net/irda/iriap.c | 3 +- net/irda/irlap.c | 35 +- net/irda/irlap_event.c | 93 +- net/irda/irlap_frame.c | 3 +- net/irda/irlmp.c | 64 +- net/irda/irlmp_event.c | 70 +- net/irda/irlmp_frame.c | 62 +- net/irda/irnet/irnet.h | 24 +- net/irda/irnet/irnet_irda.c | 219 +- net/irda/irnet/irnet_ppp.c | 4 +- net/irda/irsyms.c | 17 +- net/irda/irttp.c | 107 +- net/irda/parameters.c | 30 +- net/irda/qos.c | 31 +- net/irda/timer.c | 32 +- net/netlink/netlink_dev.c | 13 +- net/sched/sch_api.c | 4 +- scripts/Lindent | 2 +- scripts/patch-kernel | 201 +- 535 files changed, 67823 insertions(+), 16950 deletions(-) create mode 100644 arch/arm/mm/proc-arm1020.S create mode 100644 arch/arm/mm/proc-arm926.S create mode 100644 arch/i386/kernel/acpitable.c create mode 100644 drivers/char/acpi_serial.c create mode 100644 drivers/char/hp_keyb.c create mode 100644 drivers/char/hp_psaux.c create mode 100644 drivers/hotplug/Config.in create mode 100644 drivers/hotplug/Makefile create mode 100644 drivers/hotplug/cpqphp.h create mode 100644 drivers/hotplug/cpqphp_core.c create mode 100644 drivers/hotplug/cpqphp_ctrl.c create mode 100644 drivers/hotplug/cpqphp_nvram.c create mode 100644 drivers/hotplug/cpqphp_nvram.h create mode 100644 drivers/hotplug/cpqphp_pci.c create mode 100644 drivers/hotplug/cpqphp_proc.c create mode 100644 drivers/hotplug/pci_hotplug.h create mode 100644 drivers/hotplug/pci_hotplug_core.c create mode 100644 drivers/hotplug/pci_hotplug_util.c create mode 100644 drivers/net/tulip/pnic2.c create mode 100644 drivers/video/sis/300vtbl.h create mode 100644 drivers/video/sis/310vtbl.h create mode 100644 drivers/video/sis/325vtbl.h create mode 100644 drivers/video/sis/init.c create mode 100644 drivers/video/sis/init.h create mode 100644 drivers/video/sis/init301.c create mode 100644 drivers/video/sis/init301.h create mode 100644 drivers/video/sis/oem300.h create mode 100644 drivers/video/sis/oem310.h create mode 100644 drivers/video/sis/osdef.h delete mode 100644 drivers/video/sis/sis.h delete mode 100644 drivers/video/sis/sis_300.c delete mode 100644 drivers/video/sis/sis_300.h delete mode 100644 drivers/video/sis/sis_301.c delete mode 100644 drivers/video/sis/sis_301.h create mode 100644 drivers/video/sis/sis_main.h create mode 100644 drivers/video/sis/vgatypes.h create mode 100644 drivers/video/sis/vstruct.h create mode 100644 fs/ext3/Makefile create mode 100644 fs/ext3/acl.c create mode 100644 fs/ext3/balloc.c create mode 100644 fs/ext3/bitmap.c create mode 100644 fs/ext3/dir.c create mode 100644 fs/ext3/file.c create mode 100644 fs/ext3/fsync.c create mode 100644 fs/ext3/ialloc.c create mode 100644 fs/ext3/inode.c create mode 100644 fs/ext3/ioctl.c create mode 100644 fs/ext3/namei.c create mode 100644 fs/ext3/super.c create mode 100644 fs/ext3/symlink.c create mode 100644 fs/jbd/Makefile create mode 100644 fs/jbd/checkpoint.c create mode 100644 fs/jbd/commit.c create mode 100644 fs/jbd/journal.c create mode 100644 fs/jbd/recovery.c create mode 100644 fs/jbd/revoke.c create mode 100644 fs/jbd/transaction.c create mode 100644 fs/nfs/pagelist.c create mode 100644 fs/reiserfs/procfs.c create mode 100644 fs/sysv/ChangeLog rename include/asm-arm/{arch-integrator => }/sizes.h (100%) delete mode 100644 include/asm-ia64/ipc.h delete mode 100644 include/asm-s390x/s390-regs-common.h create mode 100644 include/linux/acpi_serial.h create mode 100644 include/linux/atmppp.h create mode 100644 include/linux/ext3_fs.h create mode 100644 include/linux/ext3_fs_i.h create mode 100644 include/linux/ext3_fs_sb.h create mode 100644 include/linux/ext3_jbd.h create mode 100644 include/linux/jbd.h create mode 100644 include/linux/journal-head.h create mode 100644 net/atm/pppoatm.c diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 62f0643ab1bf..b33b56732f86 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -2,7 +2,7 @@ # Eric S. Raymond # Steven Cole # -# Merged version 2.48: Current with 2.4.14 and 2.4.13-ac8. +# Merged version 2.49: Current with 2.4.15-pre1 and 2.4.13-ac8. # # This version of the Linux kernel configuration help texts # corresponds to the kernel versions 2.4.x. @@ -1795,6 +1795,16 @@ CONFIG_MD_RAID5 If unsure, say Y. +Multipath I/O support +CONFIG_MD_MULTIPATH + Multipath-IO is the ability of certain devices to address the same + physical disk over multiple 'IO paths'. The code ensures that such + paths can be defined and handled at runtime, and ensures that a + transparent failover to the backup path(s) happens if a IO errors + arrives on the primary path. + + If unsure, say N. + # AC tree only Support for IDE Raid controllers CONFIG_BLK_DEV_ATARAID @@ -2826,8 +2836,9 @@ CONFIG_ALPHA_CABRIOLET DP264 CONFIG_ALPHA_DP264 - Hard Data HD-DP264-based Alpha systems. There is a Hard Data - website at . + Various 21264 systems with the tsunami core logic chipset. + API Networks: 264DP, UP2000(+), CS20; + Compaq: DS10(E,L), XP900, XP1000, DS20(E), ES40. EB164 CONFIG_ALPHA_EB164 @@ -13603,6 +13614,15 @@ CONFIG_REISERFS_PROC_INFO everyone but ReiserFS developers and people fine-tuning reiserfs or tracing problems should say N. +Publish some reiserfs-specific info under /proc/fs/reiserfs +CONFIG_REISERFS_PROC_INFO + Create under /proc/fs/reiserfs hierarchy of files, displaying + various ReiserFS statistics and internal data on the expense of + making your kernel or module slightly larger (+8K). This also increases + amount of kernel memory required for each mount. Almost everyone + but ReiserFS developers and people fine-tuning reiserfs or tracing + problems should say NO. + Second extended fs support CONFIG_EXT2_FS This is the de facto standard Linux file system (method to organize @@ -22202,14 +22222,21 @@ CONFIG_IRDA read the IR-HOWTO, available at . + If you want to exchange bits of data (vCal, vCard) with a PDA, you + will need to install some OBEX application, such as OpenObex : + + This support is also available as a module called irda.o. If you want to compile it as a module, say M here and read . Ultra (connectionless) protocol CONFIG_IRDA_ULTRA - Say Y here to support the connectionless Ultra IRDA protocol, also - called IrOBEX. + Say Y here to support the connectionless Ultra IRDA protocol. + Ultra allows to exchange data over IrDA with really simple devices + (watch, beacon) without the overhead of the IrDA protocol (no handshaking, + no management frames, simple fixed header). + Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1); IrDA protocol options CONFIG_IRDA_OPTIONS diff --git a/Documentation/DocBook/via-audio.tmpl b/Documentation/DocBook/via-audio.tmpl index 768031ccba95..22588c519326 100644 --- a/Documentation/DocBook/via-audio.tmpl +++ b/Documentation/DocBook/via-audio.tmpl @@ -68,7 +68,7 @@ support are not yet available. - This driver supports any Linux kernel version after 2.3.50. + This driver supports any Linux kernel version after 2.4.10. Please send bug reports to the mailing list linux-via@gtf.org. @@ -157,14 +157,6 @@ - RealPlayer trouble - - - RealPlayer output very scratchy. Workaround: use esd, and - configure RealPlayer to output to esd. - - - @@ -191,6 +183,9 @@ MMAP support, and several other notable fixes that resulted from his hard work and testing. + + Thomas Sailer for further bugfixes. + @@ -234,6 +229,31 @@ Driver ChangeLog + +Version 1.9.1 + + + + + DSP read/write bugfixes from Thomas Sailer. + + + + + + Add new PCI id for single-channel use of Via 8233. + + + + + + Other bug fixes, tweaks, new ioctls. + + + + + + Version 1.1.15 diff --git a/Documentation/memory.txt b/Documentation/memory.txt index 638aae42102d..7af1709e8fac 100644 --- a/Documentation/memory.txt +++ b/Documentation/memory.txt @@ -37,7 +37,7 @@ Try: * Not overclocking your CPU. * Having the memory tested in a memory tester or exchanged - with the vendor. + with the vendor. Consider testing it with memtest86 yourself. * Exchanging your CPU, cache, or motherboard for one that works. diff --git a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt index 2de1d83005d8..25c7195db918 100644 --- a/Documentation/networking/8139too.txt +++ b/Documentation/networking/8139too.txt @@ -82,7 +82,7 @@ OPTION 1: Build inside kernel tree (into kernel image, or as module) (overwrite 8139too driver in kernel tree with different version) 1) cp 8139too.c $my_source_tree/drivers/net/8139too.c - + OPTION 2: Build outside kernel tree Use the included Makefile. @@ -139,7 +139,7 @@ And thanks to every supporter free software. Submitting Bug Reports ---------------------- -Obtain and compile the modified rtl8139-diag source code from the +Obtain and compile the modified rtl8139-diag source code from the 8139too driver Web site, http://sourceforge.net/projects/gkernel/ This diagnostics programs, originally from Donald Becker, has been modified to display all registers on your RTL8139 chip, not just the @@ -181,6 +181,27 @@ suggestions welcome) (WIP) Change History -------------- +Version 0.9.22 - November 8, 2001 + +* Additional retries before aborting Tx +* Do not write other TxConfig bits when writing clear-abort bit. +* Ack TxErr intr status after each Tx abort, too. + + +Version 0.9.21 - November 1, 2001 + +* Disable early Rx, it hurts performance and creates races. +* Remove DPRINTK macro function tracing. +* Better interrupt sharing behavior. +* Acknowledge PCI errors. +* Remove early-Rx acknowledgement, unnecessary +* Remove code for uncommon case where Tx packets are + properly aligned, and do not need to be copied. + Tx packets are now always copied into a static DMA buffer, + which is allocated at interface open. +* Fix problems with kernel thread exit. + + Version 0.9.20 - October 18, 2001 * Print out notice when 8139C+ chip is detected @@ -212,7 +233,7 @@ Version 0.9.18 - July 6, 2001 Version 0.9.17 - May 7, 2001 * Fix chipset wakeup bug which prevent media connection for 8139B -* Print out "media is unconnected..." instead of +* Print out "media is unconnected..." instead of "partner ability 0000" diff --git a/Documentation/parport.txt b/Documentation/parport.txt index 6eea47a0a308..2a43c34e82f1 100644 --- a/Documentation/parport.txt +++ b/Documentation/parport.txt @@ -162,6 +162,10 @@ modes Parallel port's hardware modes, comma-separated, is available and will be used. DMA DMA is available and will be used. + Note that the current implementation will only take + advantage of COMPAT and ECP modes if it has an IRQ + line to use. + autoprobe Any IEEE-1284 device ID information that has been acquired from the (non-IEEE 1284.3) device. diff --git a/MAINTAINERS b/MAINTAINERS index 0d289243c2e7..741d225f624a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1412,8 +1412,8 @@ L: linux-video@atrey.karlin.mff.cuni.cz S: Maintained SYSV FILESYSTEM -P: Krzysztof G. Baranowski -M: kgb@manjak.knm.org.pl +P: Christoph Hellwig +M: hch@caldera.de S: Maintained TLAN NETWORK DRIVER diff --git a/Makefile b/Makefile index ea7862a1d19f..743f39d52776 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 15 -EXTRAVERSION =-pre1 +EXTRAVERSION =-pre2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/alpha/config.in b/arch/alpha/config.in index b67e2c4fbda3..6fe42adabcba 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -296,6 +296,10 @@ if [ "$CONFIG_SCSI" != "n" ]; then fi endmenu +if [ "$CONFIG_PCI" = "y" ]; then + source drivers/message/fusion/Config.in +fi + if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment comment 'Network device support' diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index deb736f4fba6..a54bcf7dc651 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -1145,3 +1145,6 @@ sys_call_table: .quad sys_mincore /* 375 */ .quad sys_pciconfig_iobase .quad sys_getdents64 + .quad sys_gettid + .quad sys_readahead + .quad sys_ni_syscall /* 380, sys_security */ diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index e3d75f7a1a4f..ebf1463baec2 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c index 237d9abc9647..866d9c8649bf 100644 --- a/arch/alpha/kernel/sys_miata.c +++ b/arch/alpha/kernel/sys_miata.c @@ -176,6 +176,19 @@ miata_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { -1, -1, -1, -1, -1}, /* IdSel 31, PCI-PCI */ }; const long min_idsel = 3, max_idsel = 20, irqs_per_slot = 5; + + /* the USB function of the 82c693 has it's interrupt connected to + the 2nd 8259 controller. So we have to check for it first. */ + + if((slot == 7) && (PCI_FUNC(dev->devfn) == 3)) { + u8 irq=0; + + if(pci_read_config_byte(pci_find_slot(dev->bus->number, dev->devfn & ~(7)), 0x40,&irq)!=PCIBIOS_SUCCESSFUL) + return -1; + else + return irq; + } + return COMMON_TABLE_LOOKUP; } diff --git a/arch/alpha/lib/dec_and_lock.c b/arch/alpha/lib/dec_and_lock.c index 4497441a5a62..875966988f84 100644 --- a/arch/alpha/lib/dec_and_lock.c +++ b/arch/alpha/lib/dec_and_lock.c @@ -18,16 +18,17 @@ atomic_dec_and_lock: \n\ subl $1, 1, $1 \n\ beq $1, 2f \n\ stl_c $1, 0($16) \n\ - beq $1, 3f \n\ + beq $1, 4f \n\ mb \n\ clr $0 \n\ ret \n\ -3: br 1b \n\ -2: lda $27, atomic_dec_and_lock_1 \n\ +2: br $29, 3f \n\ +3: ldgp $29, 0($29) \n\ + br $atomic_dec_and_lock_1..ng \n\ + .subsection 2 \n\ +4: br 1b \n\ .end atomic_dec_and_lock"); - /* FALLTHRU */ - static int __attribute__((unused)) atomic_dec_and_lock_1(atomic_t *atomic, spinlock_t *lock) { diff --git a/arch/alpha/lib/io.c b/arch/alpha/lib/io.c index de592ff08129..46e789239865 100644 --- a/arch/alpha/lib/io.c +++ b/arch/alpha/lib/io.c @@ -9,124 +9,124 @@ #include -unsigned int _inb(unsigned long addr) +u8 _inb(unsigned long addr) { return __inb(addr); } -unsigned int _inw(unsigned long addr) +u16 _inw(unsigned long addr) { return __inw(addr); } -unsigned int _inl(unsigned long addr) +u32 _inl(unsigned long addr) { return __inl(addr); } -void _outb(unsigned char b, unsigned long addr) +void _outb(u8 b, unsigned long addr) { __outb(b, addr); } -void _outw(unsigned short b, unsigned long addr) +void _outw(u16 b, unsigned long addr) { __outw(b, addr); } -void _outl(unsigned int b, unsigned long addr) +void _outl(u32 b, unsigned long addr) { __outl(b, addr); } -unsigned long ___raw_readb(unsigned long addr) +u8 ___raw_readb(unsigned long addr) { return __readb(addr); } -unsigned long ___raw_readw(unsigned long addr) +u16 ___raw_readw(unsigned long addr) { return __readw(addr); } -unsigned long ___raw_readl(unsigned long addr) +u32 ___raw_readl(unsigned long addr) { return __readl(addr); } -unsigned long ___raw_readq(unsigned long addr) +u64 ___raw_readq(unsigned long addr) { return __readq(addr); } -unsigned long _readb(unsigned long addr) +u8 _readb(unsigned long addr) { unsigned long r = __readb(addr); mb(); return r; } -unsigned long _readw(unsigned long addr) +u16 _readw(unsigned long addr) { unsigned long r = __readw(addr); mb(); return r; } -unsigned long _readl(unsigned long addr) +u32 _readl(unsigned long addr) { unsigned long r = __readl(addr); mb(); return r; } -unsigned long _readq(unsigned long addr) +u64 _readq(unsigned long addr) { unsigned long r = __readq(addr); mb(); return r; } -void ___raw_writeb(unsigned char b, unsigned long addr) +void ___raw_writeb(u8 b, unsigned long addr) { __writeb(b, addr); } -void ___raw_writew(unsigned short b, unsigned long addr) +void ___raw_writew(u16 b, unsigned long addr) { __writew(b, addr); } -void ___raw_writel(unsigned int b, unsigned long addr) +void ___raw_writel(u32 b, unsigned long addr) { __writel(b, addr); } -void ___raw_writeq(unsigned long b, unsigned long addr) +void ___raw_writeq(u64 b, unsigned long addr) { __writeq(b, addr); } -void _writeb(unsigned char b, unsigned long addr) +void _writeb(u8 b, unsigned long addr) { __writeb(b, addr); mb(); } -void _writew(unsigned short b, unsigned long addr) +void _writew(u16 b, unsigned long addr) { __writew(b, addr); mb(); } -void _writel(unsigned int b, unsigned long addr) +void _writel(u32 b, unsigned long addr) { __writel(b, addr); mb(); } -void _writeq(unsigned long b, unsigned long addr) +void _writeq(u64 b, unsigned long addr) { __writeq(b, addr); mb(); diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 687a0de2ddd6..26c4c3b6abad 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -39,11 +39,12 @@ tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610 tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi +tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu +AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float ifeq ($(CONFIG_CPU_26),y) PROCESSOR = armo @@ -120,6 +121,10 @@ ifeq ($(CONFIG_ARCH_INTEGRATOR),y) MACHINE = integrator endif +ifeq ($(CONFIG_ARCH_CAMELOT),y) +MACHINE = epxa10db +endif + ifeq ($(CONFIG_ARCH_CLPS711X),y) TEXTADDR = 0xc0028000 MACHINE = clps711x @@ -150,17 +155,22 @@ endif HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ arch/arm/kernel/init_task.o -SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe \ - arch/arm/fastfpe +SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) LIBS := arch/arm/lib/lib.a $(LIBS) ifeq ($(CONFIG_FPE_NWFPE),y) LIBS := arch/arm/nwfpe/math-emu.o $(LIBS) endif + +# Only include fastfpe if it is part of the kernel tree. +FASTFPE := arch/arm/fastfpe +ifeq ($(FASTFPE),$(wildcard $(FASTFPE))) +SUBDIRS += $(FASTFPE) ifeq ($(CONFIG_FPE_FASTFPE),y) LIBS := arch/arm/fastfpe/fast-math-emu.o $(LIBS) endif +endif ifeq ($(findstring y,$(CONFIG_ARCH_CLPS7500) $(CONFIG_ARCH_L7200)),y) SUBDIRS += drivers/acorn/char @@ -213,7 +223,8 @@ archdep: scripts/mkdep archsymlinks @$(MAKETOOLS) dep @$(MAKEBOOT) dep -maketools: checkbin +# we need version.h +maketools: checkbin include/linux/version.h @$(MAKETOOLS) all # Ensure this is ld "2.9.4" or later diff --git a/arch/arm/config.in b/arch/arm/config.in index 86c10eee60c1..845918443bbf 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -12,7 +12,7 @@ define_bool CONFIG_UID16 y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n define_bool CONFIG_GENERIC_BUST_SPINLOCK n - +define_bool CONFIG_GENERIC_ISA_DMA n mainmenu_option next_comment comment 'Code maturity level options' @@ -261,19 +261,42 @@ if [ "$CONFIG_CPU_ARM920T" = "y" ]; then fi fi +# ARM926T +if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + bool 'Support ARM926T processor' CONFIG_CPU_ARM926T +else + define_bool CONFIG_CPU_ARM926T n +fi +if [ "$CONFIG_CPU_ARM926T" = "y" ]; then + bool ' ARM926T CPU idle' CONFIG_CPU_ARM926_CPU_IDLE + bool ' ARM926T I-Cache on' CONFIG_CPU_ARM926_I_CACHE_ON + bool ' ARM926T D-Cache on' CONFIG_CPU_ARM926_D_CACHE_ON + if [ "$CONFIG_CPU_ARM926_D_CACHE_ON" = "y" ] ; then + bool ' Force write through caches on ARM926T' CONFIG_CPU_ARM926_WRITETHROUGH + fi + if [ "$CONFIG_CPU_ARM926_I_CACHE_ON" = "y" -o \ + "$CONFIG_CPU_ARM926_D_CACHE_ON" = "y" ]; then + bool ' Round robin I and D cache replacement algorithm' CONFIG_CPU_ARM926_ROUND_ROBIN + fi +fi + # ARM1020 -#if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then -# bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020 -#else +if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020 +else define_bool CONFIG_CPU_ARM1020 n -#fi -#if [ "$CONFIG_CPU_ARM1020" = "y" ]; then -# bool ' ARM10 I-Cache on' CONFIG_CPU_ARM10_I_CACHE_ON -# bool ' ARM10 D-Cache on' CONFIG_CPU_ARM10_D_CACHE_ON -# if [ "$CONFIG_CPU_ARM10_D_CACHE_ON" = "y" ] ; then -# bool ' Force write through caches on ARM10' CONFIG_CPU_ARM10_FORCE_WRITE_THROUGH -# fi -#fi +fi +if [ "$CONFIG_CPU_ARM1020" = "y" ]; then + bool ' ARM1020 I-Cache on' CONFIG_CPU_ARM1020_I_CACHE_ON + bool ' ARM10 D-Cache on' CONFIG_CPU_ARM1020_D_CACHE_ON + if [ "$CONFIG_CPU_ARM1020_D_CACHE_ON" = "y" ] ; then + bool ' Force write through caches on ARM1020' CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH + fi + if [ "$CONFIG_CPU_ARM1020_I_CACHE_ON" = "y" -o \ + "$CONFIG_CPU_ARM1020_D_CACHE_ON" = "y" ]; then + bool ' Round robin I and D cache replacement algorithm' CONFIG_CPU_ARM1020_ROUND_ROBIN + fi +fi # SA110 if [ "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_FOOTBRIDGE" = "y" -o \ diff --git a/arch/arm/lib/gcclib.h b/arch/arm/lib/gcclib.h index ad70b93e92ba..65314a3d9e27 100644 --- a/arch/arm/lib/gcclib.h +++ b/arch/arm/lib/gcclib.h @@ -11,7 +11,7 @@ typedef int DItype __attribute__ ((mode (DI))); typedef int word_type __attribute__ ((mode (__word__))); typedef unsigned int UDItype __attribute__ ((mode (DI))); -#if 0 /* FIXME: endian test here!!! */ +#ifdef __ARMEB__ struct DIstruct {SItype high, low;}; #else struct DIstruct {SItype low, high;}; diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index d9b9b2c66003..b9282be0dc87 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -34,6 +34,7 @@ p-$(CONFIG_CPU_ARM610) += proc-arm6,7.o p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o p-$(CONFIG_CPU_ARM720T) += proc-arm720.o p-$(CONFIG_CPU_ARM920T) += proc-arm920.o +p-$(CONFIG_CPU_ARM926T) += proc-arm926.o p-$(CONFIG_CPU_ARM1020) += proc-arm1020.o p-$(CONFIG_CPU_SA110) += proc-sa110.o p-$(CONFIG_CPU_SA1100) += proc-sa110.o diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S new file mode 100644 index 000000000000..055d52c2e3b0 --- /dev/null +++ b/arch/arm/mm/proc-arm1020.S @@ -0,0 +1,762 @@ +/* + * linux/arch/arm/mm/arm1020.S: MMU functions for ARM1020 + * + * Copyright (C) 2000 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * These are the low level assembler for performing cache and TLB + * functions on the arm1020. + */ +#include +#include +#include +#include +#include +#include + +/* + * This is the maximum size of an area which will be invalidated + * using the single invalidate entry instructions. Anything larger + * than this, and we go for the whole cache. + * + * This value should be chosen such that we choose the cheapest + * alternative. + */ +#define MAX_AREA_SIZE 32768 + +/* + * the cache line size of the I and D cache + */ +#define DCACHELINESIZE 32 +#define ICACHELINESIZE 32 + +/* + * and the page size + */ +#define PAGESIZE 4096 + + .text + +/* + * cpu_arm1020_data_abort() + * + * obtain information about current aborted instruction + * + * r0 = address of aborted instruction + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +ENTRY(cpu_arm1020_data_abort) + ldr r1, [r0] @ read aborted instruction + mrc p15, 0, r0, c6, c0, 0 @ get FAR + tst r1, r1, lsr #21 @ C = bit 20 + mrc p15, 0, r3, c5, c0, 0 @ get FSR + sbc r1, r1, r1 @ r1 = C - 1 + and r3, r3, #255 + mov pc, lr + +/* + * cpu_arm1020_check_bugs() + */ +ENTRY(cpu_arm1020_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm1020_proc_init() + */ +ENTRY(cpu_arm1020_proc_init) + mov pc, lr + +/* + * cpu_arm1020_proc_fin() + */ +ENTRY(cpu_arm1020_proc_fin) + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_arm1020_cache_clean_invalidate_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm1020_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_arm1020_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * cpu_arm1020_do_idle() + */ + .align 5 +ENTRY(cpu_arm1020_do_idle) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* ================================= CACHE ================================ */ + + +/* + * cpu_arm1020_cache_clean_invalidate_all() + * + * clean and invalidate all cache lines + * + * Note: + * 1. we should preserve r0 at all times + */ + .align 5 +ENTRY(cpu_arm1020_cache_clean_invalidate_all) + mov r2, #1 +cpu_arm1020_cache_clean_invalidate_all_r2: +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, ip, c7, c10, 4 + + mov r1, #0xf @ 16 segments +1: mov r3, #0x3F @ 64 entries +2: mov ip, r3, LSL #26 @ shift up entry + orr ip, ip, r1, LSL #5 @ shift in/up index + mcr p15, 0, ip, c7, c14, 2 @ Clean & Inval DCache entry + mcr p15, 0, ip, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov ip, ip +#endif + subs r3, r3, #1 + cmp r3, #0 + bge 2b @ entries 3F to 0 + subs r1, r1, #1 + cmp r1, #0 + bge 1b @ segments 7 to 0 +#endif + +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache +#endif + mcr p15, 0, ip, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov ip, ip + mov ip, ip +#endif + mov pc, lr + +/* + * cpu_arm1020_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_arm1020_cache_clean_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm1020_cache_clean_invalidate_all_r2 + mcr p15, 0, r3, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r3, c7, c10, 4 @ drain WB + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r3, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b +#endif + +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + teq r2, #0 + movne r0, #0 + mcrne p15, 0, r0, c7, c5, 0 @ invalidate I cache +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif +#endif + mov pc, lr + +/* + * cpu_arm1020_flush_ram_page(page) + * + * clean and invalidate all cache lines associated with this area of memory + * + * page: page to clean and invalidate + */ + .align 5 +ENTRY(cpu_arm1020_flush_ram_page) + mcr p15, 0, r1, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mov r0, #0 + +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_arm1020_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that we must clean the D-cached entries + * around the boundaries if the start and/or end address are not cache + * aligned. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm1020_dcache_invalidate_range) +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + /* D cache are on */ + tst r0, #DCACHELINESIZE - 1 + bic r0, r0, #DCACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 4 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry at start + mcrne p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + tst r1, #DCACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 4 + mcrne p15, 0, r1, c7, c10, 1 @ clean D entry at end + mcrne p15, 0, r1, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r1, r1 + mov r1, r1 + mov r1, r1 +#endif + +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b +#else + /* D cache off, but still drain the write buffer */ + mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif +#endif + mov pc, lr + +/* + * cpu_arm1020_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm1020_dcache_clean_range) + bic r0, r0, #DCACHELINESIZE - 1 + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm1020_cache_clean_invalidate_all_r2 + mcr p15, 0, r3, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r3, c7, c10, 4 @ drain WB + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r3, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b +#endif + +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* + * cpu_arm1020_dcache_clean_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * page: virtual address of page to clean from dcache + * + * Note: + * 1. we don't need to flush the write buffer in this case. + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_arm1020_dcache_clean_page) + mov r1, #PAGESIZE + mcr p15, 0, r0, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bhi 1b +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* + * cpu_arm1020_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_arm1020_dcache_clean_entry) + mov r1, #0 + mcr p15, 0, r1, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r0, c7, c10, 1 @ clean single D entry + mcr p15, 0, r1, c7, c10, 4 @ drain WB +#endif +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + mcr p15, 0, r1, c7, c5, 1 @ invalidate I entry +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r1, r1 + mov r1, r1 +#endif + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_arm1020_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm1020_icache_invalidate_range) +1: mcr p15, 0, r0, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r0, c7, c10, 1 @ Clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blo 1b +ENTRY(cpu_arm1020_icache_invalidate_page) + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* ================================== TLB ================================= */ + +/* + * cpu_arm1020_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_arm1020_tlb_invalidate_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D tlbs +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* + * cpu_arm1020_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_arm1020_tlb_invalidate_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm1020_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_arm1020_tlb_invalidate_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_arm1020_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_arm1020_set_pgd) +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r3, c7, c10, 4 + mov r1, #0xF @ 16 segments +1: mov r3, #0x3F @ 64 entries +2: mov ip, r3, LSL #26 @ shift up entry + orr ip, ip, r1, LSL #5 @ shift in/up index + mcr p15, 0, ip, c7, c14, 2 @ Clean & Inval DCache entry + mov ip, #0 + mcr p15, 0, ip, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov ip, ip +#endif + subs r3, r3, #1 + cmp r3, #0 + bge 2b @ entries 3F to 0 + subs r1, r1, #1 + cmp r1, #0 + bge 1b @ segments 15 to 0 + +#endif + mov r1, #0 +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache +#endif + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov ip, ip + mov ip, ip +#endif + mov pc, lr + +/* + * cpu_arm1020_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_arm1020_set_pmd) +#ifdef CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH + eor r2, r1, #0x0a @ C & Section + tst r2, #0x0b + biceq r1, r1, #4 @ clear bufferable bit +#endif + str r1, [r0] +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r0, c7, c10, 4 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* + * cpu_arm1020_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_arm1020_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + +#ifdef CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH + eor r3, r1, #0x0a @ C & small page? + tst r3, #0x0b + biceq r2, r2, #4 +#endif + str r2, [r0] @ hardware version + mov r0, r0 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r0, c7, c10, 4 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + + +cpu_manu_name: + .asciz "ARM/VLSI" +ENTRY(cpu_arm1020_name) + .ascii "Arm1020" +#if defined(CONFIG_CPU_ARM1020_CPU_IDLE) + .ascii "s" +#endif +#if defined(CONFIG_CPU_ARM1020_I_CACHE_ON) + .ascii "i" +#endif +#if defined(CONFIG_CPU_ARM1020_D_CACHE_ON) + .ascii "d" +#if defined(CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH) + .ascii "(wt)" +#else + .ascii "(wb)" +#endif +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + .ascii "B" +#endif +#ifdef CONFIG_CPU_ARM1020_ROUND_ROBIN + .ascii "RR" +#endif + .ascii "\0" + .align + + .section ".text.init", #alloc, #execinstr + +__arm1020_setup: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + bic r0, r0, #0x0e00 @ ....??r......... + bic r0, r0, #0x0002 @ ..............a. + bic r0, r0, #0x000c @ W,D + bic r0, r0, #0x1000 @ I +/* + * Turn on what we want + */ + orr r0, r0, #0x0031 @ ..........DP...M + orr r0, r0, #0x0100 @ .......S........ + +#ifdef CONFIG_CPU_ARM1020_ROUND_ROBIN + orr r0, r0, #0x4000 @ .R.............. +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + orr r0, r0, #0x0800 @ ....Z........... +#endif +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + orr r0, r0, #0x0004 @ Enable D cache +#endif +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + orr r0, r0, #0x1000 @ I Cache on +#endif + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm1020_processor_functions, #object +arm1020_processor_functions: + .word cpu_arm1020_data_abort + .word cpu_arm1020_check_bugs + .word cpu_arm1020_proc_init + .word cpu_arm1020_proc_fin + .word cpu_arm1020_reset + .word cpu_arm1020_do_idle + + /* cache */ + .word cpu_arm1020_cache_clean_invalidate_all + .word cpu_arm1020_cache_clean_invalidate_range + .word cpu_arm1020_flush_ram_page + + /* dcache */ + .word cpu_arm1020_dcache_invalidate_range + .word cpu_arm1020_dcache_clean_range + .word cpu_arm1020_dcache_clean_page + .word cpu_arm1020_dcache_clean_entry + + /* icache */ + .word cpu_arm1020_icache_invalidate_range + .word cpu_arm1020_icache_invalidate_page + + /* tlb */ + .word cpu_arm1020_tlb_invalidate_all + .word cpu_arm1020_tlb_invalidate_range + .word cpu_arm1020_tlb_invalidate_page + + /* pgtable */ + .word cpu_arm1020_set_pgd + .word cpu_arm1020_set_pmd + .word cpu_arm1020_set_pte + .size arm1020_processor_functions, . - arm1020_processor_functions + + .type cpu_arm1020_info, #object +cpu_arm1020_info: + .long cpu_manu_name + .long cpu_arm1020_name + .size cpu_arm1020_info, . - cpu_arm1020_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __arm1020_proc_info,#object +__arm1020_proc_info: + .long 0x4100a200 + .long 0xff00fff0 + .long 0x00000c02 @ mmuflags + b __arm1020_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm1020_info + .long arm1020_processor_functions + .size __arm1020_proc_info, . - __arm1020_proc_info diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S new file mode 100644 index 000000000000..d3ecda0ca503 --- /dev/null +++ b/arch/arm/mm/proc-arm926.S @@ -0,0 +1,667 @@ +/* + * linux/arch/arm/mm/arm926.S: MMU functions for ARM926EJ-S + * + * Copyright (C) 1999-2001 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * These are the low level assembler for performing cache and TLB + * functions on the arm926. + */ +#include +#include +#include +#include +#include +#include + +/* + * This is the maximum size of an area which will be invalidated + * using the single invalidate entry instructions. Anything larger + * than this, and we go for the whole cache. + * + * This value should be chosen such that we choose the cheapest + * alternative. + */ +#define MAX_AREA_SIZE 16384 + +/* + * the cache line size of the I and D cache + */ +#define DCACHELINESIZE 32 +#define ICACHELINESIZE 32 + +/* + * and the page size + */ +#define PAGESIZE 4096 + + .text + +/* + * cpu_arm926_data_abort() + * + * obtain information about current aborted instruction + * + * Inputs: + * r0 = address of abort + * r1 = cpsr of abort + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +ENTRY(cpu_arm926_data_abort) + tst r1, #1<<24 @ Check for Jbit (NE -> found) + movne r1, #-1 @ Mark as writing + bne 2f + + tst r1, #1<<5 @ Check for Thumb-bit (NE -> found) + ldrneh r1, [r0] @ Read aborted Thumb instruction + tstne r1, r1, lsr #12 @ C = bit 11 + + ldreq r1, [r0] @ Read aborted ARM instruction + tsteq r1, r1, lsr #21 @ C = bit 20 + + sbc r1, r1, r1 @ r1 = C - 1 +2: + mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r3, r3, #255 + mrc p15, 0, r0, c6, c0, 0 @ get FAR + + mov pc, lr + +/* + * cpu_arm926_check_bugs() + */ +ENTRY(cpu_arm926_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm926_proc_init() + */ +ENTRY(cpu_arm926_proc_init) + mov pc, lr + +/* + * cpu_arm926_proc_fin() + */ +ENTRY(cpu_arm926_proc_fin) + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_arm926_cache_clean_invalidate_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm926_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_arm926_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * cpu_arm926_do_idle() + */ + .align 5 +ENTRY(cpu_arm926_do_idle) +#if defined(CONFIG_CPU_ARM926_CPU_IDLE) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#endif + mov pc, lr + +/* ================================= CACHE ================================ */ + + +/* + * cpu_arm926_cache_clean_invalidate_all() + * + * clean and invalidate all cache lines + * + * Note: + * 1. we should preserve r0 at all times + */ + .align 5 +ENTRY(cpu_arm926_cache_clean_invalidate_all) + mov r2, #1 +cpu_arm926_cache_clean_invalidate_all_r2: + mov ip, #0 +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +1: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate + bne 1b +#endif + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm926_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * This is a little misleading, it is not intended to clean out + * the i-cache but to make sure that any data written to the + * range is made consistant. This means that when we execute code + * in that region, everything works as we expect. + * + * This generally means writing back data in the Dcache and + * write buffer and flushing the Icache over that region + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_arm926_cache_clean_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 @ && added by PGM + bic r1, r1, #DCACHELINESIZE - 1 @ && added by DHM + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm926_cache_clean_invalidate_all_r2 + +1: teq r2, #0 +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE +#else + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE +#endif + + cmp r0, r1 + blt 1b + + mcr p15, 0, r1, c7, c10, 4 @ drain WB + + mov pc, lr + +/* + * cpu_arm926_flush_ram_page(page) + * + * clean and invalidate all cache lines associated with this area of memory + * + * page: page to clean and invalidate + */ + .align 5 +ENTRY(cpu_arm926_flush_ram_page) + mov r1, #PAGESIZE +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE +#else +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE +#endif + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_arm926_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that we must clean the D-cached entries + * around the boundaries if the start and/or end address are not cache + * aligned. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm926_dcache_invalidate_range) +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + tst r0, #DCACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry + tst r1, #DCACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 +#endif @ clean D entry + bic r0, r0, #DCACHELINESIZE - 1 + bic r1, r1, #DCACHELINESIZE - 1 +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm926_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm926_dcache_clean_range) +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + bic r0, r0, #DCACHELINESIZE - 1 + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + mov r2, #0 + bgt cpu_arm926_cache_clean_invalidate_all_r2 + + bic r1, r1, #DCACHELINESIZE -1 + add r1, r1, #DCACHELINESIZE + +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #DCACHELINESIZE + bpl 1b +#endif + mcr p15, 0, r2, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm926_dcache_clean_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * page: virtual address of page to clean from dcache + * + * Note: + * 1. we don't need to flush the write buffer in this case. + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_arm926_dcache_clean_page) +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bne 1b +#endif + mov pc, lr + +/* + * cpu_arm926_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_arm926_dcache_clean_entry) +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_arm926_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm926_icache_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 @ Safety check + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + bgt cpu_arm926_cache_clean_invalidate_all_r2 + + bic r1, r1, #DCACHELINESIZE - 1 + add r1, r1, #DCACHELINESIZE + +1: mcr p15, 0, r0, c7, c5, 1 @ clean I entries + add r0, r0, #DCACHELINESIZE + subs r1, r1, #DCACHELINESIZE + bne 1b + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +ENTRY(cpu_arm926_icache_invalidate_page) + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mov pc, lr + + +/* ================================== TLB ================================= */ + +/* + * cpu_arm926_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_arm926_tlb_invalidate_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm926_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_arm926_tlb_invalidate_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + + mov r3, #PAGESIZE + sub r3, r3, #1 + bic r0, r0, r3 + bic r1, r1, r3 + +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm926_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_arm926_tlb_invalidate_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_arm926_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_arm926_set_pgd) + mov ip, #0 +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + /* Any reason why we don't use mcr p15, 0, r0, c7, c7, 0 here? --rmk */ + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +@ && 'Clean & Invalidate whole DCache' +1: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate + bne 1b +#endif + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm926_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_arm926_set_pmd) +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + eor r2, r1, #0x0a @ C & Section + tst r2, #0x0b + biceq r1, r1, #4 @ clear bufferable bit +#endif + str r1, [r0] +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm926_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_arm926_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + eor r3, r2, #0x0a @ C & small page? + tst r3, #0x0b + biceq r2, r2, #4 +#endif + str r2, [r0] @ hardware version + mov r0, r0 +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + + +cpu_manu_name: + .asciz "ARM" +ENTRY(cpu_arm926_name) + .ascii "ARM926EJ-S" +#if defined(CONFIG_CPU_ARM926_CPU_IDLE) + .ascii "s" +#endif +#if defined(CONFIG_CPU_ARM926_I_CACHE_ON) + .ascii "i" +#endif +#if defined(CONFIG_CPU_ARM926_D_CACHE_ON) + .ascii "d" +#if defined(CONFIG_CPU_ARM926_WRITETHROUGH) + .ascii "(wt)" +#else + .ascii "(wb)" +#endif +#ifdef CONFIG_CPU_ARM926_ROUND_ROBIN + .ascii "RR" +#endif +#endif + .ascii "\0" + .align + + .section ".text.init", #alloc, #execinstr + +__arm926_setup: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + + +#if defined(CONFIG_CPU_ARM926_WRITETHROUGH) + mov r0, #4 @ disable write-back on caches explicitly + mcr p15, 7, r0, c15, c0, 0 +#endif + + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + @ VI ZFRS BLDP WCAM + bic r0, r0, #0x0e00 + bic r0, r0, #0x0002 + bic r0, r0, #0x000c + bic r0, r0, #0x1000 @ ...0 000. .... 000. +/* + * Turn on what we want + */ + orr r0, r0, #0x0031 + orr r0, r0, #0x2100 @ ..1. ...1 ..11 ...1 + +#ifdef CONFIG_CPU_ARM926_ROUND_ROBIN + orr r0, r0, #0x4000 @ .1.. .... .... .... +#endif +#ifdef CONFIG_CPU_ARM926_D_CACHE_ON + orr r0, r0, #0x0004 @ .... .... .... .1.. +#endif +#ifdef CONFIG_CPU_ARM926_I_CACHE_ON + orr r0, r0, #0x1000 @ ...1 .... .... .... +#endif + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm926_processor_functions, #object +arm926_processor_functions: + .word cpu_arm926_data_abort + .word cpu_arm926_check_bugs + .word cpu_arm926_proc_init + .word cpu_arm926_proc_fin + .word cpu_arm926_reset + .word cpu_arm926_do_idle + + /* cache */ + .word cpu_arm926_cache_clean_invalidate_all + .word cpu_arm926_cache_clean_invalidate_range + .word cpu_arm926_flush_ram_page + + /* dcache */ + .word cpu_arm926_dcache_invalidate_range + .word cpu_arm926_dcache_clean_range + .word cpu_arm926_dcache_clean_page + .word cpu_arm926_dcache_clean_entry + + /* icache */ + .word cpu_arm926_icache_invalidate_range + .word cpu_arm926_icache_invalidate_page + + /* tlb */ + .word cpu_arm926_tlb_invalidate_all + .word cpu_arm926_tlb_invalidate_range + .word cpu_arm926_tlb_invalidate_page + + /* pgtable */ + .word cpu_arm926_set_pgd + .word cpu_arm926_set_pmd + .word cpu_arm926_set_pte + .size arm926_processor_functions, . - arm926_processor_functions + + .type cpu_arm926_info, #object +cpu_arm926_info: + .long cpu_manu_name + .long cpu_arm926_name + .size cpu_arm926_info, . - cpu_arm926_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5EJ" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5EJ" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __arm926_proc_info,#object +__arm926_proc_info: + .long 0x41009260 + .long 0xff00fff0 + .long 0x00000c1e @ mmuflags + b __arm926_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm926_info + .long arm926_processor_functions + .size __arm926_proc_info, . - __arm926_proc_info diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index eea3d63b8501..8d3b013b707f 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Mon Oct 22 09:49:06 2001 +# Last update: Fri Oct 26 17:37:13 2001 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -134,3 +134,6 @@ bushstb ARCH_BUSHSTB BUSHSTB 122 epsilon1 SA1100_EPSILON1 EPSILON1 123 balloon SA1100_BALLOON BALLOON 124 puppy ARCH_PUPPY PUPPY 125 +elroy SA1100_ELROY ELROY 126 +gms720 ARCH_GMS720 GMS720 127 +s24x ARCH_S24X S24X 128 diff --git a/arch/cris/defconfig b/arch/cris/defconfig index 61fc16f594f4..d784598b78f5 100644 --- a/arch/cris/defconfig +++ b/arch/cris/defconfig @@ -82,8 +82,9 @@ CONFIG_ETRAX_ETHERNET=y CONFIG_NET_ETHERNET=y # CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y -C# CONFIG_ETRAX_ETHERNET_LPSLAVE is not set -ONFIG_ETRAX_SERIAL=y +# CONFIG_ETRAX_ETHERNET_LPSLAVE is not set +CONFIG_ETRAX_SERIAL=y +CONFIG_ETRAX_SERIAL_PORT0=y # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set CONFIG_ETRAX_SERIAL_PORT1=y # CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set diff --git a/arch/cris/drivers/Config.in b/arch/cris/drivers/Config.in index 06b68ef5ab7e..7d934a60035b 100644 --- a/arch/cris/drivers/Config.in +++ b/arch/cris/drivers/Config.in @@ -23,6 +23,14 @@ fi bool 'Serial-port support' CONFIG_ETRAX_SERIAL if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then +# bool ' Use fast timers for DMA flush and RS-485 timing' CONFIG_ETRAX_SERIAL_FAST_TIMER n + define_bool CONFIG_ETRAX_SERIAL_FAST_TIMER n + if [ "$CONFIG_ETRAX_SERIAL_FAST_TIMER" = "n" ]; then + bool ' Fast serial port DMA flush' CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST + if [ "$CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST" = "n" ]; then + int ' Receive flush timeout (ticks) ' CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 + fi + fi bool ' Serial port 0 enabled' CONFIG_ETRAX_SERIAL_PORT0 if [ "$CONFIG_ETRAX_SERIAL_PORT0" = "y" ]; then bool ' Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB diff --git a/arch/cris/drivers/axisflashmap.c b/arch/cris/drivers/axisflashmap.c index 93233154f953..784c444bb9d1 100644 --- a/arch/cris/drivers/axisflashmap.c +++ b/arch/cris/drivers/axisflashmap.c @@ -11,6 +11,9 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.15 2001/10/19 12:41:04 jonashg + * Name of probe has changed in MTD. + * * Revision 1.14 2001/09/21 07:14:10 jonashg * Made root filesystem (cramfs) use mtdblock driver when booting from flash. * @@ -237,7 +240,9 @@ init_axis_flash(void) printk(KERN_NOTICE "Axis flash mapping: %x at %x\n", WINDOW_SIZE, FLASH_CACHED_ADDR); - mymtd = (struct mtd_info *)do_map_probe("cfi", &axis_map); +#ifdef CONFIG_MTD_CFI + mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &axis_map); +#endif #ifdef CONFIG_MTD_AMDSTD if (!mymtd) { diff --git a/arch/cris/drivers/gpio.c b/arch/cris/drivers/gpio.c index c7627e074115..a88b0f6e44bd 100644 --- a/arch/cris/drivers/gpio.c +++ b/arch/cris/drivers/gpio.c @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.9 2001/05/04 14:16:07 matsfg Exp $ +/* $Id: gpio.c,v 1.11 2001/10/30 14:39:12 johana Exp $ * * Etrax general port I/O device * @@ -6,9 +6,18 @@ * * Authors: Bjorn Wesen (initial version) * Ola Knutsson (LED handling) - * Johan Adolfsson (read/set directions) + * Johan Adolfsson (read/set directions, write) * * $Log: gpio.c,v $ + * Revision 1.11 2001/10/30 14:39:12 johana + * Added D() around gpio_write printk. + * + * Revision 1.10 2001/10/25 10:24:42 johana + * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast + * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB + * from ~60 seconds to 4 seconds). + * Added save_flags/cli/restore_flags in ioctl. + * * Revision 1.9 2001/05/04 14:16:07 matsfg * Corrected spelling error * @@ -69,6 +78,8 @@ static wait_queue_head_t *gpio_wq; static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static ssize_t gpio_write(struct file * file, const char * buf, size_t count, + loff_t *off); static int gpio_open(struct inode *inode, struct file *filp); static int gpio_release(struct inode *inode, struct file *filp); static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); @@ -82,6 +93,9 @@ struct gpio_private { unsigned char changeable_dir; unsigned char changeable_bits; unsigned char highalarm, lowalarm; + unsigned char clk_mask; + unsigned char data_mask; + unsigned char write_msb; wait_queue_head_t alarm_wq; int minor; }; @@ -139,6 +153,59 @@ gpio_poll(struct file *filp, return 1; } +static ssize_t gpio_write(struct file * file, const char * buf, size_t count, + loff_t *off) +{ + struct gpio_private *priv = (struct gpio_private *)file->private_data; + unsigned char data, clk_mask, data_mask, write_msb; + unsigned long flags; + ssize_t retval = count; + if (verify_area(VERIFY_READ, buf, count)) + { + return -EFAULT; + } + clk_mask = priv->clk_mask; + data_mask = priv->data_mask; + /* It must have been configured using the IO_CFG_WRITE_MODE */ + /* Perhaps a better error code? */ + if (clk_mask == 0 || data_mask == 0) + { + return -EPERM; + } + write_msb = priv->write_msb; + D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb)); + while (count--) { + int i; + data = *buf++; + if (priv->write_msb) { + for (i = 7; i>=0;i--) { + save_flags(flags); cli(); + *priv->port = *priv->shadow &= ~clk_mask; + if (data & 1<port = *priv->shadow |= data_mask; + else + *priv->port = *priv->shadow &= ~data_mask; + /* For FPGA: min 5.0ns (DCC) before CCLK high */ + *priv->port = *priv->shadow |= clk_mask; + restore_flags(flags); + } + } else { + for (i = 0; i<=7;i++) { + save_flags(flags); cli(); + *priv->port = *priv->shadow &= ~clk_mask; + if (data & 1<port = *priv->shadow |= data_mask; + else + *priv->port = *priv->shadow &= ~data_mask; + /* For FPGA: min 5.0ns (DCC) before CCLK high */ + *priv->port = *priv->shadow |= clk_mask; + restore_flags(flags); + } + } + } + return retval; +} + static int gpio_open(struct inode *inode, struct file *filp) { @@ -170,6 +237,8 @@ gpio_open(struct inode *inode, struct file *filp) priv->highalarm = 0; priv->lowalarm = 0; + priv->clk_mask = 0; + priv->data_mask = 0; init_waitqueue_head(&priv->alarm_wq); filp->private_data = (void *)priv; @@ -209,8 +278,8 @@ static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + unsigned long flags; struct gpio_private *priv = (struct gpio_private *)file->private_data; - if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { return -EINVAL; } @@ -220,14 +289,18 @@ gpio_ioctl(struct inode *inode, struct file *file, // read the port return *priv->port; case IO_SETBITS: + save_flags(flags); cli(); // set changeable bits with a 1 in arg *priv->port = *priv->shadow |= ((unsigned char)arg & priv->changeable_bits); + restore_flags(flags); break; case IO_CLRBITS: + save_flags(flags); cli(); // clear changeable bits with a 1 in arg *priv->port = *priv->shadow &= ~((unsigned char)arg & priv->changeable_bits); + restore_flags(flags); break; case IO_HIGHALARM: // set alarm when bits with 1 in arg go high @@ -246,14 +319,18 @@ gpio_ioctl(struct inode *inode, struct file *file, /* Read direction 0=input 1=output */ return *priv->dir_shadow; case IO_SETINPUT: + save_flags(flags); cli(); /* Set direction 0=unchanged 1=input */ *priv->dir = *priv->dir_shadow &= ~((unsigned char)arg & priv->changeable_dir); + restore_flags(flags); return *priv->dir_shadow; case IO_SETOUTPUT: + save_flags(flags); cli(); /* Set direction 0=unchanged 1=output */ *priv->dir = *priv->dir_shadow |= ((unsigned char)arg & priv->changeable_dir); + restore_flags(flags); return *priv->dir_shadow; case IO_SHUTDOWN: SOFT_SHUTDOWN(); @@ -265,6 +342,24 @@ gpio_ioctl(struct inode *inode, struct file *file, #else return 0; #endif + break; + case IO_CFG_WRITE_MODE: + priv->clk_mask = arg & 0xFF; + priv->data_mask = (arg >> 8) & 0xFF; + priv->write_msb = (arg >> 16) & 0x01; + /* Check if we're allowed to change the bits and + * the direction is correct + */ + if (!((priv->clk_mask & priv->changeable_bits) && + (priv->data_mask & priv->changeable_bits) && + (priv->clk_mask & *priv->dir_shadow) && + (priv->data_mask & *priv->dir_shadow)) ) + { + priv->clk_mask = 0; + priv->data_mask = 0; + return -EPERM; + } + break; default: if(priv->minor == LEDS) return gpio_leds_ioctl(cmd, arg); @@ -301,6 +396,7 @@ struct file_operations gpio_fops = { owner: THIS_MODULE, poll: gpio_poll, ioctl: gpio_ioctl, + write: gpio_write, open: gpio_open, release: gpio_release, }; @@ -338,7 +434,7 @@ gpio_init(void) #endif - printk("ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB\n"); + printk("ETRAX 100LX GPIO driver v2.2, (c) 2001 Axis Communications AB\n"); return res; } diff --git a/arch/cris/drivers/serial.c b/arch/cris/drivers/serial.c index b59ce87134e5..6de63c4ac822 100644 --- a/arch/cris/drivers/serial.c +++ b/arch/cris/drivers/serial.c @@ -1,4 +1,4 @@ -/* $Id: serial.c,v 1.18 2001/09/24 09:27:22 pkj Exp $ +/* $Id: serial.c,v 1.23 2001/10/30 17:53:26 pkj Exp $ * * Serial port driver for the ETRAX 100LX chip * @@ -7,6 +7,27 @@ * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ + * Revision 1.23 2001/10/30 17:53:26 pkj + * * Set info->uses_dma to 0 when a port is closed. + * * Mark the timer1 interrupt as a fast one (SA_INTERRUPT). + * * Call start_flush_timer() in start_receive() if + * CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is defined. + * + * Revision 1.22 2001/10/30 17:44:03 pkj + * Use %lu for received and transmitted counters in line_info(). + * + * Revision 1.21 2001/10/30 17:40:34 pkj + * Clean-up. The only change to functionality is that + * CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS(=5) is used instead of + * MAX_FLUSH_TIME(=8). + * + * Revision 1.20 2001/10/30 15:24:49 johana + * Added char_time stuff from 2.0 driver. + * + * Revision 1.19 2001/10/30 15:23:03 johana + * Merged with 1.13.2 branch + fixed indentation + * and changed CONFIG_ETRAX100_XYS to CONFIG_ETRAX_XYZ + * * Revision 1.18 2001/09/24 09:27:22 pkj * Completed ext_baud_table[] in cflag_to_baud() and cflag_to_etrax_baud(). * @@ -26,11 +47,19 @@ * Revision 1.14 2001/08/15 07:31:23 bjarne * Introduced two new members to the e100_serial struct. * configured - Will be set to 1 if the port has been configured in .config - * uses_dma - Should be set to 1 if the port uses DMA. Currently it is set to 1 + * uses_dma - Should be set to 1 if the port uses DMA. Currently it is set + * to 1 * when a port is opened. This is used to limit the DMA interrupt * routines to only manipulate DMA channels actually used by the * serial driver. * + * Revision 1.13.2.2 2001/10/17 13:57:13 starvik + * Receiver was broken by the break fixes + * + * Revision 1.13.2.1 2001/07/20 13:57:39 ronny + * Merge with new stuff from etrax100ser.c. Works but haven't checked stuff + * like break handling. + * * Revision 1.13 2001/05/09 12:40:31 johana * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h * @@ -226,7 +255,7 @@ * */ -static char *serial_version = "$Revision: 1.18 $"; +static char *serial_version = "$Revision: 1.23 $"; #include #include @@ -284,6 +313,11 @@ static int serial_refcount; #define SERIAL_TYPE_CALLOUT 2 #endif +#define DEBUG_LOG(line, string, value) + +/* Add an x here to log a lot of timer stuff */ +#define TIMERD(x) + /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -299,8 +333,9 @@ static int serial_refcount; expect the first received event on the serial port to be an error, break or similar. Used to be able to flash IRMA from eLinux */ -//#define SERIAL_HANDLE_EARLY_ERRORS +#define SERIAL_HANDLE_EARLY_ERRORS +#define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10) #ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS /* Default number of timer ticks before flushing rx fifo @@ -310,8 +345,6 @@ static int serial_refcount; #define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 #endif -#define MAX_FLUSH_TIME 8 - #define _INLINE_ inline static void change_speed(struct e100_serial *info); @@ -320,7 +353,7 @@ static int rs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count); #define DEF_BAUD 0x99 /* 115.2 kbit/s */ -#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST ) +#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) #define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */ /* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ #define DEF_TX 0x80 /* or SERIAL_CTRL_B */ @@ -335,6 +368,22 @@ static int rs_write(struct tty_struct * tty, int from_user, #define REG_BAUD 3 #define REG_XOFF 4 /* this is a 32 bit register */ +/* The bitfields are the same for all serial ports */ +#define SER_RXD_MASK IO_MASK(R_SERIAL0_STATUS, rxd) +#define SER_DATA_AVAIL_MASK IO_MASK(R_SERIAL0_STATUS, data_avail) +#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err) +#define SER_PAR_ERR_MASK IO_MASK(R_SERIAL0_STATUS, par_err) +#define SER_OVERRUN_MASK IO_MASK(R_SERIAL0_STATUS, overrun) + +#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK) + +/* Values for info->errorcode */ +#define ERRCODE_SET_BREAK (TTY_BREAK) +#define ERRCODE_INSERT 0x100 +#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK) + +#define FORCE_EOP(info) *R_SET_EOP = 1U << info->iseteop; + /* * General note regarding the use of IO_* macros in this file: * @@ -413,6 +462,29 @@ static struct tty_struct *serial_table[NR_PORTS]; static struct termios *serial_termios[NR_PORTS]; static struct termios *serial_termios_locked[NR_PORTS]; +#ifdef CONFIG_SERIAL_PROC_ENTRY +#define PROCSTAT(x) x +struct ser_statistics_type{ + int overrun_cnt; + int early_errors_cnt; + int ser_ints_ok_cnt; + int errors_cnt; + unsigned long int processing_flip; + unsigned long processing_flip_still_room; + unsigned long int timeout_flush_cnt; + int rx_dma_ints; + int tx_dma_ints; + int rx_tot; + int tx_tot; +}; + +static struct ser_statistics_type ser_stat[NR_PORTS]; + +#else + +#define PROCSTAT(x) + +#endif /* CONFIG_SERIAL_PROC_ENTRY */ /* RS-485 */ #if defined(CONFIG_ETRAX_RS485) @@ -577,10 +649,34 @@ static void _INLINE_ start_flush_timer(void) /* enable timer1 irq */ *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); + fast_timer_started = 1; } #endif /* CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST */ +/* Calculate the chartime depending on baudrate, numbor of bits etc. */ +static void update_char_time(struct e100_serial * info) +{ + tcflag_t cflags = info->tty->termios->c_cflag; + int bits; + + /* calc. number of bits / data byte */ + /* databits + startbit and 1 stopbit */ + if ((cflags & CSIZE) == CS7) + bits = 9; + else + bits = 10; + + if (cflags & CSTOPB) /* 2 stopbits ? */ + bits++; + + if (cflags & PARENB) /* parity bit ? */ + bits++; + + /* calc timeout */ + info->char_time_usec = ((bits * 1000000) / info->baud) + 1; +} + /* * This function maps from the Bxxxx defines in asm/termbits.h into real * baud rates. @@ -642,7 +738,8 @@ static inline void e100_dtr(struct e100_serial *info, int set) { #ifndef CONFIG_SVINTO_SIM - unsigned char mask = ( 1 << e100_modem_pins[info->line].dtr_bit); + unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit); + #ifdef SERIAL_DEBUG_IO printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); printk("ser%i shadow before 0x%02X get: %i\n", @@ -651,7 +748,8 @@ e100_dtr(struct e100_serial *info, int set) #endif /* DTR is active low */ { - unsigned long flags; + unsigned long flags; + save_flags(flags); cli(); *e100_modem_pins[info->line].shadow &= ~mask; @@ -696,8 +794,9 @@ e100_ri_out(struct e100_serial *info, int set) #ifndef CONFIG_SVINTO_SIM /* RI is active low */ { - unsigned char mask = ( 1 << e100_modem_pins[info->line].ri_bit); - unsigned long flags; + unsigned char mask = (1 << e100_modem_pins[info->line].ri_bit); + unsigned long flags; + save_flags(flags); cli(); *e100_modem_pins[info->line].shadow &= ~mask; @@ -718,8 +817,9 @@ e100_cd_out(struct e100_serial *info, int set) #ifndef CONFIG_SVINTO_SIM /* CD is active low */ { - unsigned char mask = ( 1 << e100_modem_pins[info->line].cd_bit); - unsigned long flags; + unsigned char mask = (1 << e100_modem_pins[info->line].cd_bit); + unsigned long flags; + save_flags(flags); cli(); *e100_modem_pins[info->line].shadow &= ~mask; @@ -797,7 +897,7 @@ e100_enable_txdma_irq(struct e100_serial *info) #ifdef SERIAL_HANDLE_EARLY_ERRORS /* in order to detect and fix errors on the first byte - we have to use the serial interrupts as well. */ + we have to use the serial interrupts as well. */ static inline void e100_disable_serial_data_irq(struct e100_serial *info) @@ -860,7 +960,7 @@ e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) e100_disable_rxdma_irq(info); #endif - if (info->rs485.delay_rts_before_send > 0){ + if (info->rs485.delay_rts_before_send > 0) { current->timeout = jiffies + (info->rs485.delay_rts_before_send * HZ)/1000; current->state = TASK_INTERRUPTIBLE; schedule(); @@ -880,36 +980,38 @@ e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) /* calc. number of bits / data byte */ cflags = info->tty->termios->c_cflag; + /* databits + startbit and 1 stopbit */ - if((cflags & CSIZE) == CS7) - bits = 9; + if ((cflags & CSIZE) == CS7) + bits = 9; else - bits = 10; + bits = 10; - if(cflags & CSTOPB) /* 2 stopbits ? */ - bits++; + if (cflags & CSTOPB) /* 2 stopbits ? */ + bits++; - if(cflags & PARENB) /* parity bit ? */ - bits++; + if (cflags & PARENB) /* parity bit ? */ + bits++; /* calc timeout */ delay_ms = ((bits * size * 1000) / info->baud) + 1; max_j = jiffies + (delay_ms * HZ)/1000 + 10; - while (jiffies < max_j ) { - if (info->port[REG_STATUS] & - IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { - for( i=0 ; i<100; i++ ) {}; - if (info->port[REG_STATUS] & - IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { - /* ~25 for loops per usec */ - stop_delay = 1000000 / info->baud; - if(cflags & CSTOPB) - stop_delay *= 2; - udelay(stop_delay); - break; - } - } + while (jiffies < max_j) { + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { + for (i = 0; i < 100; i++) + ; + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { + /* ~25 for loops per usec */ + stop_delay = 1000000 / info->baud; + if (cflags & CSTOPB) + stop_delay *= 2; + udelay(stop_delay); + break; + } + } } e100_rts(info, info->rs485.rts_after_sent); @@ -1004,9 +1106,9 @@ transmit_chars(struct e100_serial *info) * no-op - transmit_chars would never really be called during sim * since rs_write does not write into the xmit buffer then. */ - if(info->xmit.tail) + if (info->xmit.tail) printk("Error in serial.c:transmit_chars(), tail!=0\n"); - if(info->xmit.head != info->xmit.tail) { + if (info->xmit.head != info->xmit.tail) { SIMCOUT(info->xmit.buf + info->xmit.tail, CIRC_CNT(info->xmit.head, info->xmit.tail, @@ -1022,10 +1124,10 @@ transmit_chars(struct e100_serial *info) IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); #ifdef SERIAL_DEBUG_INTR - if(info->line == SERIAL_DEBUG_LINE) + if (info->line == SERIAL_DEBUG_LINE) printk("tc\n"); #endif - if(!info->tr_running) { + if (!info->tr_running) { /* weirdo... we shouldn't get here! */ printk("Achtung: transmit_chars with !tr_running\n"); return; @@ -1037,7 +1139,7 @@ transmit_chars(struct e100_serial *info) and update xmit accordingly */ /* if the stop bit was not set, all data has been sent */ - if(!(descr->status & d_stop)) { + if (!(descr->status & d_stop)) { sentl = descr->sw_len; } else /* otherwise we find the amount of data sent here */ @@ -1060,7 +1162,7 @@ transmit_chars(struct e100_serial *info) c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); - if(c <= 0) { + if (c <= 0) { /* our job here is done, don't schedule any new DMA transfer */ info->tr_running = 0; @@ -1106,7 +1208,7 @@ static void start_transmit(struct e100_serial *info) { #if 0 - if(info->line == SERIAL_DEBUG_LINE) + if (info->line == SERIAL_DEBUG_LINE) printk("x\n"); #endif @@ -1118,7 +1220,6 @@ start_transmit(struct e100_serial *info) transmit_chars(info); } - static _INLINE_ void receive_chars(struct e100_serial *info) { @@ -1138,79 +1239,128 @@ receive_chars(struct e100_serial *info) /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ + // ? *info->iclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - if(!tty) /* something wrong... */ + if (!tty) /* something wrong... */ return; descr = &info->rec_descr; - + /* find out how many bytes were read */ /* if the eop bit was not set, all data has been received */ - if(!(descr->status & d_eop)) { + if (!(descr->status & d_eop)) { recvl = descr->sw_len; } else { /* otherwise we find the amount of data received here */ recvl = descr->hw_len; } - if(recvl) { - unsigned char *buf; - struct async_icount *icount; - icount = &info->icount; + /* read the status register so we can detect errors, + * but we can't really do anything about those errors + * anyway, since we have the DMA in "force eop at error" mode + * the fault characters are not in the buffer anyway. + */ - /* update stats */ - icount->rx += recvl; + rstat = info->port[REG_STATUS]; - /* read the status register so we can detect errors */ - rstat = info->port[REG_STATUS]; + if ((rstat & SER_ERROR_MASK) != 0) { + unsigned char data; + /* if we got an error, we must reset it by reading the + * data_in field + */ + data = info->port[REG_DATA]; + PROCSTAT(ser_stat[info->line].errors_cnt++); + DEBUG_LOG(info->line, " #dERR: s d 0x%04X\n", + ((rstat & SER_ERROR_MASK) << 8) | data); + /* Only handle the saved error code, that indicates that we got + * the last character of a break that looks like it's ok, but + * is not + */ - if(rstat & (IO_MASK(R_SERIAL0_STATUS, overrun) | - IO_MASK(R_SERIAL0_STATUS, par_err) | - IO_MASK(R_SERIAL0_STATUS, framing_err))) { - /* if we got an error, we must reset it by reading the - * data_in field + if (info->errorcode == 0) { + *tty->flip.flag_buf_ptr = TTY_NORMAL; + } else { + unsigned char data; + data = info->port[REG_DATA]; + if (info->errorcode & ERRCODE_INSERT) { + unsigned char *currbuf; + /* Get the current buffer */ + if (tty->flip.buf_num) { + currbuf = tty->flip.char_buf + TTY_FLIPBUF_SIZE; + } else { + currbuf = tty->flip.char_buf; + } + /* We should insert a character in the buffer! */ + if (recvl == 0) { + recvl = 1; + DEBUG_LOG(info->line, "insert to %lu\n", recvl); + } else { + /* Move stuff around.. */ + DEBUG_LOG(info->line, "#insert to %lu!\n", recvl); + if (recvl < TTY_FLIPBUF_SIZE) { + int i; + /* Move the data 1 step right */ + i = recvl; + while (i) { + currbuf[i] = currbuf[i-1]; + i--; + } + recvl++; + } else { + /* We can't move it all! Skip break! */ + /* TODO: Handle full buffer? */ + DEBUG_LOG(info->line, "#BRK skipped! %lu!\n", recvl); + info->errorcode = 0; + } + } + } + + PROCSTAT(ser_stat[info->line].errors_cnt++); + DEBUG_LOG(info->line, " #bERR: s d 0x%04X\n", + ((rstat & SER_ERROR_MASK) << 8) | data); + *tty->flip.flag_buf_ptr = (info->errorcode & 0xFF); + info->errorcode = 0; +#if 0 + printk("SERERR: 0x%02X data: 0x%02X\n", rstat & SER_ERROR_MASK, data); +#endif + /* we only ever write errors into the first byte in + * the flip flag buffer, so we dont have to clear it + * all every time */ - (void)info->port[REG_DATA]; } - - /* we only ever write errors into the first byte in the flip - * flag buffer, so we dont have to clear it all every time - */ + } - if(rstat & 0x04) { - icount->parity++; - *tty->flip.flag_buf_ptr = TTY_PARITY; - } else if(rstat & 0x08) { - icount->overrun++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } else if(rstat & 0x02) { - icount->frame++; - *tty->flip.flag_buf_ptr = TTY_FRAME; - } else - *tty->flip.flag_buf_ptr = 0; + DEBUG_LOG(info->line, "recvl %lu\n", recvl); + + if (recvl) { + unsigned char *buf; + struct async_icount *icount = &info->icount; + + /* update stats */ + icount->rx += recvl; /* use the flip buffer next in turn to restart DMA into */ - + if (tty->flip.buf_num) { buf = tty->flip.char_buf; } else { buf = tty->flip.char_buf + TTY_FLIPBUF_SIZE; } - if(buf == phys_to_virt(descr->buf)) { + if (buf == phys_to_virt(descr->buf)) { printk("ttyS%d flip-buffer overrun!\n", info->line); icount->overrun++; *tty->flip.flag_buf_ptr = TTY_OVERRUN; /* restart old buffer */ } else { descr->buf = virt_to_phys(buf); - + /* schedule or push a flip of the buffer */ - + info->tty->flip.count = recvl; #if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ @@ -1221,9 +1371,9 @@ receive_chars(struct e100_serial *info) #endif } } - + /* restart the receiving dma */ - + descr->sw_len = TTY_FLIPBUF_SIZE; descr->ctrl = d_int | d_eol | d_eop; descr->hw_len = 0; @@ -1236,6 +1386,10 @@ receive_chars(struct e100_serial *info) e100_enable_serial_data_irq(info); #endif /* input dma should be running now */ + + /* unthrottle if we have throttled */ + if (E100_RTS_GET(info)) + tty->driver.unthrottle(info->tty); } static void @@ -1253,8 +1407,8 @@ start_receive(struct e100_serial *info) /* reset the input dma channel to be sure it works */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); descr = &info->rec_descr; @@ -1270,7 +1424,10 @@ start_receive(struct e100_serial *info) *info->ifirstadr = virt_to_phys(descr); *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); - + +#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST + start_flush_timer(); +#endif } @@ -1313,12 +1470,12 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ - for(i = 0; i < NR_PORTS; i++) { + for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; if (!info->uses_dma) continue; /* check for dma_descr (dont need to check for dma_eop in output dma for serial */ - if(ireg & info->irq) { + if (ireg & info->irq) { /* we can send a new dma bunch. make it so. */ transmit_chars(info); } @@ -1352,12 +1509,12 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ - for(i = 0; i < NR_PORTS; i++) { + for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; if (!info->uses_dma) continue; /* check for both dma_eop and dma_descr for the input dma channel */ - if(ireg & ((info->irq << 2) | (info->irq << 3))) { + if (ireg & ((info->irq << 2) | (info->irq << 3))) { /* we have received something */ receive_chars(info); } @@ -1367,17 +1524,156 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) } } +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static int serial_fast_timer_started = 0; +static int serial_fast_timer_expired = 0; +static void flush_timeout_function(unsigned long data); +#define START_FLUSH_FAST_TIMER(info, string) {\ + unsigned long timer_flags; \ + save_flags(timer_flags); \ + cli(); \ + TIMERD(DEBUG_LOG(info->line, "start_timer? %i ", info->line)); \ + if (fast_timers[info->line].function == NULL) { \ + serial_fast_timer_started++; \ + TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \ + TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \ + start_one_shot_timer(&fast_timers[info->line], \ + flush_timeout_function, \ + (unsigned long)info, \ + info->char_time_usec*4, \ + string); \ + } \ + else { \ + /* DEBUG_LOG(info->line, " ## timer %i running ##\n", info->line); */ \ + } \ + restore_flags(timer_flags); \ +} + +#else +#define START_FLUSH_FAST_TIMER(info, string) +#endif + +void _INLINE_ check_flush_timeout(struct e100_serial *info) +{ + unsigned char rstat; + unsigned int magic; + + if (0 /*info->tty->processing_flip*/) { + if (!E100_RTS_GET(info)) { + int left = (*info->ihwswadr >> 16) - (*info->istatusadr & 0x3F); + + if (left < TTY_THROTTLE_LIMIT) + info->tty->driver.throttle(info->tty); + } + + PROCSTAT(ser_stat[info->line].processing_flip++); + START_FLUSH_FAST_TIMER(info, "flip"); + return; + } + + /* We check data_avail bit to determine if data has + * arrived since last time + */ + magic = info->fifo_magic; +#ifdef SERIAL_DEBUG_DATA + if (info->fifo_magic || info->fifo_didmagic) { + DEBUG_LOG(info->line, "timeout_int: did fifo_magic %03X\n", + (info->fifo_didmagic << 8) | info->fifo_magic); + } +#endif + rstat = info->port[REG_STATUS]; + /* error or datavail? */ + if (rstat & SER_ERROR_MASK) { + /* Some error has occured */ + /* If there has been valid data, + * an EOP interrupt will be made automatically. + * If no data, the normal ser_interrupt should be enabled + * and handle it. + * So do nothing! + */ + DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n", + rstat | (info->line << 8)); + return; + } + if (rstat & SER_DATA_AVAIL_MASK) { + /* Ok data, no error, count it */ + TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", + rstat | (info->line << 8))); + /* Read data to clear status flags */ + (void)info->port[REG_DATA]; + + magic++; + } + + if (magic != info->fifo_magic) { + info->fifo_magic = magic; + info->fifo_didmagic = 0; + START_FLUSH_FAST_TIMER(info, "magic"); + } else { + /* hit the timeout, force an EOP for the input + * dma channel if we haven't already + */ + if (!info->fifo_didmagic && magic) { + info->fifo_didmagic = 1; + info->fifo_magic = 0; + PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); + DEBUG_LOG(info->line, "timeout EOP %i\n", info->line); + TIMERD(DEBUG_LOG(info->line, "timeout magic %i\n", magic)); + FORCE_EOP(info); + } + } +} /* check_flush_timeout */ + +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static void flush_timeout_function(unsigned long data) +{ + struct e100_serial *info = (struct e100_serial *)data; + fast_timers[info->line].function = NULL; + serial_fast_timer_expired++; + TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); + TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired)); + check_flush_timeout(info); +} + +#elif defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST) + +static void +timeout_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct e100_serial *info; + int i; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + { + const char *s = "What? timeout_interrupt in simulator??\n"; + SIMCOUT(s,strlen(s)); + } + return; +#endif + + /* acknowledge the timer1 irq */ + *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr); + PROCSTAT(fast_timer_ints++); + + for (i = 0; i < NR_PORTS; i++) { + info = rs_table + i; + if (info->uses_dma) + check_flush_timeout(info); + } +} /* timeout_interrupt */ + +#else + /* dma fifo/buffer timeout handler forces an end-of-packet for the dma input channel if no chars - have been received for CONFIG_ETRAX_RX_TIMEOUT_TICKS/100 s. + have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s. If CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is configured then this handler is instead run at 15360 Hz. */ -#ifndef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST -static int timeout_divider = 0; -#endif - static struct timer_list flush_timer; static void @@ -1391,9 +1687,9 @@ timed_flush_handler(unsigned long ptr) return; #endif - for(i = 0; i < NR_PORTS; i++) { + for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if(!info->enabled || !(info->flags & ASYNC_INITIALIZED)) + if (!info->enabled || !(info->flags & ASYNC_INITIALIZED)) continue; /* istatusadr (bit 6-0) hold number of bytes in fifo @@ -1402,33 +1698,32 @@ timed_flush_handler(unsigned long ptr) */ magic = (*info->istatusadr & 0x3f); - magic += ((*info->ihwswadr&0xffff ) - (*info->ihwswadr >> 16)); + magic += ((*info->ihwswadr & 0xffff) - (*info->ihwswadr >> 16)); /* if magic is equal to fifo_magic (magic in previous * timeout_interrupt) then no new data has arrived since last * interrupt and we'll force eop to flush fifo+dma buffers */ - if(magic != info->fifo_magic) { + if (magic != info->fifo_magic) { info->fifo_magic = magic; info->fifo_didmagic = 0; } else { /* hit the timeout, force an EOP for the input * dma channel if we haven't already */ - if(!info->fifo_didmagic && magic) { + if (!info->fifo_didmagic && magic) { info->fifo_didmagic = 1; info->fifo_magic = 0; - *R_SET_EOP = 1U << info->iseteop; + FORCE_EOP(info); } } } /* restart flush timer */ - - mod_timer(&flush_timer, jiffies + MAX_FLUSH_TIME); + mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); } - +#endif #ifdef SERIAL_HANDLE_EARLY_ERRORS @@ -1439,48 +1734,190 @@ timed_flush_handler(unsigned long ptr) * interrupts off. */ +/* +BREAK handling on ETRAX 100: +ETRAX will generate interrupt although there is no stop bit between the +characters. + +Depending on how long the break sequence is, the end of the breaksequence +will look differently: +| indicates start/end of a character. + +B= Break character (0x00) with framing error. +E= Error byte with parity error received after B characters. +F= "Faked" valid byte received immediatly after B characters. +V= Valid byte + +1. + B BL ___________________________ V +.._|__________|__________| |valid data | + +Multiple frame errors with data == 0x00 (B), +the timing matches up "perfectly" so no extra ending char is detected. +The RXD pin is 1 in the last interrupt, in that case +we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really +know if another byte will come and this really is case 2. below +(e.g F=0xFF or 0xFE) +If RXD pin is 0 we can expect another character (see 2. below). + + +2. + + B B E or F__________________..__ V +.._|__________|__________|______ | |valid data + "valid" or + parity error + +Multiple frame errors with data == 0x00 (B), +but the part of the break trigs is interpreted as a start bit (and possibly +som 0 bits followed by a number of 1 bits and a stop bit). +Depending on parity settings etc. this last character can be either +a fake "valid" char (F) or have a parity error (E). + +If the character is valid it will be put in the buffer, +we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt +will set the flags so the tty will handle it, +if it's an error byte it will not be put in the buffer +and we set info->errorcode = ERRCODE_INSERT_BREAK. + +To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp +of the last faulty char (B) and compares it with the current time: +If the time elapsed time is less then 2*char_time_usec we will assume +it's a faked F char and not a Valid char and set +info->errorcode = ERRCODE_SET_BREAK. + +Flaws in the above solution: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We use the timer to distinguish a F character from a V character, +if a V character is to close after the break we might make the wrong decision. + +TODO: The break will be delayed until an F or V character is received. + +*/ + +static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) +{ + unsigned char rstat = info->port[REG_STATUS]; + +#ifdef SERIAL_DEBUG_INTR + printk("Interrupt from serport %d\n", i); +#endif +/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ + if (rstat & SER_ERROR_MASK) { + unsigned char data; + info->last_rx_active_usec = GET_JIFFIES_USEC(); + info->last_rx_active = jiffies; + /* if we got an error, we must reset it by + * reading the data_in field + */ + data = info->port[REG_DATA]; + + if ((data == 0x00) && (rstat & SER_FRAMING_ERR_MASK)) { + /* Most likely a break, but we get + * interrupts over and over again. + */ + + if (info->break_detected_cnt == 0) { + DEBUG_LOG(info->line, "#BRK start\n", 0); + } + if (rstat & SER_RXD_MASK) { + /* The RX pin is high now, so the break + * must be over, but.... + * we can't really know if we will get another + * last byte ending the break or not. + * And we don't know if the byte (if any) will + * have an error or look valid. + */ + DEBUG_LOG(info->line, "# BL BRK\n", 0); + info->errorcode = ERRCODE_INSERT_BREAK; + } + info->break_detected_cnt++; + } else { + /* Error doesn't look like a break, + * but could be end of a break + */ + if (info->break_detected_cnt) { + DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); + info->errorcode = ERRCODE_INSERT_BREAK; + } + info->break_detected_cnt = 0; + DEBUG_LOG(info->line, "#iERR s d %04X\n", + ((rstat & SER_ERROR_MASK) << 8) | data); + } + PROCSTAT(ser_stat[info->line].early_errors_cnt++); + +#if 0 + /* Reset DMA before starting */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); +#endif + } else { /* it was a valid byte, now let the dma do the rest */ + unsigned char data; + unsigned long curr_time_u = GET_JIFFIES_USEC(); + unsigned long curr_time = jiffies; + + if (info->break_detected_cnt) { + /* Detect if this character is a new + * valid char or the last char in a + * break sequence: + * If LSBits are 0 and MSBits are high + * AND the time is close to the + * previous interrupt we should discard + * it. + */ + long elapsed_usec = + (curr_time - info->last_rx_active) * (1000000/HZ) + + curr_time_u - info->last_rx_active_usec; + if (elapsed_usec<2*info->char_time_usec) { + DEBUG_LOG(info->line, "FBRK %i\n", info->line); + /* Report as BREAK (error) and + * let receive_chars handle it + */ + info->errorcode = ERRCODE_SET_BREAK; + } else { + DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line); + } + DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt); + } + /* Reset data_avail by + * reading the data_in field + */ + data = info->port[REG_DATA]; + info->break_detected_cnt = 0; + info->fifo_magic++; /* Count received chars */ +#ifdef SERIAL_DEBUG_INTR + printk("** OK, disabling ser_interupts\n"); +#endif + PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); + DEBUG_LOG(info->line, " ser_int OK %03X\n", + (info->line << 8) | data); + e100_disable_serial_data_irq(info); + } + + /* restart the DMA never hurts */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); + START_FLUSH_FAST_TIMER(info, "ser_int"); +} /* handle_ser_interrupt */ + static void ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct e100_serial *info; int i; - unsigned char rstat; - for(i = 0; i < NR_PORTS; i++) { + for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; + if (!info->uses_dma) continue; - rstat = info->port[REG_STATUS]; - - if(*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) { /* This line caused the irq */ -#ifdef SERIAL_DEBUG_INTR - printk("Interrupt from serport %d\n", i); -#endif - if(rstat & 0x0e) { - /* FIXME: This is weird, but if this delay is - * not present then irmaflash does not work... - */ - udelay(2300); - /* if we got an error, we must reset it by - * reading the data_in field - */ - (void)info->port[REG_DATA]; - - PROCSTAT(early_errors_cnt[info->line]++); - - /* restart the DMA */ - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); - } - else { /* it was a valid byte, now let the dma do the rest */ -#ifdef SERIAL_DEBUG_INTR - printk("** OK, disabling ser_interrupts\n"); -#endif - e100_disable_serial_data_irq(info); - } + /* Which line caused the irq? */ + if (*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) { + handle_ser_interrupt(info); } } -} +} /* ser_interrupt */ #endif /* @@ -1573,7 +2010,7 @@ startup(struct e100_serial * info) printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit.buf); #endif - if(info->tty) { + if (info->tty) { /* clear the tty flip flag buffer since we will not * be using it (we only use the first byte..) @@ -1612,11 +2049,11 @@ startup(struct e100_serial * info) *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); /* wait until reset cycle is complete */ - while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); - while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); *info->iclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | @@ -1697,6 +2134,7 @@ shutdown(struct e100_serial * info) *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + info->uses_dma = 0; #endif /* CONFIG_SVINTO_SIM */ @@ -1740,7 +2178,7 @@ change_speed(struct e100_serial *info) /* first some safety checks */ - if(!info->tty || !info->tty->termios) + if (!info->tty || !info->tty->termios) return; if (!info->port) return; @@ -1807,9 +2245,10 @@ change_speed(struct e100_serial *info) info->port[REG_TR_CTRL] = info->tx_ctrl; info->port[REG_REC_CTRL] = info->rx_ctrl; *((unsigned long *)&info->port[REG_XOFF]) = 0; +#endif /* !CONFIG_SVINTO_SIM */ -#endif /* CONFIG_SVINTO_SIM */ -} + update_char_time(info); +} /* change_speed */ /* start transmitting chars NOW */ @@ -1852,7 +2291,7 @@ rs_write(struct tty_struct * tty, int from_user, return 0; #ifdef SERIAL_DEBUG_DATA - if(info->line == SERIAL_DEBUG_LINE) + if (info->line == SERIAL_DEBUG_LINE) printk("rs_write (%d), status %d\n", count, info->port[REG_STATUS]); #endif @@ -1871,7 +2310,7 @@ rs_write(struct tty_struct * tty, int from_user, * atomic operation... this could perhaps be avoided by more clever * design. */ - if(from_user) { + if (from_user) { down(&tmp_buf_sem); while (1) { int c1; @@ -1906,7 +2345,7 @@ rs_write(struct tty_struct * tty, int from_user, up(&tmp_buf_sem); } else { cli(); - while(1) { + while (1) { c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); @@ -1931,10 +2370,10 @@ rs_write(struct tty_struct * tty, int from_user, * the IRQ's are not running anyway for this port. */ - if(info->xmit.head != info->xmit.tail - && !tty->stopped && - !tty->hw_stopped && - !info->tr_running) { + if (info->xmit.head != info->xmit.tail + && !tty->stopped && + !tty->hw_stopped && + !info->tr_running) { start_transmit(info); } @@ -2107,11 +2546,11 @@ set_serial_info(struct e100_serial * info, old_info = *info; - if(!capable(CAP_SYS_ADMIN)) { - if((new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (info->flags & ~ASYNC_USR_MASK))) + if (!capable(CAP_SYS_ADMIN)) { + if ((new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) return -EPERM; info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); @@ -2136,7 +2575,7 @@ set_serial_info(struct e100_serial * info, #endif check_and_exit: - if(info->flags & ASYNC_INITIALIZED) { + if (info->flags & ASYNC_INITIALIZED) { change_speed(info); } else retval = startup(info); @@ -2156,16 +2595,18 @@ set_serial_info(struct e100_serial * info, static int get_lsr_info(struct e100_serial * info, unsigned int *value) { - unsigned int result; - -#ifdef CONFIG_SVINTO_SIM - /* Always open. */ - result = TIOCSER_TEMT; -#else - if (*info->ostatusadr & 0x007F) /* something in fifo */ + unsigned int result = TIOCSER_TEMT; +#ifndef CONFIG_SVINTO_SIM + unsigned long curr_time = jiffies; + unsigned long curr_time_usec = GET_JIFFIES_USEC(); + unsigned long elapsed_usec = + (curr_time - info->last_tx_active) * 1000000/HZ + + curr_time_usec - info->last_tx_active_usec; + + if (info->xmit.head != info->xmit.tail || + elapsed_usec < 2*info->char_time_usec) { result = 0; - else - result = TIOCSER_TEMT; + } #endif if (copy_to_user(value, &result, sizeof(int))) @@ -2178,10 +2619,9 @@ struct state_str { int state; const char *str; - }; -const struct state_str control_state_str[]={ +const struct state_str control_state_str[] = { {TIOCM_DTR, "DTR" }, {TIOCM_RTS, "RTS"}, {TIOCM_ST, "ST?" }, @@ -2612,20 +3052,31 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) { unsigned long orig_jiffies; struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long curr_time = jiffies; + unsigned long curr_time_usec = GET_JIFFIES_USEC(); + long elapsed_usec = + (curr_time - info->last_tx_active) * (1000000/HZ) + + curr_time_usec - info->last_tx_active_usec; /* * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k) */ orig_jiffies = jiffies; - while(info->xmit.head != info->xmit.tail || /* More in send queue */ - (*info->ostatusadr & 0x007f)) { /* more in FIFO */ + while (info->xmit.head != info->xmit.tail || /* More in send queue */ + (*info->ostatusadr & 0x007f) || /* more in FIFO */ + (elapsed_usec < 2*info->char_time_usec)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; + curr_time = jiffies; + curr_time_usec = GET_JIFFIES_USEC(); + elapsed_usec = + (curr_time - info->last_tx_active) * (1000000/HZ) + + curr_time_usec - info->last_tx_active_usec; } set_current_state(TASK_RUNNING); } @@ -2809,10 +3260,11 @@ rs_open(struct tty_struct *tty, struct file * filp) return -ENODEV; /* find the corresponding e100_serial struct in the table */ - info = rs_table + line; - /* dont allow the opening of ports that are not enabled in the HW config */ - if (!info->enabled) return -ENODEV; + + /* don't allow the opening of ports that are not enabled in the HW config */ + if (!info->enabled) + return -ENODEV; #ifdef SERIAL_DEBUG_OPEN printk("[%d] rs_open %s%d, count = %d\n", current->pid, @@ -2923,20 +3375,20 @@ static inline int line_info(char *buf, struct e100_serial *info) ret += sprintf(buf+ret, " baud:%d", info->baud); - ret += sprintf(buf+ret, " tx:%d rx:%d", - info->icount.tx, info->icount.rx); + ret += sprintf(buf+ret, " tx:%lu rx:%lu", + info->icount.tx, info->icount.rx); if (info->icount.frame) - ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + ret += sprintf(buf+ret, " fe:%lu", info->icount.frame); if (info->icount.parity) - ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + ret += sprintf(buf+ret, " pe:%lu", info->icount.parity); if (info->icount.brk) - ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + ret += sprintf(buf+ret, " brk:%lu", info->icount.brk); if (info->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + ret += sprintf(buf+ret, " oe:%lu", info->icount.overrun); /* * Last thing is the RS-232 status lines @@ -2996,9 +3448,11 @@ rs_init(void) /* Setup the timed flush handler system */ +#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) && !defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST) init_timer(&flush_timer); flush_timer.function = timed_flush_handler; - mod_timer(&flush_timer, jiffies + MAX_FLUSH_TIME); + mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); +#endif /* Initialize the tty_driver structure */ @@ -3089,6 +3543,7 @@ rs_init(void) init_waitqueue_head(&info->close_wait); info->xmit.buf = 0; info->xmit.tail = info->xmit.head = 0; + if (info->enabled) { printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n", serial_driver.name, info->line, (unsigned int)info->port); @@ -3099,38 +3554,38 @@ rs_init(void) /* Not needed in simulator. May only complicate stuff. */ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ #ifdef CONFIG_ETRAX_SERIAL_PORT0 - if(request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL)) + if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL)) panic("irq22"); - if(request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL)) + if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL)) panic("irq23"); #endif #ifdef SERIAL_HANDLE_EARLY_ERRORS - if(request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) + if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) panic("irq8"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT1 - if(request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) + if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) panic("irq24"); - if(request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) + if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) panic("irq25"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT2 /* DMA Shared with par0 (and SCSI0 and ATA) */ - if(request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) + if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) panic("irq18"); - if(request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) + if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) panic("irq19"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT3 /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */ - if(request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) + if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) panic("irq20"); - if(request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) + if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) panic("irq21"); #endif + #ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST - /* TODO: a timeout_interrupt needs to be written that calls timeout_handler */ - if(request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ, + if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ | SA_INTERRUPT, "fast serial dma timeout", NULL)) { printk("err: timer1 irq\n"); } diff --git a/arch/cris/drivers/serial.h b/arch/cris/drivers/serial.h index 0b49ee2e6fbc..119f2fb85e84 100644 --- a/arch/cris/drivers/serial.h +++ b/arch/cris/drivers/serial.h @@ -87,6 +87,15 @@ struct e100_serial { struct wait_queue *close_wait; #endif + unsigned long char_time_usec; /* The time for 1 char, in usecs */ + unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */ + unsigned long last_tx_active; /* Last tx time in jiffies */ + unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */ + unsigned long last_rx_active; /* Last rx time in jiffies */ + + int break_detected_cnt; + int errorcode; + #ifdef CONFIG_RS485 struct rs485_control rs485; /* RS-485 support */ #endif diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile index 4edd9cabfc38..be2063e2fa53 100644 --- a/arch/cris/kernel/Makefile +++ b/arch/cris/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.8 2001/10/01 14:44:07 bjornw Exp $ +# $Id: Makefile,v 1.9 2001/10/22 13:10:21 pkj Exp $ # # Makefile for the linux kernel. # @@ -16,6 +16,9 @@ all: kernel.o head.o O_TARGET := kernel.o + +export-objs := ksyms.o + obj-y := process.o signal.o entry.o traps.o irq.o \ ptrace.o setup.o time.o sys_cris.o shadows.o \ debugport.o semaphore.o diff --git a/arch/cris/kernel/entry.S b/arch/cris/kernel/entry.S index 69b27be3307b..a33a1c12afb8 100644 --- a/arch/cris/kernel/entry.S +++ b/arch/cris/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.34 2001/10/01 14:45:03 bjornw Exp $ +/* $Id: entry.S,v 1.35 2001/10/30 17:10:15 bjornw Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,9 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.35 2001/10/30 17:10:15 bjornw + * Add some syscalls + * * Revision 1.34 2001/10/01 14:45:03 bjornw * Removed underscores and added register prefixes * @@ -981,6 +984,9 @@ sys_call_table: .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ + .long SYMBOL_NAME(sys_ni_syscall) /* Reserved for Security */ + .long SYMBOL_NAME(sys_gettid) + .long SYMBOL_NAME(sys_readahead) /* 225 */ /* * NOTE!! This doesn't have to be exact - we just have @@ -989,7 +995,7 @@ sys_call_table: * been shrunk every time we add a new system call. */ - .rept NR_syscalls-222 + .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) .endr diff --git a/arch/cris/kernel/head.S b/arch/cris/kernel/head.S index b98df4a8a1bd..3eef976e5613 100644 --- a/arch/cris/kernel/head.S +++ b/arch/cris/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.40 2001/10/03 14:59:57 pkj Exp $ +/* $Id: head.S,v 1.41 2001/10/29 14:55:58 pkj Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,9 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.41 2001/10/29 14:55:58 pkj + * Corrected pa$r0 to par0. + * * Revision 1.40 2001/10/03 14:59:57 pkj * Added support for resetting the Bluetooth hardware. * @@ -520,7 +523,7 @@ _start_it: moveq 0,$r0 #if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \ && !defined(CONFIG_DMA_MEMCPY) - ; DMA channels 6 and 7 to se$r0, kgdb doesnt want DMA + ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \ | IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0 #endif @@ -554,7 +557,7 @@ _start_it: #endif #if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) ; parport 0 enabled using DMA 2/3 - or.w IO_STATE (R_GEN_CONFIG, pa$r0, select),$r0 + or.w IO_STATE (R_GEN_CONFIG, par0, select),$r0 #endif #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) ; parport 1 enabled using DMA 4/5 diff --git a/arch/cris/kernel/kgdb.c b/arch/cris/kernel/kgdb.c index abf67f4284d0..e5c6428d7ca8 100644 --- a/arch/cris/kernel/kgdb.c +++ b/arch/cris/kernel/kgdb.c @@ -18,6 +18,9 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! Revision 1.6 2001/10/09 13:10:03 matsfg +*! Added $ on registers and removed some underscores +*! *! Revision 1.5 2001/04/17 13:58:39 orjanf *! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. *! @@ -52,7 +55,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.5 2001/04/17 13:58:39 orjanf Exp $ +*! $Id: kgdb.c,v 1.6 2001/10/09 13:10:03 matsfg Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -1343,90 +1346,90 @@ kill_restart () void kgdb_handle_breakpoint(void); asm (" - .global _kgdb_handle_breakpoint -_kgdb_handle_breakpoint: + .global kgdb_handle_breakpoint +kgdb_handle_breakpoint: ;; ;; Response to the break-instruction ;; ;; Create a register image of the caller ;; - move dccr,[_reg+0x5E] ; Save the flags in DCCR before disable interrupts + move $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts di ; Disable interrupts - move.d r0,[_reg] ; Save R0 - move.d r1,[_reg+0x04] ; Save R1 - move.d r2,[_reg+0x08] ; Save R2 - move.d r3,[_reg+0x0C] ; Save R3 - move.d r4,[_reg+0x10] ; Save R4 - move.d r5,[_reg+0x14] ; Save R5 - move.d r6,[_reg+0x18] ; Save R6 - move.d r7,[_reg+0x1C] ; Save R7 - move.d r8,[_reg+0x20] ; Save R8 - move.d r9,[_reg+0x24] ; Save R9 - move.d r10,[_reg+0x28] ; Save R10 - move.d r11,[_reg+0x2C] ; Save R11 - move.d r12,[_reg+0x30] ; Save R12 - move.d r13,[_reg+0x34] ; Save R13 - move.d sp,[_reg+0x38] ; Save SP (R14) + move.d $r0,[reg] ; Save R0 + move.d $r1,[reg+0x04] ; Save R1 + move.d $r2,[reg+0x08] ; Save R2 + move.d $r3,[reg+0x0C] ; Save R3 + move.d $r4,[reg+0x10] ; Save R4 + move.d $r5,[reg+0x14] ; Save R5 + move.d $r6,[reg+0x18] ; Save R6 + move.d $r7,[reg+0x1C] ; Save R7 + move.d $r8,[reg+0x20] ; Save R8 + move.d $r9,[reg+0x24] ; Save R9 + move.d $r10,[reg+0x28] ; Save R10 + move.d $r11,[reg+0x2C] ; Save R11 + move.d $r12,[reg+0x30] ; Save R12 + move.d $r13,[reg+0x34] ; Save R13 + move.d $sp,[reg+0x38] ; Save SP (R14) ;; Due to the old assembler-versions BRP might not be recognized - .word 0xE670 ; move brp,r0 - subq 2,r0 ; Set to address of previous instruction. - move.d r0,[_reg+0x3c] ; Save the address in PC (R15) - clear.b [_reg+0x40] ; Clear P0 - move vr,[_reg+0x41] ; Save special register P1 - clear.w [_reg+0x42] ; Clear P4 - move ccr,[_reg+0x44] ; Save special register CCR - move mof,[_reg+0x46] ; P7 - clear.d [_reg+0x4A] ; Clear P8 - move ibr,[_reg+0x4E] ; P9, - move irp,[_reg+0x52] ; P10, - move srp,[_reg+0x56] ; P11, - move dtp0,[_reg+0x5A] ; P12, register BAR, assembler might not know BAR + .word 0xE670 ; move brp,$r0 + subq 2,$r0 ; Set to address of previous instruction. + move.d $r0,[reg+0x3c] ; Save the address in PC (R15) + clear.b [reg+0x40] ; Clear P0 + move $vr,[reg+0x41] ; Save special register P1 + clear.w [reg+0x42] ; Clear P4 + move $ccr,[reg+0x44] ; Save special register CCR + move $mof,[reg+0x46] ; P7 + clear.d [reg+0x4A] ; Clear P8 + move $ibr,[reg+0x4E] ; P9, + move $irp,[reg+0x52] ; P10, + move $srp,[reg+0x56] ; P11, + move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR ; P13, register DCCR already saved ;; Due to the old assembler-versions BRP might not be recognized .word 0xE670 ; move brp,r0 ;; Static (compiled) breakpoints must return to the next instruction in order ;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction ;; in order to execute it when execution is continued. - test.b [_is_dyn_brkp] ; Is this a dynamic breakpoint? + test.b [is_dyn_brkp] ; Is this a dynamic breakpoint? beq is_static ; No, a static breakpoint nop - subq 2,r0 ; rerun the instruction the break replaced + subq 2,$r0 ; rerun the instruction the break replaced is_static: - moveq 1,r1 - move.b r1,[_is_dyn_brkp] ; Set the state variable to dynamic breakpoint - move.d r0,[_reg+0x62] ; Save the return address in BRP - move usp,[_reg+0x66] ; USP + moveq 1,$r1 + move.b $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint + move.d $r0,[reg+0x62] ; Save the return address in BRP + move $usp,[reg+0x66] ; USP ;; ;; Handle the communication ;; - move.d _internal_stack+1020,sp ; Use the internal stack which grows upward - moveq 5,r10 ; SIGTRAP - jsr _handle_exception ; Interactive routine + move.d internal_stack+1020,$sp ; Use the internal stack which grows upward + moveq 5,$r10 ; SIGTRAP + jsr handle_exception ; Interactive routine ;; ;; Return to the caller ;; - move.d [_reg],r0 ; Restore R0 - move.d [_reg+0x04],r1 ; Restore R1 - move.d [_reg+0x08],r2 ; Restore R2 - move.d [_reg+0x0C],r3 ; Restore R3 - move.d [_reg+0x10],r4 ; Restore R4 - move.d [_reg+0x14],r5 ; Restore R5 - move.d [_reg+0x18],r6 ; Restore R6 - move.d [_reg+0x1C],r7 ; Restore R7 - move.d [_reg+0x20],r8 ; Restore R8 - move.d [_reg+0x24],r9 ; Restore R9 - move.d [_reg+0x28],r10 ; Restore R10 - move.d [_reg+0x2C],r11 ; Restore R11 - move.d [_reg+0x30],r12 ; Restore R12 - move.d [_reg+0x34],r13 ; Restore R13 + move.d [reg],$r0 ; Restore R0 + move.d [reg+0x04],$r1 ; Restore R1 + move.d [reg+0x08],$r2 ; Restore R2 + move.d [reg+0x0C],$r3 ; Restore R3 + move.d [reg+0x10],$r4 ; Restore R4 + move.d [reg+0x14],$r5 ; Restore R5 + move.d [reg+0x18],$r6 ; Restore R6 + move.d [reg+0x1C],$r7 ; Restore R7 + move.d [reg+0x20],$r8 ; Restore R8 + move.d [reg+0x24],$r9 ; Restore R9 + move.d [reg+0x28],$r10 ; Restore R10 + move.d [reg+0x2C],$r11 ; Restore R11 + move.d [reg+0x30],$r12 ; Restore R12 + move.d [reg+0x34],$r13 ; Restore R13 ;; ;; FIXME: Which registers should be restored? ;; - move.d [_reg+0x38],sp ; Restore SP (R14) - move [_reg+0x56],srp ; Restore the subroutine return pointer. - move [_reg+0x5E],dccr ; Restore DCCR - move [_reg+0x66],usp ; Restore USP - jump [_reg+0x62] ; A jump to the content in register BRP works. + move.d [reg+0x38],$sp ; Restore SP (R14) + move [reg+0x56],$srp ; Restore the subroutine return pointer. + move [reg+0x5E],$dccr ; Restore DCCR + move [reg+0x66],$usp ; Restore USP + jump [reg+0x62] ; A jump to the content in register BRP works. nop ; "); @@ -1440,85 +1443,85 @@ is_static: void kgdb_handle_serial(void); asm (" - .global _kgdb_handle_serial -_kgdb_handle_serial: + .global kgdb_handle_serial +kgdb_handle_serial: ;; ;; Response to a serial interrupt ;; - move dccr,[_reg+0x5E] ; Save the flags in DCCR + move $dccr,[reg+0x5E] ; Save the flags in DCCR di ; Disable interrupts - move.d r0,[_reg] ; Save R0 - move.d r1,[_reg+0x04] ; Save R1 - move.d r2,[_reg+0x08] ; Save R2 - move.d r3,[_reg+0x0C] ; Save R3 - move.d r4,[_reg+0x10] ; Save R4 - move.d r5,[_reg+0x14] ; Save R5 - move.d r6,[_reg+0x18] ; Save R6 - move.d r7,[_reg+0x1C] ; Save R7 - move.d r8,[_reg+0x20] ; Save R8 - move.d r9,[_reg+0x24] ; Save R9 - move.d r10,[_reg+0x28] ; Save R10 - move.d r11,[_reg+0x2C] ; Save R11 - move.d r12,[_reg+0x30] ; Save R12 - move.d r13,[_reg+0x34] ; Save R13 - move.d sp,[_reg+0x38] ; Save SP (R14) - move irp,[_reg+0x3c] ; Save the address in PC (R15) - clear.b [_reg+0x40] ; Clear P0 - move vr,[_reg+0x41] ; Save special register P1, - clear.w [_reg+0x42] ; Clear P4 - move ccr,[_reg+0x44] ; Save special register CCR - move mof,[_reg+0x46] ; P7 - clear.d [_reg+0x4A] ; Clear P8 - move ibr,[_reg+0x4E] ; P9, - move irp,[_reg+0x52] ; P10, - move srp,[_reg+0x56] ; P11, - move dtp0,[_reg+0x5A] ; P12, register BAR, assembler might not know BAR + move.d $r0,[reg] ; Save R0 + move.d $r1,[reg+0x04] ; Save R1 + move.d $r2,[reg+0x08] ; Save R2 + move.d $r3,[reg+0x0C] ; Save R3 + move.d $r4,[reg+0x10] ; Save R4 + move.d $r5,[reg+0x14] ; Save R5 + move.d $r6,[reg+0x18] ; Save R6 + move.d $r7,[reg+0x1C] ; Save R7 + move.d $r8,[reg+0x20] ; Save R8 + move.d $r9,[reg+0x24] ; Save R9 + move.d $r10,[reg+0x28] ; Save R10 + move.d $r11,[reg+0x2C] ; Save R11 + move.d $r12,[reg+0x30] ; Save R12 + move.d $r13,[reg+0x34] ; Save R13 + move.d $sp,[reg+0x38] ; Save SP (R14) + move $irp,[reg+0x3c] ; Save the address in PC (R15) + clear.b [reg+0x40] ; Clear P0 + move $vr,[reg+0x41] ; Save special register P1, + clear.w [reg+0x42] ; Clear P4 + move $ccr,[reg+0x44] ; Save special register CCR + move $mof,[reg+0x46] ; P7 + clear.d [reg+0x4A] ; Clear P8 + move $ibr,[reg+0x4E] ; P9, + move $irp,[reg+0x52] ; P10, + move $srp,[reg+0x56] ; P11, + move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR ; P13, register DCCR already saved ;; Due to the old assembler-versions BRP might not be recognized .word 0xE670 ; move brp,r0 - move.d r0,[_reg+0x62] ; Save the return address in BRP - move usp,[_reg+0x66] ; USP + move.d $r0,[reg+0x62] ; Save the return address in BRP + move $usp,[reg+0x66] ; USP ;; get the serial character (from debugport.c) and check if its a ctrl-c - jsr _getDebugChar - cmp.b 3, r10 + jsr getDebugChar + cmp.b 3, $r10 bne goback nop ;; ;; Handle the communication ;; - move.d _internal_stack+1020,sp ; Use the internal stack - moveq 2,r10 ; SIGINT - jsr _handle_exception ; Interactive routine + move.d internal_stack+1020,$sp ; Use the internal stack + moveq 2,$r10 ; SIGINT + jsr handle_exception ; Interactive routine goback: ;; ;; Return to the caller ;; - move.d [_reg],r0 ; Restore R0 - move.d [_reg+0x04],r1 ; Restore R1 - move.d [_reg+0x08],r2 ; Restore R2 - move.d [_reg+0x0C],r3 ; Restore R3 - move.d [_reg+0x10],r4 ; Restore R4 - move.d [_reg+0x14],r5 ; Restore R5 - move.d [_reg+0x18],r6 ; Restore R6 - move.d [_reg+0x1C],r7 ; Restore R7 - move.d [_reg+0x20],r8 ; Restore R8 - move.d [_reg+0x24],r9 ; Restore R9 - move.d [_reg+0x28],r10 ; Restore R10 - move.d [_reg+0x2C],r11 ; Restore R11 - move.d [_reg+0x30],r12 ; Restore R12 - move.d [_reg+0x34],r13 ; Restore R13 + move.d [reg],$r0 ; Restore R0 + move.d [reg+0x04],$r1 ; Restore R1 + move.d [reg+0x08],$r2 ; Restore R2 + move.d [reg+0x0C],$r3 ; Restore R3 + move.d [reg+0x10],$r4 ; Restore R4 + move.d [reg+0x14],$r5 ; Restore R5 + move.d [reg+0x18],$r6 ; Restore R6 + move.d [reg+0x1C],$r7 ; Restore R7 + move.d [reg+0x20],$r8 ; Restore R8 + move.d [reg+0x24],$r9 ; Restore R9 + move.d [reg+0x28],$r10 ; Restore R10 + move.d [reg+0x2C],$r11 ; Restore R11 + move.d [reg+0x30],$r12 ; Restore R12 + move.d [reg+0x34],$r13 ; Restore R13 ;; ;; FIXME: Which registers should be restored? ;; - move.d [_reg+0x38],sp ; Restore SP (R14) - move [_reg+0x56],srp ; Restore the subroutine return pointer. - move [_reg+0x5E],dccr ; Restore DCCR - move [_reg+0x66],usp ; Restore USP + move.d [reg+0x38],$sp ; Restore SP (R14) + move [reg+0x56],$srp ; Restore the subroutine return pointer. + move [reg+0x5E],$dccr ; Restore DCCR + move [reg+0x66],$usp ; Restore USP reti ; Return from the interrupt routine nop "); diff --git a/arch/cris/kernel/ksyms.c b/arch/cris/kernel/ksyms.c index 22e2c8e30e69..aaf66ee05ec7 100644 --- a/arch/cris/kernel/ksyms.c +++ b/arch/cris/kernel/ksyms.c @@ -24,6 +24,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern unsigned long get_cmos_time(void); extern void __ashrdi3(void); +extern void iounmap(void *addr); /* platform dependent support */ @@ -45,6 +46,19 @@ EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(__ashrdi3); +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); + +/* export shadow registers for the CPU I/O pins */ + +EXPORT_SYMBOL(genconfig_shadow); +EXPORT_SYMBOL(port_pa_data_shadow); +EXPORT_SYMBOL(port_pa_dir_shadow); +EXPORT_SYMBOL(port_pb_data_shadow); +EXPORT_SYMBOL(port_pb_dir_shadow); +EXPORT_SYMBOL(port_pb_config_shadow); +EXPORT_SYMBOL(port_g_data_shadow); + /* other stuff */ EXPORT_SYMBOL(strncpy_from_user); diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c index 1f80b9baf8f5..82ee4579fd75 100644 --- a/arch/cris/kernel/process.c +++ b/arch/cris/kernel/process.c @@ -77,6 +77,7 @@ * setup. */ +static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c index 95f2d71f3358..2a7f45cc6e5b 100644 --- a/arch/cris/kernel/setup.c +++ b/arch/cris/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.21 2001/10/01 14:45:35 bjornw Exp $ +/* $Id: setup.c,v 1.22 2001/10/23 17:42:58 pkj Exp $ * * linux/arch/cris/kernel/setup.c * @@ -202,32 +202,58 @@ static struct cpu_info { } cpu_info[] = { /* The first four models will never ever run this code and are only here for display. */ - { "ETRAX 1", 0, 0 }, - { "ETRAX 2", 0, 0 }, - { "ETRAX 3", 0, HAS_TOKENRING }, - { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, - { "Unknown", 0, 0 }, - { "Unknown", 0, 0 }, - { "Unknown", 0, 0 }, - { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, - { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, + { "ETRAX 1", 0, 0 }, + { "ETRAX 2", 0, 0 }, + { "ETRAX 3", 0, HAS_TOKENRING }, + { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, - { "Unknown", 0, 0 }, + { "Unknown", 0, 0 } /* This entry MUST be the last */ }; /* - * BUFFER is PAGE_SIZE bytes long. + * get_cpuinfo - Get information on one CPU for use by the procfs. + * + * Prints info on the next CPU into buffer. Beware, doesn't check for + * buffer overflow. Current implementation of procfs assumes that the + * resulting data is <= 1K. + * + * BUFFER is PAGE_SIZE - 1K bytes long. + * + * Args: + * buffer -- you guessed it, the data buffer + * cpu_np -- Input: next cpu to get (start at 0). Output: Updated. + * + * Returns number of bytes written to buffer. */ -int get_cpuinfo(char *buffer) +int get_cpuinfo(char *buffer, unsigned *cpu_np) { int revision; + struct cpu_info *info; + unsigned n; /* read the version register in the CPU and print some stuff */ revision = rdvr(); + if (revision < 0 || revision >= sizeof cpu_info/sizeof *cpu_info) { + info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; + } else + info = &cpu_info[revision]; + + /* No SMP at the moment, so just toggle 0/1 */ + n = *cpu_np; + *cpu_np = 1; + if (n != 0) { + return (0); + } + return sprintf(buffer, "cpu\t\t: CRIS\n" "cpu revision\t: %d\n" @@ -244,16 +270,16 @@ int get_cpuinfo(char *buffer) "bogomips\t: %lu.%02lu\n", revision, - cpu_info[revision].model, - cpu_info[revision].cache, - cpu_info[revision].flags & HAS_FPU ? "yes" : "no", - cpu_info[revision].flags & HAS_MMU ? "yes" : "no", - cpu_info[revision].flags & HAS_MMU_BUG ? "yes" : "no", - cpu_info[revision].flags & HAS_ETHERNET100 ? "10/100" : "10", - cpu_info[revision].flags & HAS_TOKENRING ? "4/16 Mbps" : "no", - cpu_info[revision].flags & HAS_SCSI ? "yes" : "no", - cpu_info[revision].flags & HAS_ATA ? "yes" : "no", - cpu_info[revision].flags & HAS_USB ? "yes" : "no", + info->model, + info->cache, + info->flags & HAS_FPU ? "yes" : "no", + info->flags & HAS_MMU ? "yes" : "no", + info->flags & HAS_MMU_BUG ? "yes" : "no", + info->flags & HAS_ETHERNET100 ? "10/100" : "10", + info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", + info->flags & HAS_SCSI ? "yes" : "no", + info->flags & HAS_ATA ? "yes" : "no", + info->flags & HAS_USB ? "yes" : "no", (loops_per_jiffy * HZ + 500) / 500000, ((loops_per_jiffy * HZ + 500) / 5000) % 100); } diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c index 7ad89928df5f..00b8ff6e889a 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.8 2001/07/18 14:01:03 bjornw Exp $ +/* $Id: time.c,v 1.9 2001/10/25 10:26:37 johana Exp $ * * linux/arch/cris/kernel/time.c * @@ -51,6 +51,11 @@ static int have_rtc; /* used to remember if we have an RTC or not */ extern int setup_etrax_irq(int, struct irqaction *); +/* Lookup table to convert *R_TIMER0 to microseconds (us) + * Timer goes from TIMER0_DIV down to 1 meaning 0-10000us in step of approx 52us + */ +unsigned short cris_timer0_value_us[TIMER0_DIV+1]; + #define TICK_SIZE tick static unsigned long do_slow_gettimeoffset(void) @@ -380,6 +385,7 @@ static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT, void __init time_init(void) { + int i; /* probe for the RTC and read it if it exists */ if(RTC_INIT() < 0) { @@ -442,6 +448,13 @@ time_init(void) IO_STATE(R_TIMER_CTRL, tm0, run) | IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); #endif + + for (i=0; i <= TIMER0_DIV; i++) { + /* We must be careful not to get overflow... */ + cris_timer0_value_us[TIMER0_DIV-i] = + (unsigned short)((unsigned long) + ((i*(1000000/HZ))/TIMER0_DIV)&0x0000FFFFL); + } *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c index 48cec40d0cb9..9fcda3abd2b8 100644 --- a/arch/cris/kernel/traps.c +++ b/arch/cris/kernel/traps.c @@ -138,8 +138,8 @@ show_registers(struct pt_regs * regs) register. */ unsigned long usp = rdusp(); - printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx %s\n", - regs->irp, regs->srp, regs->dccr, usp, regs->mof, print_tainted()); + printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", + regs->irp, regs->srp, regs->dccr, usp, regs->mof ); printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S index 7b6264b4d40a..909c0b870ac9 100644 --- a/arch/i386/boot/bootsect.S +++ b/arch/i386/boot/bootsect.S @@ -395,9 +395,15 @@ print_digit: # NOTE: Doesn't save %ax or %dx; do it yourself if you need to. kill_motor: +#if 1 + xorw %ax, %ax # reset FDC + xorb %dl, %dl + int $0x13 +#else movw $0x3f2, %dx xorb %al, %al outb %al, %dx +#endif ret sectors: .word 0 diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index 6a14c8c5cd35..0907ea962d90 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -232,8 +232,8 @@ bad_sig: # Move rest of setup code/data to here movw $2048, %di # four sectors loaded by LILO subw %si, %si - movw %cs, %ax # aka SETUPSEG - movw %ax, %es + pushw %cs + popw %es movw $SYSSEG, %ax movw %ax, %ds rep @@ -253,6 +253,7 @@ no_sig: call prtstr no_sig_loop: + hlt jmp no_sig_loop good_sig: @@ -641,18 +642,40 @@ move_self_here: movw %ax, %ds movw %dx, %ss end_move_self: # now we are at the right place - lidt idt_48 # load idt with 0,0 - xorl %eax, %eax # Compute gdt_base - movw %ds, %ax # (Convert %ds:gdt to a linear ptr) - shll $4, %eax - addl $gdt, %eax - movl %eax, (gdt_48+2) - lgdt gdt_48 # load gdt with whatever is - # appropriate -# that was painless, now we enable a20 +# +# Enable A20. This is at the very best an annoying procedure. +# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin. +# + +A20_TEST_LOOPS = 32 # Iterations per wait +A20_ENABLE_LOOPS = 255 # Total loops to try + + +a20_try_loop: + + # First, see if we are on a system with no A20 gate. +a20_none: + call a20_test + jnz a20_done + + # Next, try the BIOS (INT 0x15, AX=0x2401) +a20_bios: + movw $0x2401, %ax + pushfl # Be paranoid about flags + int $0x15 + popfl + + call a20_test + jnz a20_done + + # Try enabling A20 through the keyboard controller +a20_kbc: call empty_8042 + call a20_test # Just in case the BIOS worked + jnz a20_done # but had a delayed reaction. + movb $0xD1, %al # command write outb %al, $0x64 call empty_8042 @@ -661,29 +684,62 @@ end_move_self: # now we are at the right place outb %al, $0x60 call empty_8042 -# -# You must preserve the other bits here. Otherwise embarrasing things -# like laptops powering off on boot happen. Corrected version by Kira -# Brown from Linux 2.2 -# - inb $0x92, %al # - orb $02, %al # "fast A20" version - outb %al, $0x92 # some chips have only this - -# wait until a20 really *is* enabled; it can take a fair amount of -# time on certain systems; Toshiba Tecras are known to have this -# problem. The memory location used here (0x200) is the int 0x80 -# vector, which should be safe to use. - - xorw %ax, %ax # segment 0x0000 - movw %ax, %fs - decw %ax # segment 0xffff (HMA) - movw %ax, %gs -a20_wait: - incw %ax # unused memory location <0xfff0 - movw %ax, %fs:(0x200) # we use the "int 0x80" vector - cmpw %gs:(0x210), %ax # and its corresponding HMA addr - je a20_wait # loop until no longer aliased + # Wait until a20 really *is* enabled; it can take a fair amount of + # time on certain systems; Toshiba Tecras are known to have this + # problem. +a20_kbc_wait: + xorw %cx, %cx +a20_kbc_wait_loop: + call a20_test + jnz a20_done + loop a20_kbc_wait_loop + + # Final attempt: use "configuration port A" +a20_fast: + inb $0x92, %al # Configuration Port A + orb $0x02, %al # "fast A20" version + andb $0xFE, %al # don't accidentally reset + outb %al, $0x92 + + # Wait for configuration port A to take effect +a20_fast_wait: + xorw %cx, %cx +a20_fast_wait_loop: + call a20_test + jnz a20_done + loop a20_fast_wait_loop + + # A20 is still not responding. Try frobbing it again. + # + decb (a20_tries) + jnz a20_try_loop + + movw $a20_err_msg, %si + call prtstr + +a20_die: + hlt + jmp a20_die + +a20_tries: + .byte A20_ENABLE_LOOPS + +a20_err_msg: + .ascii "linux: fatal error: A20 gate not responding!" + .byte 13, 10, 0 + + # If we get here, all is good +a20_done: + +# set up gdt and idt + lidt idt_48 # load idt with 0,0 + xorl %eax, %eax # Compute gdt_base + movw %ds, %ax # (Convert %ds:gdt to a linear ptr) + shll $4, %eax + addl $gdt, %eax + movl %eax, (gdt_48+2) + lgdt gdt_48 # load gdt with whatever is + # appropriate # make sure any possible coprocessor is properly reset.. xorw %ax, %ax @@ -840,6 +896,37 @@ bootsect_panic_loop: bootsect_panic_mess: .string "INT15 refuses to access high mem, giving up." + +# This routine tests whether or not A20 is enabled. If so, it +# exits with zf = 0. +# +# The memory address used, 0x200, is the int $0x80 vector, which +# should be safe. + +A20_TEST_ADDR = 4*0x80 + +a20_test: + pushw %cx + pushw %ax + xorw %cx, %cx + movw %cx, %fs # Low memory + decw %cx + movw %cx, %gs # High memory area + movw $A20_TEST_LOOPS, %cx + movw %fs:(A20_TEST_ADDR), %ax + pushw %ax +a20_test_wait: + incw %ax + movw %ax, %fs:(A20_TEST_ADDR) + call delay # Serialize and make delay constant + cmpw %gs:(A20_TEST_ADDR+0x10), %ax + loope a20_test_wait + + popw %fs:(A20_TEST_ADDR) + popw %ax + popw %cx + ret + # This routine checks that the keyboard command queue is empty # (after emptying the output buffers) # diff --git a/arch/i386/defconfig b/arch/i386/defconfig index ae0ccd783bba..9dfa12f38e5c 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -597,11 +597,15 @@ CONFIG_DRM_RADEON=y CONFIG_AUTOFS4_FS=y # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a1dc301ef838..789604e6fbfd 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -38,7 +38,7 @@ obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o -obj-$(CONFIG_X86_IO_APIC) += io_apic.o +obj-$(CONFIG_X86_IO_APIC) += io_apic.o acpitable.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o include $(TOPDIR)/Rules.make diff --git a/arch/i386/kernel/acpitable.c b/arch/i386/kernel/acpitable.c new file mode 100644 index 000000000000..a4c0297833c9 --- /dev/null +++ b/arch/i386/kernel/acpitable.c @@ -0,0 +1,897 @@ +/* + * acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1) + * + * Copyright (C) 1999 Andrew Henroid + * Copyright (C) 2001 Richard Schaal + * Copyright (C) 2001 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * Copyright (C) 2001 Arjan van de Ven + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SELF_CONTAINED_ACPI + +#ifdef SELF_CONTAINED_ACPI +/* + * The following codes are cut&pasted from drivers/acpi. Part of the code + * there can be not updated or delivered yet. + * To avoid conflicts when CONFIG_ACPI is defined, the following codes are + * modified so that they are self-contained in this file. + * -- jun + */ +#define dprintk printk +typedef unsigned int ACPI_TBLPTR; + +#define AE_CODE_ENVIRONMENTAL 0x0000 +#define AE_OK (u32) 0x0000 +#define AE_ERROR (u32) (0x0001 | AE_CODE_ENVIRONMENTAL) +#define AE_NO_ACPI_TABLES (u32) (0x0002 | AE_CODE_ENVIRONMENTAL) +#define AE_NOT_FOUND (u32) (0x0005 | AE_CODE_ENVIRONMENTAL) + +typedef struct { /* ACPI common table header */ + char signature[4]; /* identifies type of table */ + u32 length; /* length of table, + in bytes, * including header */ + u8 revision; /* specification minor version # */ + u8 checksum; /* to make sum of entire table == 0 */ + char oem_id[6]; /* OEM identification */ + char oem_table_id[8]; /* OEM table identification */ + u32 oem_revision; /* OEM revision number */ + char asl_compiler_id[4]; /* ASL compiler vendor ID */ + u32 asl_compiler_revision; /* ASL compiler revision number */ +} acpi_table_header __attribute__ ((packed));; + +enum { + ACPI_APIC = 0, + ACPI_BOOT, + ACPI_DBGP, + ACPI_DSDT, + ACPI_ECDT, + ACPI_ETDT, + ACPI_FACP, + ACPI_FACS, + ACPI_OEMX, + ACPI_PSDT, + ACPI_SBST, + ACPI_SLIT, + ACPI_SPCR, + ACPI_SRAT, + ACPI_SSDT, + ACPI_SPMI, + ACPI_XSDT, + ACPI_TABLE_COUNT +}; + +static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { + "APIC", + "BOOT", + "DBGP", + "DSDT", + "ECDT", + "ETDT", + "FACP", + "FACS", + "OEM", + "PSDT", + "SBST", + "SLIT", + "SPCR", + "SRAT", + "SSDT", + "SPMI", + "XSDT" +}; + +struct acpi_table_madt { + acpi_table_header header; + u32 lapic_address; + struct { + u32 pcat_compat:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed));; + +enum { + ACPI_MADT_LAPIC = 0, + ACPI_MADT_IOAPIC, + ACPI_MADT_INT_SRC_OVR, + ACPI_MADT_NMI_SRC, + ACPI_MADT_LAPIC_NMI, + ACPI_MADT_LAPIC_ADDR_OVR, + ACPI_MADT_IOSAPIC, + ACPI_MADT_LSAPIC, + ACPI_MADT_PLAT_INT_SRC, + ACPI_MADT_ENTRY_COUNT +}; + +#define RSDP_SIG "RSD PTR " +#define RSDT_SIG "RSDT" + +#define ACPI_DEBUG_PRINT(pl) + +#define ACPI_MEMORY_MODE 0x01 +#define ACPI_LOGICAL_ADDRESSING 0x00 +#define ACPI_PHYSICAL_ADDRESSING 0x01 + +#define LO_RSDP_WINDOW_BASE 0 /* Physical Address */ +#define HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ +#define LO_RSDP_WINDOW_SIZE 0x400 +#define HI_RSDP_WINDOW_SIZE 0x20000 +#define RSDP_SCAN_STEP 16 +#define RSDP_CHECKSUM_LENGTH 20 + +typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long); + +static acpi_table_handler acpi_boot_ops[ACPI_TABLE_COUNT]; + +struct acpi_table_rsdp { + char signature[8]; + u8 checksum; + char oem_id[6]; + u8 revision; + u32 rsdt_address; +} __attribute__ ((packed)); + +struct acpi_table_rsdt { + acpi_table_header header; + u32 entry[ACPI_TABLE_COUNT]; +} __attribute__ ((packed)); + +typedef struct { + u8 type; + u8 length; +} acpi_madt_entry_header __attribute__ ((packed)); + +typedef struct { + u16 polarity:2; + u16 trigger:2; + u16 reserved:12; +} acpi_madt_int_flags __attribute__ ((packed)); + +struct acpi_table_lapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + struct { + u32 enabled:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed)); + +struct acpi_table_ioapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 address; + u32 global_irq_base; +} __attribute__ ((packed)); + +struct acpi_table_int_src_ovr { + acpi_madt_entry_header header; + u8 bus; + u8 bus_irq; + u32 global_irq; + acpi_madt_int_flags flags; +} __attribute__ ((packed)); + +struct acpi_table_nmi_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u32 global_irq; +} __attribute__ ((packed)); + +struct acpi_table_lapic_nmi { + acpi_madt_entry_header header; + u8 acpi_id; + acpi_madt_int_flags flags; + u8 lint; +} __attribute__ ((packed)); + +struct acpi_table_lapic_addr_ovr { + acpi_madt_entry_header header; + u8 reserved[2]; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_iosapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 global_irq_base; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_lsapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + u8 eid; + u8 reserved[3]; + struct { + u32 enabled:1; + u32 reserved:31; + } flags; +} __attribute__ ((packed)); + +struct acpi_table_plat_int_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u8 type; + u8 id; + u8 eid; + u8 iosapic_vector; + u32 global_irq; + u32 reserved; +} __attribute__ ((packed)); + +/* + * ACPI Table Descriptor. One per ACPI table + */ +typedef struct acpi_table_desc { + struct acpi_table_desc *prev; + struct acpi_table_desc *next; + struct acpi_table_desc *installed_desc; + acpi_table_header *pointer; + void *base_pointer; + u8 *aml_pointer; + u64 physical_address; + u32 aml_length; + u32 length; + u32 count; + u16 table_id; + u8 type; + u8 allocation; + u8 loaded_into_namespace; + +} acpi_table_desc __attribute__ ((packed));; + +static unsigned char __init +acpi_tb_checksum(void *buffer, int length) +{ + int i; + unsigned char *bytebuffer; + unsigned char sum = 0; + + if (!buffer || length <= 0) + return 0; + + bytebuffer = (unsigned char *) buffer; + + for (i = 0; i < length; i++) + sum += *(bytebuffer++); + + return sum; +} + +static int __init +acpi_table_checksum(acpi_table_header * header) +{ + u8 *p = (u8 *) header; + int length = 0; + int sum = 0; + + if (!header) + return -EINVAL; + + length = header->length; + + while (length--) + sum += *p++; + + return sum & 0xFF; +} + +static void __init +acpi_print_table_header(acpi_table_header * header) +{ + if (!header) + return; + + printk(KERN_INFO "ACPI table found: %.4s v%d [%.6s %.8s %d.%d]\n", + header->signature, header->revision, header->oem_id, + header->oem_table_id, header->oem_revision >> 16, + header->oem_revision & 0xffff); + + return; +} + +/******************************************************************************* + * + * FUNCTION: Acpi_tb_scan_memory_for_rsdp + * + * PARAMETERS: Start_address - Starting pointer for search + * Length - Maximum length to search + * + * RETURN: Pointer to the RSDP if found, otherwise NULL. + * + * DESCRIPTION: Search a block of memory for the RSDP signature + * + ******************************************************************************/ + +static unsigned char *__init +acpi_tb_scan_memory_for_rsdp(unsigned char *address, int length) +{ + u32 offset; + + if (length <= 0) + return NULL; + + /* Search from given start addr for the requested length */ + + offset = 0; + + while (offset < length) { + /* The signature must match and the checksum must be correct */ + if (strncmp(address, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0 && + acpi_tb_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) { + /* If so, we have found the RSDP */ + printk(KERN_INFO + "ACPI: RSDP located at physical address %p\n", + address); + return address; + } + offset += RSDP_SCAN_STEP; + address += RSDP_SCAN_STEP; + } + + /* Searched entire block, no RSDP was found */ + printk(KERN_INFO "ACPI: Searched entire block, no RSDP was found.\n"); + return NULL; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_find_rsdp + * + * PARAMETERS: *Table_info - Where the table info is returned + * Flags - Current memory mode (logical vs. + * physical addressing) + * + * RETURN: Status + * + * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor + * pointer structure. If it is found, set *RSDP to point to it. + * + * NOTE: The RSDP must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (ACPI 1.0 section + * 5.2.2; assertion #421). + * + ******************************************************************************/ + +static int __init +acpi_tb_find_rsdp(acpi_table_desc * table_info, u32 flags) +{ + unsigned char *address; + + /* + * Physical address is given. + */ + /* + * Region 1) Search EBDA (low memory) paragraphs + */ + address = + acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE), + LO_RSDP_WINDOW_SIZE); + + if (address) { + /* Found it, return the physical address */ + table_info->physical_address = (ACPI_TBLPTR) __pa(address); + return AE_OK; + } + + /* + * Region 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + */ + address = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE), + HI_RSDP_WINDOW_SIZE); + if (address) { + /* Found it, return the physical address */ + table_info->physical_address = (ACPI_TBLPTR) __pa(address); + return AE_OK; + } + + /* RSDP signature was not found */ + return AE_NOT_FOUND; +} + +static unsigned long __init +acpi_find_root_pointer(u32 flags) +{ + acpi_table_desc table_info; + int status; + + /* Get the RSDP */ + + status = acpi_tb_find_rsdp(&table_info, flags); + if (status) + return 0; + + return table_info.physical_address; +} + +static unsigned long __init +acpi_os_get_root_pointer(u32 flags) +{ + unsigned long address; + +#ifndef CONFIG_ACPI_EFI + + address = acpi_find_root_pointer(flags); + +#else + if (efi.acpi20) + address = (unsigned long) efi.acpi20; + else if (efi.acpi) + address = (unsigned long) efi.acpi; + else + address = 0; +#endif /*CONFIG_ACPI_EFI */ + + if (address == 0) + printk(KERN_ERR "ACPI: System description tables not found\n"); + + return address; +} + +/* + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_0, + * to map the target physical address. The problem is that set_fixmap() + * provides a single page, and it is possible that the page is not + * sufficient. + * By using this area, we can map up to MAX_IO_APICS pages temporarily, + * i.e. until the next __va_range() call. + */ +static __inline__ char * +__va_range(unsigned long phys, unsigned long size) +{ + unsigned long base, offset, mapped_size, mapped_phys = phys; + int idx = FIX_IO_APIC_BASE_0; + + offset = phys & (PAGE_SIZE - 1); + mapped_size = PAGE_SIZE - offset; + set_fixmap(idx, mapped_phys); + base = fix_to_virt(FIX_IO_APIC_BASE_0); + + /* + * Most cases can be covered by the below. + */ + if (mapped_size >= size) + return ((unsigned char *) base + offset); + + dprintk("__va_range: mapping more than a single page, size = 0x%lx\n", + size); + + do { + if (idx++ == FIX_IO_APIC_BASE_END) + return 0; /* cannot handle this */ + mapped_phys = mapped_phys + PAGE_SIZE; + set_fixmap(idx, mapped_phys); + mapped_size = mapped_size + PAGE_SIZE; + } while (mapped_size < size); + + return ((unsigned char *) base + offset); +} + +static int __init acpi_tables_init(void) +{ + int result = -ENODEV; + int status = AE_OK; + unsigned long rsdp_addr = 0; + acpi_table_header *header = NULL; + struct acpi_table_rsdp *rsdp = NULL; +#ifndef CONFIG_IA64 + struct acpi_table_rsdt *rsdt = NULL; + struct acpi_table_rsdt saved_rsdt; +#else + struct acpi071_table_rsdt *rsdt = NULL; +#endif + int tables = 0; + int type = 0; + int i = 0; + + rsdp_addr = acpi_os_get_root_pointer(ACPI_PHYSICAL_ADDRESSING); + + if (!rsdp_addr) + return -ENODEV; + + rsdp = (struct acpi_table_rsdp *) rsdp_addr; + + printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, + rsdp->oem_id); + if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { + printk(KERN_WARNING "RSDP table signature incorrect\n"); + return -EINVAL; + } + + rsdt = (struct acpi_table_rsdt *) + __va_range(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt)); + + if (rsdt) { + header = (acpi_table_header *) & rsdt->header; + acpi_print_table_header(header); + if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { + printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); + rsdt = NULL; + } else { + /* + * The number of tables is computed by taking the + * size of all entries (header size minus total + * size of RSDT) divided by the size of each entry + * (4-byte table pointers). + */ + tables = + (header->length - sizeof(acpi_table_header)) / 4; + } + } + + if (!rsdt) { + printk(KERN_WARNING + "ACPI: Invalid root system description tables (RSDT)\n"); + return -ENODEV; + } + + memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); + + if (saved_rsdt.header.length > sizeof(saved_rsdt)) { + printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", + saved_rsdt.header.length); + return -ENODEV; + } + + for (i = 0; i < tables; i++) { + + if (rsdt) { + header = (acpi_table_header *) + __va_range(saved_rsdt.entry[i], + sizeof(acpi_table_header)); + } + + if (!header) + break; + + acpi_print_table_header(header); + + for (type = 0; type < ACPI_TABLE_COUNT; type++) + if (!strncmp + ((char *) &header->signature, + acpi_table_signatures[type],strlen(acpi_table_signatures[type]))) + break; + + if (type >= ACPI_TABLE_COUNT) { + printk(KERN_WARNING "ACPI: Unsupported table %.4s\n", + header->signature); + continue; + } + + if (acpi_table_checksum(header)) { + printk(KERN_WARNING "ACPI %s has invalid checksum\n", + acpi_table_signatures[i]); + continue; + } + + if (acpi_boot_ops && acpi_boot_ops[type]) + result = + acpi_boot_ops[type] (header, + (unsigned long) saved_rsdt. + entry[i]); + } + + return result; +} +#endif /* SELF_CONTAINED_ACPI */ + +static int total_cpus __initdata = 0; +int have_acpi_tables; + +extern void __init MP_processor_info(struct mpc_config_processor *); + +static void __init +acpi_parse_lapic(struct acpi_table_lapic *local_apic) +{ + struct mpc_config_processor proc_entry; + int ix = 0; + + if (!local_apic) + return; + + dprintk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n", + local_apic->acpi_id, local_apic->id, local_apic->flags.enabled); + + dprintk("CPU %d (0x%02x00)", total_cpus, local_apic->id); + + if (local_apic->flags.enabled) { + printk(" enabled"); + ix = local_apic->id; + if (ix >= MAX_APICS) { + printk(KERN_WARNING + "Processor #%d INVALID - (Max ID: %d).\n", ix, + MAX_APICS); + return; + } + /* + * Fill in the info we want to save. Not concerned about + * the processor ID. Processor features aren't present in + * the table. + */ + proc_entry.mpc_type = MP_PROCESSOR; + proc_entry.mpc_apicid = local_apic->id; + proc_entry.mpc_cpuflag = CPU_ENABLED; + if (proc_entry.mpc_apicid == boot_cpu_physical_apicid) { + printk(" (BSP)"); + proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR; + } + proc_entry.mpc_cpufeature = + (boot_cpu_data.x86 << 8) | (boot_cpu_data. + x86_model << 4) | boot_cpu_data. + x86_mask; + proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0]; + proc_entry.mpc_reserved[0] = 0; + proc_entry.mpc_reserved[1] = 0; + proc_entry.mpc_apicver = 0x10; /* integrated APIC */ + MP_processor_info(&proc_entry); + } else { + printk(" disabled"); + } + printk("\n"); + + total_cpus++; + return; +} + +static void __init +acpi_parse_ioapic(struct acpi_table_ioapic *ioapic) +{ + + if (!ioapic) + return; + + printk(KERN_INFO + "IOAPIC (id[0x%x] address[0x%x] global_irq_base[0x%x])\n", + ioapic->id, ioapic->address, ioapic->global_irq_base); + + if (nr_ioapics >= MAX_IO_APICS) { + printk(KERN_WARNING + "Max # of I/O APICs (%d) exceeded (found %d).\n", + MAX_IO_APICS, nr_ioapics); + panic("Recompile kernel with bigger MAX_IO_APICS!\n"); + } +} + +static void __init +acpi_parse_int_src_ovr(struct acpi_table_int_src_ovr *intsrc) +{ + /* + static int first_time_switch = 0; + struct mpc_config_intsrc my_intsrc; + int i; + */ + if (!intsrc) + return; + + printk(KERN_INFO + "INT_SRC_OVR (bus[%d] irq[0x%x] global_irq[0x%x] polarity[0x%x] trigger[0x%x])\n", + intsrc->bus, intsrc->bus_irq, intsrc->global_irq, + intsrc->flags.polarity, intsrc->flags.trigger); +} + +/* + * At this point, we look at the interrupt assignment entries in the MPS + * table. + */ + +static void __init acpi_parse_nmi_src(struct acpi_table_nmi_src *nmisrc) +{ + if (!nmisrc) + return; + + printk(KERN_INFO + "NMI_SRC (polarity[0x%x] trigger[0x%x] global_irq[0x%x])\n", + nmisrc->flags.polarity, nmisrc->flags.trigger, + nmisrc->global_irq); + +} +static void __init +acpi_parse_lapic_nmi(struct acpi_table_lapic_nmi *localnmi) +{ + if (!localnmi) + return; + + printk(KERN_INFO + "LAPIC_NMI (acpi_id[0x%04x] polarity[0x%x] trigger[0x%x] lint[0x%x])\n", + localnmi->acpi_id, localnmi->flags.polarity, + localnmi->flags.trigger, localnmi->lint); +} +static void __init +acpi_parse_lapic_addr_ovr(struct acpi_table_lapic_addr_ovr *lapic_addr_ovr) +{ + if (!lapic_addr_ovr) + return; + + printk(KERN_INFO "LAPIC_ADDR_OVR (address[0x%lx])\n", + (unsigned long) lapic_addr_ovr->address); + +} + +#ifdef CONFIG_IA64 +static void __init +acpi_parse_iosapic(struct acpi_table_iosapic *iosapic) +{ + if (!iosapic) + return; + + printk(KERN_INFO "IOSAPIC (id[%x] global_irq_base[%x] address[%lx])\n", + iosapic->id, iosapic->global_irq_base, + (unsigned long) iosapic->address); + + return 0; +} +static void __init +acpi_parse_lsapic(struct acpi_table_lsapic *lsapic) +{ + if (!lsapic) + return; + + printk(KERN_INFO + "LSAPIC (acpi_id[0x%04x] id[0x%x] eid[0x%x] enabled[%d])\n", + lsapic->acpi_id, lsapic->id, lsapic->eid, lsapic->flags.enabled); + + if (!lsapic->flags.enabled) + return; +} +#endif +static void __init +acpi_parse_plat_int_src(struct acpi_table_plat_int_src *plintsrc) +{ + if (!plintsrc) + return; + + printk(KERN_INFO + "PLAT_INT_SRC (polarity[0x%x] trigger[0x%x] type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", + plintsrc->flags.polarity, plintsrc->flags.trigger, + plintsrc->type, plintsrc->id, plintsrc->eid, + plintsrc->iosapic_vector, plintsrc->global_irq); +} +static int __init +acpi_parse_madt(acpi_table_header * header, unsigned long phys) +{ + + struct acpi_table_madt *madt = + (struct acpi_table_madt *) __va_range(phys, header->length); + acpi_madt_entry_header *entry_header = NULL; + int table_size = 0; + + if (!madt) + return -EINVAL; + + table_size = (int) (header->length - sizeof(*madt)); + entry_header = + (acpi_madt_entry_header *) ((void *) madt + sizeof(*madt)); + + while (entry_header && (table_size > 0)) { + switch (entry_header->type) { + case ACPI_MADT_LAPIC: + acpi_parse_lapic((struct acpi_table_lapic *) + entry_header); + break; + case ACPI_MADT_IOAPIC: + acpi_parse_ioapic((struct acpi_table_ioapic *) + entry_header); + break; + case ACPI_MADT_INT_SRC_OVR: + acpi_parse_int_src_ovr((struct acpi_table_int_src_ovr *) + entry_header); + break; + case ACPI_MADT_NMI_SRC: + acpi_parse_nmi_src((struct acpi_table_nmi_src *) + entry_header); + break; + case ACPI_MADT_LAPIC_NMI: + acpi_parse_lapic_nmi((struct acpi_table_lapic_nmi *) + entry_header); + break; + case ACPI_MADT_LAPIC_ADDR_OVR: + acpi_parse_lapic_addr_ovr((struct + acpi_table_lapic_addr_ovr *) + entry_header); + break; +#ifdef CONFIG_IA64 + case ACPI_MADT_IOSAPIC: + acpi_parse_iosapic((struct acpi_table_iosapic *) + entry_header); + break; + case ACPI_MADT_LSAPIC: + acpi_parse_lsapic((struct acpi_table_lsapic *) + entry_header); + break; +#endif + case ACPI_MADT_PLAT_INT_SRC: + acpi_parse_plat_int_src((struct acpi_table_plat_int_src + *) entry_header); + break; + default: + printk(KERN_WARNING + "Unsupported MADT entry type 0x%x\n", + entry_header->type); + break; + } + table_size -= entry_header->length; + entry_header = + (acpi_madt_entry_header *) ((void *) entry_header + + entry_header->length); + } + + if (!total_cpus) { + printk("ACPI: No Processors found in the APCI table.\n"); + return -EINVAL; + } + + printk(KERN_INFO "%d CPUs total\n", total_cpus); + + if (madt->lapic_address) + mp_lapic_addr = madt->lapic_address; + else + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + + printk(KERN_INFO "Local APIC address %x\n", madt->lapic_address); + + return 0; +} + +extern int enable_acpi_smp_table; + +/* + * Configure the processor info using MADT in the ACPI tables. If we fail to + * configure that, then we use the MPS tables. + */ +void __init +config_acpi_tables(void) +{ + int result = 0; + + /* + * Only do this when requested, either because of CPU/Bios type or from the command line + */ + if (!enable_acpi_smp_table) { + return; + } + + memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops)); + acpi_boot_ops[ACPI_APIC] = acpi_parse_madt; + result = acpi_tables_init(); + + if (!result) { + have_acpi_tables = 1; + printk("Enabling the CPU's according to the ACPI table\n"); + } +} diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 2b68085ca7e8..c7bff7b28bca 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -575,7 +575,6 @@ static inline void apic_pm_init2(void) { } static int __init detect_init_APIC (void) { u32 h, l, features; - int needs_pm = 0; extern void get_cpu_vendor(struct cpuinfo_x86*); /* Workaround for us being called before identify_cpu(). */ @@ -608,7 +607,6 @@ static int __init detect_init_APIC (void) l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); - needs_pm = 1; } } /* @@ -628,8 +626,7 @@ static int __init detect_init_APIC (void) printk("Found and enabled local APIC!\n"); - if (needs_pm) - apic_pm_init1(); + apic_pm_init1(); return 0; diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index cf499eb3e490..3a9299653042 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -1471,7 +1471,7 @@ static int do_ioctl(struct inode * inode, struct file *filp, as = filp->private_data; if (check_apm_user(as, "ioctl")) return -EIO; - if (!as->suser) + if ((!as->suser) || (!as->writer)) return -EPERM; switch (cmd) { case APM_IOC_STANDBY: diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c index 433ef7156b11..3f95d10b00d8 100644 --- a/arch/i386/kernel/dmi_scan.c +++ b/arch/i386/kernel/dmi_scan.c @@ -12,6 +12,7 @@ unsigned long dmi_broken; int is_sony_vaio_laptop; +int enable_acpi_smp_table; struct dmi_header { @@ -401,7 +402,6 @@ static __init int init_ints_after_s1(struct dmi_blacklist *d) */ typedef void (pm_kbd_func) (void); -extern pm_kbd_func *pm_kbd_request_override; static __init int broken_ps2_resume(struct dmi_blacklist *d) { diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index 333f693ee9ba..eb6f71e02b02 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -36,6 +36,7 @@ int smp_found_config; */ int apic_version [MAX_APICS]; int mp_bus_id_to_type [MAX_MP_BUSSES]; +int mp_bus_id_to_node [MAX_MP_BUSSES]; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_current_pci_id; @@ -55,6 +56,7 @@ unsigned long mp_lapic_addr; /* Processor that is doing the boot up */ unsigned int boot_cpu_physical_apicid = -1U; +unsigned int boot_cpu_logical_apicid = -1U; /* Internal processor count */ static unsigned int num_processors; @@ -118,18 +120,45 @@ static char __init *mpc_family(int family,int model) return n; } -static void __init MP_processor_info (struct mpc_config_processor *m) -{ - int ver; +#ifdef CONFIG_X86_IO_APIC +extern int have_acpi_tables; /* set by acpitable.c */ +#else +#define have_acpi_tables (0) +#endif +/* + * Have to match translation table entries to main table entries by counter + * hence the mpc_record variable .... can't see a less disgusting way of + * doing this .... + */ + +static int mpc_record; +static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata; + +void __init MP_processor_info (struct mpc_config_processor *m) +{ + int ver, quad, logical_apicid; + if (!(m->mpc_cpuflag & CPU_ENABLED)) return; - printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, - mpc_family( (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , - (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), - m->mpc_apicver); + logical_apicid = m->mpc_apicid; + if (clustered_apic_mode) { + quad = translation_table[mpc_record]->trans_quad; + logical_apicid = (quad << 4) + + (m->mpc_apicid ? m->mpc_apicid << 1 : 1); + printk("Processor #%d %s APIC version %d (quad %d, apic %d)\n", + m->mpc_apicid, + mpc_family((m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , + (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), + m->mpc_apicver, quad, logical_apicid); + } else { + printk("Processor #%d %s APIC version %d\n", + m->mpc_apicid, + mpc_family((m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , + (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), + m->mpc_apicver); + } if (m->mpc_featureflag&(1<<0)) Dprintk(" Floating point unit present.\n"); @@ -172,7 +201,8 @@ static void __init MP_processor_info (struct mpc_config_processor *m) Dprintk(" Willamette New Instructions present.\n"); if (m->mpc_featureflag&(1<<27)) Dprintk(" Self Snoop present.\n"); - /* 28 Reserved */ + if (m->mpc_featureflag&(1<<28)) + Dprintk(" HT present.\n"); if (m->mpc_featureflag&(1<<29)) Dprintk(" Thermal Monitor present.\n"); /* 30, 31 Reserved */ @@ -181,6 +211,7 @@ static void __init MP_processor_info (struct mpc_config_processor *m) if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { Dprintk(" Bootup CPU\n"); boot_cpu_physical_apicid = m->mpc_apicid; + boot_cpu_logical_apicid = logical_apicid; } num_processors++; @@ -192,12 +223,11 @@ static void __init MP_processor_info (struct mpc_config_processor *m) } ver = m->mpc_apicver; - if (clustered_apic_mode) - /* Crude temporary hack. Assumes processors are sequential */ - phys_cpu_present_map |= 1 << (num_processors-1); - else + if (clustered_apic_mode) { + phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad); + } else { phys_cpu_present_map |= 1 << m->mpc_apicid; - + } /* * Validate version */ @@ -214,7 +244,13 @@ static void __init MP_bus_info (struct mpc_config_bus *m) memcpy(str, m->mpc_bustype, 6); str[6] = 0; - Dprintk("Bus #%d is %s\n", m->mpc_busid, str); + + if (clustered_apic_mode) { + mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad; + printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]); + } else { + Dprintk("Bus #%d is %s\n", m->mpc_busid, str); + } if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; @@ -286,6 +322,63 @@ static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m) BUG(); } +static void __init MP_translation_info (struct mpc_config_translation *m) +{ + printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, + m->trans_quad, m->trans_global, m->trans_local); + + if (mpc_record >= MAX_MPC_ENTRY) + printk("MAX_MPC_ENTRY exceeded!\n"); + else + translation_table[mpc_record] = m; /* stash this for later */ +} + +/* + * Read/parse the MPC oem tables + */ + +static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \ + unsigned short oemsize) +{ + int count = sizeof (*oemtable); /* the header size */ + unsigned char *oemptr = ((unsigned char *)oemtable)+count; + + printk("Found an OEM MPC table at %8p - parsing it ... \n", oemtable); + if (memcmp(oemtable->oem_signature,MPC_OEM_SIGNATURE,4)) + { + printk("SMP mpc oemtable: bad signature [%c%c%c%c]!\n", + oemtable->oem_signature[0], + oemtable->oem_signature[1], + oemtable->oem_signature[2], + oemtable->oem_signature[3]); + return; + } + if (mpf_checksum((unsigned char *)oemtable,oemtable->oem_length)) + { + printk("SMP oem mptable: checksum error!\n"); + return; + } + while (count < oemtable->oem_length) { + switch (*oemptr) { + case MP_TRANSLATION: + { + struct mpc_config_translation *m= + (struct mpc_config_translation *)oemptr; + MP_translation_info(m); + oemptr += sizeof(*m); + count += sizeof(*m); + ++mpc_record; + break; + } + default: + { + printk("Unrecognised OEM table entry type! - %d\n", (int) *oemptr); + return; + } + } + } +} + /* * Read/parse the MPC */ @@ -327,8 +420,18 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) printk("APIC at: 0x%lX\n",mpc->mpc_lapic); - /* save the local APIC address, it might be non-default */ - mp_lapic_addr = mpc->mpc_lapic; + /* save the local APIC address, it might be non-default, + * but only if we're not using the ACPI tables + */ + if (!have_acpi_tables) + mp_lapic_addr = mpc->mpc_lapic; + + if (clustered_apic_mode && mpc->mpc_oemptr) { + /* We need to process the oem mpc tables to tell us which quad things are in ... */ + mpc_record = 0; + smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize); + mpc_record = 0; + } /* * Now process the configuration blocks. @@ -339,7 +442,10 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) { struct mpc_config_processor *m= (struct mpc_config_processor *)mpt; - MP_processor_info(m); + + /* ACPI may already have provided this one for us */ + if (!have_acpi_tables) + MP_processor_info(m); mpt += sizeof(*m); count += sizeof(*m); break; @@ -381,7 +487,13 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) count+=sizeof(*m); break; } + default: + { + count = mpc->mpc_length; + break; + } } + ++mpc_record; } if (clustered_apic_mode && nr_ioapics > 2) { /* don't initialise IO apics on secondary quads */ @@ -550,6 +662,7 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) } static struct intel_mp_floating *mpf_found; +extern void config_acpi_tables(void); /* * Scan the memory blocks for an SMP configuration block. @@ -557,6 +670,18 @@ static struct intel_mp_floating *mpf_found; void __init get_smp_config (void) { struct intel_mp_floating *mpf = mpf_found; + +#ifdef CONFIG_X86_IO_APIC + /* + * Check if the ACPI tables are provided. Use them only to get + * the processor information, mainly because it provides + * the info on the logical processor(s), rather than the physical + * processor(s) that are provided by the MPS. We attempt to + * check only if the user provided a commandline override + */ + config_acpi_tables(); +#endif + printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { printk(" IMCR and PIC compatibility mode.\n"); diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index fe03b503854c..fc6248324321 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -2249,9 +2249,11 @@ int __init mtrr_init(void) proc_root_mtrr->proc_fops = &mtrr_fops; } #endif +#ifdef USERSPACE_INTERFACE devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, &mtrr_fops, NULL); +#endif init_table (); return 0; } /* End Function mtrr_init */ diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c index 68b4849aaf7a..364bf52bba39 100644 --- a/arch/i386/kernel/pci-pc.c +++ b/arch/i386/kernel/pci-pc.c @@ -309,7 +309,7 @@ static struct pci_ops pci_direct_conf2 = { * This should be close to trivial, but it isn't, because there are buggy * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. */ -static int __init pci_sanity_check(struct pci_ops *o) +static int __devinit pci_sanity_check(struct pci_ops *o) { u16 x; struct pci_bus bus; /* Fake bus and device */ @@ -329,7 +329,7 @@ static int __init pci_sanity_check(struct pci_ops *o) return 0; } -static struct pci_ops * __init pci_check_direct(void) +static struct pci_ops * __devinit pci_check_direct(void) { unsigned int tmp; unsigned long flags; @@ -488,7 +488,7 @@ static struct { static int pci_bios_present; -static int __init check_pcibios(void) +static int __devinit check_pcibios(void) { u32 signature, eax, ebx, ecx; u8 status, major_ver, minor_ver, hw_mech; @@ -538,7 +538,7 @@ static int __init check_pcibios(void) return 0; } -static int __init pci_bios_find_device (unsigned short vendor, unsigned short device_id, +static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id, unsigned short index, unsigned char *bus, unsigned char *device_fn) { unsigned short bx; @@ -747,7 +747,7 @@ static struct pci_ops pci_bios_access = { * Try to find PCI BIOS. */ -static struct pci_ops * __init pci_find_bios(void) +static struct pci_ops * __devinit pci_find_bios(void) { union bios32 *check; unsigned char sum; @@ -801,7 +801,7 @@ static struct pci_ops * __init pci_find_bios(void) * which used BIOS ordering, we are bound to do this... */ -static void __init pcibios_sort(void) +static void __devinit pcibios_sort(void) { LIST_HEAD(sorted_devices); struct list_head *ln; @@ -855,7 +855,7 @@ struct irq_routing_options { u16 segment; } __attribute__((packed)); -struct irq_routing_table * __init pcibios_get_irq_routing_table(void) +struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void) { struct irq_routing_options opt; struct irq_routing_table *rt = NULL; @@ -929,7 +929,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq) * expected to be unique) and remove the ghost devices. */ -static void __init pcibios_fixup_ghosts(struct pci_bus *b) +static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) { struct list_head *ln, *mn; struct pci_dev *d, *e; @@ -979,7 +979,7 @@ static void __init pcibios_fixup_ghosts(struct pci_bus *b) * Discover remaining PCI buses in case there are peer host bridges. * We use the number of last PCI bus provided by the PCI BIOS. */ -static void __init pcibios_fixup_peer_bridges(void) +static void __devinit pcibios_fixup_peer_bridges(void) { int n; struct pci_bus bus; @@ -1010,7 +1010,7 @@ static void __init pcibios_fixup_peer_bridges(void) * Exceptions for specific devices. Usually work-arounds for fatal design flaws. */ -static void __init pci_fixup_i450nx(struct pci_dev *d) +static void __devinit pci_fixup_i450nx(struct pci_dev *d) { /* * i450NX -- Find and scan all secondary buses on all PXB's. @@ -1032,7 +1032,7 @@ static void __init pci_fixup_i450nx(struct pci_dev *d) pcibios_last_bus = -1; } -static void __init pci_fixup_i450gx(struct pci_dev *d) +static void __devinit pci_fixup_i450gx(struct pci_dev *d) { /* * i450GX and i450KX -- Find and scan all secondary buses. @@ -1045,49 +1045,7 @@ static void __init pci_fixup_i450gx(struct pci_dev *d) pcibios_last_bus = -1; } -#if 0 -/* Until we get proper handling pray the BIOS gets it right */ -/* - * ServerWorks host bridges -- Find and scan all secondary buses. - * Register 0x44 contains first, 0x45 last bus number routed there. - */ -static void __init pci_fixup_serverworks(struct pci_dev *d) -{ - u8 busno1, busno2; - - pci_read_config_byte(d, 0x44, &busno1); - pci_read_config_byte(d, 0x45, &busno2); - if (busno2 < busno1) - busno2 = busno1; - if (busno2 > pcibios_last_bus) { - pcibios_last_bus = busno2; - printk("PCI: ServerWorks host bridge: last bus %02x\n", pcibios_last_bus); - } -} -#endif - -#if 0 -/* Our bus code shouldnt need this fixup any more. Delete once verified */ -/* - * Compaq host bridges -- Find and scan all secondary buses. - * This time registers 0xc8 and 0xc9. - */ -static void __init pci_fixup_compaq(struct pci_dev *d) -{ - u8 busno1, busno2; - - pci_read_config_byte(d, 0xc8, &busno1); - pci_read_config_byte(d, 0xc9, &busno2); - if (busno2 < busno1) - busno2 = busno1; - if (busno2 > pcibios_last_bus) { - pcibios_last_bus = busno2; - printk("PCI: Compaq host bridge: last bus %02x\n", busno2); - } -} -#endif - -static void __init pci_fixup_umc_ide(struct pci_dev *d) +static void __devinit pci_fixup_umc_ide(struct pci_dev *d) { /* * UM8886BF IDE controller sets region type bits incorrectly, @@ -1100,7 +1058,7 @@ static void __init pci_fixup_umc_ide(struct pci_dev *d) d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } -static void __init pci_fixup_ide_bases(struct pci_dev *d) +static void __devinit pci_fixup_ide_bases(struct pci_dev *d) { int i; @@ -1119,7 +1077,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d) } } -static void __init pci_fixup_ide_trash(struct pci_dev *d) +static void __devinit pci_fixup_ide_trash(struct pci_dev *d) { int i; @@ -1132,7 +1090,7 @@ static void __init pci_fixup_ide_trash(struct pci_dev *d) d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; } -static void __init pci_fixup_latency(struct pci_dev *d) +static void __devinit pci_fixup_latency(struct pci_dev *d) { /* * SiS 5597 and 5598 chipsets require latency timer set to @@ -1142,7 +1100,7 @@ static void __init pci_fixup_latency(struct pci_dev *d) pcibios_max_latency = 32; } -static void __init pci_fixup_piix4_acpi(struct pci_dev *d) +static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) { /* * PIIX4 ACPI device: hardwired IRQ9 @@ -1173,16 +1131,6 @@ static void __init pci_fixup_via_athlon_bug(struct pci_dev *d) struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx }, -#if 0 -/* Until we get proper handling pray the BIOS gets it right */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HE, pci_fixup_serverworks }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, pci_fixup_serverworks }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CMIC_HE, pci_fixup_serverworks }, -#endif -#if 0 -/* Our bus code shouldnt need this fixup any more. Delete once verified */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_6010, pci_fixup_compaq }, -#endif { PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash }, { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, @@ -1198,14 +1146,14 @@ struct pci_fixup pcibios_fixups[] = { * are examined. */ -void __init pcibios_fixup_bus(struct pci_bus *b) +void __devinit pcibios_fixup_bus(struct pci_bus *b) { pcibios_fixup_ghosts(b); pci_read_bridge_bases(b); } -void __init pcibios_config_init(void) +void __devinit pcibios_config_init(void) { /* * Try all known PCI access methods. Note that we support using @@ -1262,7 +1210,7 @@ void __init pcibios_init(void) #endif } -char * __init pcibios_setup(char *str) +char * __devinit pcibios_setup(char *str) { if (!strcmp(str, "off")) { pci_probe = 0; diff --git a/arch/i386/kernel/semaphore.c b/arch/i386/kernel/semaphore.c index 338c6d7e3c3d..c2ff936a5474 100644 --- a/arch/i386/kernel/semaphore.c +++ b/arch/i386/kernel/semaphore.c @@ -243,7 +243,8 @@ asm( .globl __write_lock_failed __write_lock_failed: " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) -1: cmpl $" RW_LOCK_BIAS_STR ",(%eax) +1: rep; nop + cmpl $" RW_LOCK_BIAS_STR ",(%eax) jne 1b " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) @@ -255,7 +256,8 @@ __write_lock_failed: .globl __read_lock_failed __read_lock_failed: lock ; incl (%eax) -1: cmpl $1,(%eax) +1: rep; nop + cmpl $1,(%eax) js 1b lock ; decl (%eax) diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 3bb1dc94cadb..d81fa81af8af 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -165,6 +165,8 @@ long strnlen_user(const char *s, long n) unsigned long res, tmp; __asm__ __volatile__( + " testl %0, %0\n" + " jz 3f\n" " andl %0,%%ecx\n" "0: repne; scasb\n" " setne %%al\n" @@ -174,6 +176,8 @@ long strnlen_user(const char *s, long n) ".section .fixup,\"ax\"\n" "2: xorl %%eax,%%eax\n" " jmp 1b\n" + "3: movb $1,%%al\n" + " jmp 1b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index c08d2864fdbd..a107bbc8daa4 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -17,13 +17,15 @@ LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds AFLAGS_KERNEL := -mconstant-gp EXTRA = -CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 -falign-functions=32 +CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ + -falign-functions=32 +# -ffunction-sections CFLAGS_KERNEL := -mconstant-gp GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') ifneq ($(GCC_VERSION),2) - CFLAGS += -frename-registers + CFLAGS += -frename-registers --param max-inline-insns=400 endif ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y) @@ -32,7 +34,7 @@ endif ifdef CONFIG_IA64_GENERIC CORE_FILES := arch/$(ARCH)/hp/hp.a \ - arch/$(ARCH)/sn/sn.a \ + arch/$(ARCH)/sn/sn.o \ arch/$(ARCH)/dig/dig.a \ arch/$(ARCH)/sn/io/sgiio.o \ $(CORE_FILES) @@ -52,15 +54,14 @@ ifdef CONFIG_IA64_HP_SIM $(CORE_FILES) endif -ifdef CONFIG_IA64_SGI_SN1 +ifdef CONFIG_IA64_SGI_SN CFLAGS += -DBRINGUP - SUBDIRS := arch/$(ARCH)/sn/sn1 \ - arch/$(ARCH)/sn \ + SUBDIRS := arch/$(ARCH)/sn/kernel \ arch/$(ARCH)/sn/io \ arch/$(ARCH)/sn/fprom \ $(SUBDIRS) - CORE_FILES := arch/$(ARCH)/sn/sn.a \ - arch/$(ARCH)/sn/io/sgiio.o\ + CORE_FILES := arch/$(ARCH)/sn/kernel/sn.o \ + arch/$(ARCH)/sn/io/sgiio.o \ $(CORE_FILES) endif @@ -105,7 +106,7 @@ FORCE: ; compressed: vmlinux $(OBJCOPY) --strip-all vmlinux vmlinux-tmp - gzip -9 vmlinux-tmp + gzip vmlinux-tmp mv vmlinux-tmp.gz vmlinux.gz rawboot: diff --git a/arch/ia64/config.in b/arch/ia64/config.in index 52f953f5f96f..fb0931f7b75c 100644 --- a/arch/ia64/config.in +++ b/arch/ia64/config.in @@ -28,6 +28,7 @@ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then define_bool CONFIG_ACPI y + define_bool CONFIG_ACPI_EFI y define_bool CONFIG_ACPI_INTERPRETER y define_bool CONFIG_ACPI_KERNEL_CONFIG y fi @@ -40,7 +41,8 @@ choice 'IA-64 system type' \ "generic CONFIG_IA64_GENERIC \ DIG-compliant CONFIG_IA64_DIG \ HP-simulator CONFIG_IA64_HP_SIM \ - SGI-SN1 CONFIG_IA64_SGI_SN1" generic + SGI-SN1 CONFIG_IA64_SGI_SN1 \ + SGI-SN2 CONFIG_IA64_SGI_SN2" generic choice 'Kernel page size' \ "4KB CONFIG_IA64_PAGE_SIZE_4KB \ @@ -51,25 +53,6 @@ choice 'Kernel page size' \ if [ "$CONFIG_ITANIUM" = "y" ]; then define_bool CONFIG_IA64_BRL_EMU y bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC - if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC - fi - if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium B1-step specific code' CONFIG_ITANIUM_B1_SPECIFIC - fi - if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium B2-step specific code' CONFIG_ITANIUM_B2_SPECIFIC - fi - bool ' Enable Itanium C-step specific code' CONFIG_ITANIUM_CSTEP_SPECIFIC - if [ "$CONFIG_ITANIUM_CSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium C0-step specific code' CONFIG_ITANIUM_C0_SPECIFIC - fi - if [ "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \ - -o "$CONFIG_ITANIUM_B1_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B2_SPECIFIC" = "y" ]; then - define_bool CONFIG_ITANIUM_PTCG n - else - define_bool CONFIG_ITANIUM_PTCG y - fi if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then define_int CONFIG_IA64_L1_CACHE_SHIFT 7 # align cache-sensitive data to 128 bytes else @@ -78,7 +61,6 @@ if [ "$CONFIG_ITANIUM" = "y" ]; then fi if [ "$CONFIG_MCKINLEY" = "y" ]; then - define_bool CONFIG_ITANIUM_PTCG y define_int CONFIG_IA64_L1_CACHE_SHIFT 7 bool ' Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then @@ -87,28 +69,32 @@ if [ "$CONFIG_MCKINLEY" = "y" ]; then fi if [ "$CONFIG_IA64_DIG" = "y" ]; then - bool ' Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA define_bool CONFIG_PM y fi -if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then - bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM - define_bool CONFIG_DEVFS_DEBUG y +if [ "$CONFIG_IA64_SGI_SN1" = "y" ] || [ "$CONFIG_IA64_SGI_SN2" = "y" ]; then + define_bool CONFIG_IA64_SGI_SN y + bool ' Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG n + bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN_SIM + bool ' Enable autotest (llsc). Option to run cache test instead of booting' \ + CONFIG_IA64_SGI_AUTOTEST n define_bool CONFIG_DEVFS_FS y - define_bool CONFIG_IA64_BRL_EMU y + if [ "$CONFIG_DEVFS_FS" = "y" ]; then + bool ' Enable DEVFS Debug Code' CONFIG_DEVFS_DEBUG n + fi + bool ' Enable protocol mode for the L1 console' CONFIG_SERIAL_SGI_L1_PROTOCOL y + define_bool CONFIG_DISCONTIGMEM y define_bool CONFIG_IA64_MCA y - define_bool CONFIG_ITANIUM y - define_bool CONFIG_SGI_IOC3_ETH y + define_bool CONFIG_NUMA y define_bool CONFIG_PERCPU_IRQ y - define_int CONFIG_CACHE_LINE_SHIFT 7 - bool ' Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM - bool ' Enable NUMA support' CONFIG_NUMA + tristate ' PCIBA support' CONFIG_PCIBA fi define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore. bool 'SMP support' CONFIG_SMP +tristate 'Support running of Linux/x86 binaries' CONFIG_IA32_SUPPORT bool 'Performance monitor support' CONFIG_PERFMON tristate '/proc/pal support' CONFIG_IA64_PALINFO tristate '/proc/efi/vars support' CONFIG_EFI_VARS @@ -270,19 +256,23 @@ fi mainmenu_option next_comment comment 'Kernel hacking' -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for IA-32 emulation' CONFIG_IA32_SUPPORT - tristate 'Kernel FP software completion' CONFIG_MATHEMU -else - define_bool CONFIG_MATHEMU y -fi +choice 'Physical memory granularity' \ + "16MB CONFIG_IA64_GRANULE_16MB \ + 64MB CONFIG_IA64_GRANULE_64MB" 64MB -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -bool 'Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK -bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG -bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ -bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS -bool 'Disable VHPT' CONFIG_DISABLE_VHPT +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + bool ' Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS + bool ' Disable VHPT' CONFIG_DISABLE_VHPT + bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ + +# early printk is currently broken for SMP: the secondary processors get stuck... +# bool ' Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK + + bool ' Debug memory allocations' CONFIG_DEBUG_SLAB + bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + bool ' Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG + bool ' Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ +fi endmenu diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig index ce3b4bbe759a..6a0a9ff94dba 100644 --- a/arch/ia64/defconfig +++ b/arch/ia64/defconfig @@ -2,48 +2,126 @@ # Automatically generated make config: don't edit # +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +# CONFIG_KMOD is not set + # # General setup # CONFIG_IA64=y # CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set # CONFIG_IA64_GENERIC is not set -CONFIG_IA64_HP_SIM=y -# CONFIG_IA64_SGI_SN1_SIM is not set -# CONFIG_IA64_DIG is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set # CONFIG_IA64_PAGE_SIZE_4KB is not set # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y # CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +CONFIG_IA64_MCA=y +CONFIG_PM=y CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -# CONFIG_PERFMON is not set -# CONFIG_NET is not set -# CONFIG_SYSVIPC is not set +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -# CONFIG_BINFMT_ELF is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set CONFIG_PCI=y CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set # -# Code maturity level options +# Parallel port support # -CONFIG_EXPERIMENTAL=y +# CONFIG_PARPORT is not set # -# Loadable module support +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + # -# CONFIG_MODULES is not set +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set # -# Parallel port support +# QoS and/or fair queueing # -# CONFIG_PARPORT is not set +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set # # Plug and Play configuration @@ -58,14 +136,12 @@ CONFIG_EXPERIMENTAL=y # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set # # I2O device support @@ -73,9 +149,22 @@ CONFIG_EXPERIMENTAL=y # CONFIG_I2O is not set # CONFIG_I2O_PCI is not set # CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set # CONFIG_I2O_SCSI is not set # CONFIG_I2O_PROC is not set +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + # # ATA/IDE/MFM/RLL support # @@ -92,12 +181,21 @@ CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +CONFIG_BLK_DEV_IDESCSI=y # # IDE chipset support/bugfixes @@ -109,45 +207,208 @@ CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDEPCI=y CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_OFFBOARD is not set -CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_PCI_AUTO is not set CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_AEC6210_TUNING is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_WDC_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD7409 is not set -# CONFIG_AMD7409_OVERRIDE is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set CONFIG_BLK_DEV_PIIX=y -CONFIG_PIIX_TUNING=y +# CONFIG_PIIX_TUNING is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_CHIPSETS is not set -CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set # # SCSI support # -# CONFIG_SCSI is not set +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=y +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set # # Amateur Radio support @@ -164,14 +425,29 @@ CONFIG_BLK_DEV_IDE_MODES=y # # CONFIG_CD_NO_IDESCSI is not set +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + # # Character devices # -# CONFIG_VT is not set -# CONFIG_SERIAL is not set +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_ACPI is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 # # I2C support @@ -182,26 +458,55 @@ CONFIG_BLK_DEV_IDE_MODES=y # Mice # # CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set # # Joysticks # -# CONFIG_JOYSTICK is not set +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=y +CONFIG_INPUT_SERPORT=y + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set CONFIG_EFI_RTC=y - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -210,69 +515,366 @@ CONFIG_EFI_RTC=y # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set +CONFIG_AGP=y +# CONFIG_AGP_INTEL is not set +CONFIG_AGP_I460=y +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +# CONFIG_AGP_SWORKS is not set +CONFIG_DRM=y +# CONFIG_DRM_NEW is not set +CONFIG_DRM_OLD=y +CONFIG_DRM40_TDFX=y +# CONFIG_DRM40_GAMMA is not set +# CONFIG_DRM40_R128 is not set +# CONFIG_DRM40_RADEON is not set +# CONFIG_DRM40_I810 is not set +# CONFIG_DRM40_MGA is not set # -# USB support +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set + # -# CONFIG_USB is not set +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set # # File systems # # CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS_FS=y # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set -# CONFIG_ISO9660_FS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set -# CONFIG_PROC_FS is not set +CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set -# CONFIG_EXT2_FS is not set +CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_NLS is not set -# CONFIG_NLS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_EFI_PARTITION=y +# CONFIG_DEVFS_GUID is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +CONFIG_SOUND_CS4281=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +CONFIG_USB_UHCI=m +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking # -# CONFIG_IA32_SUPPORT is not set -# CONFIG_MATHEMU is not set -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_IA64_EARLY_PRINTK is not set +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_IA64_PRINT_HAZARDS is not set -# CONFIG_KDB is not set diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index 2068534a8f9e..15a9f9b3960e 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -3,10 +3,11 @@ * * Copyright (C) 1999 Arun Sharma * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang + * David Mosberger-Tang * * 06/16/00 A. Mallick initialize csd/ssd/tssd/cflg for ia32_load_state * 04/13/01 D. Mosberger dropped saving tssd in ar.k1---it's not needed + * 09/14/01 D. Mosberger fixed memory management for gdt/tss page */ #include @@ -41,65 +42,59 @@ extern void ia64_elf32_init (struct pt_regs *regs); extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address); +static void elf32_set_personality (void); + #define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) #define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) -#define elf_map elf_map32 +#define elf_map elf32_map +#define SET_PERSONALITY(ex, ibcs2) elf32_set_personality() /* Ugly but avoids duplication */ #include "../../../fs/binfmt_elf.c" -/* Global descriptor table */ -unsigned long *ia32_gdt_table, *ia32_tss; +extern struct page *ia32_shared_page[]; +extern unsigned long *ia32_gdt; struct page * -put_shared_page (struct task_struct * tsk, struct page *page, unsigned long address) +ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int no_share) { - pgd_t * pgd; - pmd_t * pmd; - pte_t * pte; - - if (page_count(page) != 1) - printk("mem_map disagrees with %p at %08lx\n", (void *) page, address); - - pgd = pgd_offset(tsk->mm, address); - - spin_lock(&tsk->mm->page_table_lock); - { - pmd = pmd_alloc(tsk->mm, pgd, address); - if (!pmd) - goto out; - pte = pte_alloc(tsk->mm, pmd, address); - if (!pte) - goto out; - if (!pte_none(*pte)) - goto out; - flush_page_to_ram(page); - set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED))); - } - spin_unlock(&tsk->mm->page_table_lock); - /* no need for flush_tlb */ - return page; + struct page *pg = ia32_shared_page[(address - vma->vm_start)/PAGE_SIZE]; - out: - spin_unlock(&tsk->mm->page_table_lock); - __free_page(page); - return 0; + get_page(pg); + return pg; } +static struct vm_operations_struct ia32_shared_page_vm_ops = { + nopage: ia32_install_shared_page +}; + void ia64_elf32_init (struct pt_regs *regs) { struct vm_area_struct *vma; - int nr; /* * Map GDT and TSS below 4GB, where the processor can find them. We need to map * it with privilege level 3 because the IVE uses non-privileged accesses to these * tables. IA-32 segmentation is used to protect against IA-32 accesses to them. */ - put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_GDT_OFFSET); - if (PAGE_SHIFT <= IA32_PAGE_SHIFT) - put_shared_page(current, virt_to_page(ia32_tss), IA32_TSS_OFFSET); + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + vma->vm_mm = current->mm; + vma->vm_start = IA32_GDT_OFFSET; + vma->vm_end = vma->vm_start + max(PAGE_SIZE, 2*IA32_PAGE_SIZE); + vma->vm_page_prot = PAGE_SHARED; + vma->vm_flags = VM_READ|VM_MAYREAD; + vma->vm_ops = &ia32_shared_page_vm_ops; + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + down_write(¤t->mm->mmap_sem); + { + insert_vm_struct(current->mm, vma); + } + up_write(¤t->mm->mmap_sem); + } /* * Install LDT as anonymous memory. This gives us all-zero segment descriptors @@ -116,34 +111,13 @@ ia64_elf32_init (struct pt_regs *regs) vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; - insert_vm_struct(current->mm, vma); + down_write(¤t->mm->mmap_sem); + { + insert_vm_struct(current->mm, vma); + } + up_write(¤t->mm->mmap_sem); } - nr = smp_processor_id(); - - current->thread.map_base = IA32_PAGE_OFFSET/3; - current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */ - set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ - - /* Setup the segment selectors */ - regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */ - regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */ - - /* Setup the segment descriptors */ - regs->r24 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); /* ESD */ - regs->r27 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); /* DSD */ - regs->r28 = 0; /* FSD (null) */ - regs->r29 = 0; /* GSD (null) */ - regs->r30 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_LDT(nr)]); /* LDTD */ - - /* - * Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor - * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32 - * architecture manual. - */ - regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0, - 0, 0, 0, 0, 0, 0)); - ia64_psr(regs)->ac = 0; /* turn off alignment checking */ regs->loadrs = 0; /* @@ -164,10 +138,19 @@ ia64_elf32_init (struct pt_regs *regs) current->thread.fcr = IA32_FCR_DEFAULT; current->thread.fir = 0; current->thread.fdr = 0; - current->thread.csd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_CS >> 3]); - current->thread.ssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); - current->thread.tssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_TSS(nr)]); + /* + * Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor + * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32 + * architecture manual. + */ + regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0, + 0, 0, 0, 0, 0, 0)); + /* Setup the segment selectors */ + regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */ + + ia32_load_segment_descriptors(current); ia32_load_state(current); } @@ -189,6 +172,7 @@ ia32_setup_arg_pages (struct linux_binprm *bprm) if (!mpnt) return -ENOMEM; + down_write(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; @@ -204,54 +188,32 @@ ia32_setup_arg_pages (struct linux_binprm *bprm) } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - if (bprm->page[i]) { - put_dirty_page(current,bprm->page[i],stack_base); + struct page *page = bprm->page[i]; + if (page) { + bprm->page[i] = NULL; + put_dirty_page(current, page, stack_base); } stack_base += PAGE_SIZE; } + up_write(¤t->mm->mmap_sem); return 0; } -static unsigned long -ia32_mm_addr (unsigned long addr) +static void +elf32_set_personality (void) { - struct vm_area_struct *vma; - - if ((vma = find_vma(current->mm, addr)) == NULL) - return ELF_PAGESTART(addr); - if (vma->vm_start > addr) - return ELF_PAGESTART(addr); - return ELF_PAGEALIGN(addr); + set_personality(PER_LINUX32); + current->thread.map_base = IA32_PAGE_OFFSET/3; + current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */ + set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ } -/* - * Normally we would do an `mmap' to map in the process's text section. - * This doesn't work with IA32 processes as the ELF file might specify - * a non page size aligned address. Instead we will just allocate - * memory and read the data in from the file. Slightly less efficient - * but it works. - */ -extern long ia32_do_mmap (struct file *filep, unsigned int len, unsigned int prot, - unsigned int flags, unsigned int fd, unsigned int offset); - static unsigned long -elf_map32 (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) { - unsigned long retval; + unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK; - if (eppnt->p_memsz >= (1UL<<32) || addr > (1UL<<32) - eppnt->p_memsz) - return -EINVAL; - - /* - * Make sure the elf interpreter doesn't get loaded at location 0 - * so that NULL pointers correctly cause segfaults. - */ - if (addr == 0) - addr += PAGE_SIZE; - set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz); - memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz); - kernel_read(filep, eppnt->p_offset, (char *) addr, eppnt->p_filesz); - retval = (unsigned long) addr; - return retval; + return ia32_do_mmap(filep, (addr & IA32_PAGE_MASK), eppnt->p_filesz + pgoff, prot, type, + eppnt->p_offset - pgoff); } diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index 5b90ca5c2953..7a85fb8bf263 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -2,7 +2,7 @@ #include #include -#include "../kernel/entry.h" +#include "../kernel/minstate.h" /* * execve() is special because in case of success, we need to @@ -14,13 +14,13 @@ ENTRY(ia32_execve) alloc loc1=ar.pfs,3,2,4,0 mov loc0=rp .body - mov out0=in0 // filename + zxt4 out0=in0 // filename ;; // stop bit between alloc and call - mov out1=in1 // argv - mov out2=in2 // envp + zxt4 out1=in1 // argv + zxt4 out2=in2 // envp add out3=16,sp // regs br.call.sptk.few rp=sys32_execve -1: cmp4.ge p6,p0=r8,r0 +1: cmp.ge p6,p0=r8,r0 mov ar.pfs=loc1 // restore ar.pfs ;; (p6) mov ar.pfs=r0 // clear ar.pfs in case of success @@ -29,31 +29,80 @@ ENTRY(ia32_execve) br.ret.sptk.few rp END(ia32_execve) - // - // Get possibly unaligned sigmask argument into an aligned - // kernel buffer -GLOBAL_ENTRY(ia32_rt_sigsuspend) - // We'll cheat and not do an alloc here since we are ultimately - // going to do a simple branch to the IA64 sys_rt_sigsuspend. - // r32 is still the first argument which is the signal mask. - // We copy this 4-byte aligned value to an 8-byte aligned buffer - // in the task structure and then jump to the IA64 code. +ENTRY(ia32_clone) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + alloc r16=ar.pfs,2,2,4,0 + DO_SAVE_SWITCH_STACK + mov loc0=rp + mov loc1=r16 // save ar.pfs across do_fork + .body + zxt4 out1=in1 // newsp + mov out3=0 // stacksize + adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s + zxt4 out0=in0 // out0 = clone_flags + br.call.sptk.many rp=do_fork +.ret0: .restore sp + adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack + mov ar.pfs=loc1 + mov rp=loc0 + br.ret.sptk.many rp +END(ia32_clone) - EX(.Lfail, ld4 r2=[r32],4) // load low part of sigmask - ;; - EX(.Lfail, ld4 r3=[r32]) // load high part of sigmask - adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13 - ;; - st8 [r32]=r2 - adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13 +ENTRY(sys32_rt_sigsuspend) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs + mov loc0=rp + mov out0=in0 // mask + mov out1=in1 // sigsetsize + mov out2=sp // out2 = &sigscratch + .fframe 16 + adds sp=-16,sp // allocate dummy "sigscratch" ;; + .body + br.call.sptk.many rp=ia32_rt_sigsuspend +1: .restore sp + adds sp=16,sp + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp +END(sys32_rt_sigsuspend) - st4 [r10]=r3 - br.cond.sptk.many sys_rt_sigsuspend - -.Lfail: br.ret.sptk.many rp // failed to read sigmask -END(ia32_rt_sigsuspend) +ENTRY(sys32_sigsuspend) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs + mov loc0=rp + mov out0=in2 // mask (first two args are ignored) + ;; + mov out1=sp // out1 = &sigscratch + .fframe 16 + adds sp=-16,sp // allocate dummy "sigscratch" + .body + br.call.sptk.many rp=ia32_sigsuspend +1: .restore sp + adds sp=16,sp + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp +END(sys32_sigsuspend) +GLOBAL_ENTRY(ia32_ret_from_clone) + PT_REGS_UNWIND_INFO(0) + /* + * We need to call schedule_tail() to complete the scheduling process. + * Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the + * address of the previously executing task. + */ + br.call.sptk.many rp=ia64_invoke_schedule_tail +.ret1: adds r2=IA64_TASK_PTRACE_OFFSET,r13 + ;; + ld8 r2=[r2] + ;; + mov r8=0 + tbit.nz p6,p0=r2,PT_TRACESYS_BIT +(p6) br.cond.spnt .ia32_strace_check_retval + ;; // prevent RAW on r8 +END(ia32_ret_from_clone) + // fall thrugh GLOBAL_ENTRY(ia32_ret_from_syscall) PT_REGS_UNWIND_INFO(0) @@ -72,20 +121,25 @@ END(ia32_ret_from_syscall) // manipulate ar.pfs. // // Input: - // r15 = syscall number - // b6 = syscall entry point + // r8 = syscall number + // b6 = syscall entry point // GLOBAL_ENTRY(ia32_trace_syscall) PT_REGS_UNWIND_INFO(0) + mov r3=-38 + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp + ;; + st8 [r2]=r3 // initialize return code to -ENOSYS br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args -.ret0: br.call.sptk.few rp=b6 // do the syscall -.ret1: cmp.lt p6,p0=r8,r0 // syscall failed? +.ret2: br.call.sptk.few rp=b6 // do the syscall +.ia32_strace_check_retval: + cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 ;; st8.spill [r2]=r8 // store return value in slot for r8 br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value -.ret2: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame - br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! +.ret4: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame + br.cond.sptk.many ia64_leave_kernel END(ia32_trace_syscall) GLOBAL_ENTRY(sys32_vfork) @@ -110,7 +164,7 @@ GLOBAL_ENTRY(sys32_fork) mov out3=0 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s br.call.sptk.few rp=do_fork -.ret3: mov ar.pfs=loc1 +.ret5: mov ar.pfs=loc1 .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov rp=loc0 @@ -137,21 +191,21 @@ ia32_syscall_table: data8 sys32_time data8 sys_mknod data8 sys_chmod /* 15 */ - data8 sys_lchown + data8 sys_lchown /* 16-bit version */ data8 sys32_ni_syscall /* old break syscall holder */ data8 sys32_ni_syscall data8 sys32_lseek data8 sys_getpid /* 20 */ data8 sys_mount data8 sys_oldumount - data8 sys_setuid - data8 sys_getuid + data8 sys_setuid /* 16-bit version */ + data8 sys_getuid /* 16-bit version */ data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ data8 sys32_ptrace data8 sys32_alarm data8 sys32_ni_syscall - data8 sys_pause - data8 ia32_utime /* 30 */ + data8 sys32_pause + data8 sys32_utime /* 30 */ data8 sys32_ni_syscall /* old stty syscall holder */ data8 sys32_ni_syscall /* old gtty syscall holder */ data8 sys_access @@ -167,15 +221,15 @@ ia32_syscall_table: data8 sys32_times data8 sys32_ni_syscall /* old prof syscall holder */ data8 sys_brk /* 45 */ - data8 sys_setgid - data8 sys_getgid + data8 sys_setgid /* 16-bit version */ + data8 sys_getgid /* 16-bit version */ data8 sys32_signal - data8 sys_geteuid - data8 sys_getegid /* 50 */ + data8 sys_geteuid /* 16-bit version */ + data8 sys_getegid /* 16-bit version */ /* 50 */ data8 sys_acct data8 sys_umount /* recycled never used phys( */ data8 sys32_ni_syscall /* old lock syscall holder */ - data8 ia32_ioctl + data8 sys32_ioctl data8 sys32_fcntl /* 55 */ data8 sys32_ni_syscall /* old mpx syscall holder */ data8 sys_setpgid @@ -191,19 +245,19 @@ ia32_syscall_table: data8 sys32_sigaction data8 sys32_ni_syscall data8 sys32_ni_syscall - data8 sys_setreuid /* 70 */ - data8 sys_setregid - data8 sys32_ni_syscall - data8 sys_sigpending + data8 sys_setreuid /* 16-bit version */ /* 70 */ + data8 sys_setregid /* 16-bit version */ + data8 sys32_sigsuspend + data8 sys32_sigpending data8 sys_sethostname data8 sys32_setrlimit /* 75 */ - data8 sys32_getrlimit + data8 sys32_old_getrlimit data8 sys32_getrusage data8 sys32_gettimeofday data8 sys32_settimeofday - data8 sys_getgroups /* 80 */ - data8 sys_setgroups - data8 old_select + data8 sys32_getgroups16 /* 80 */ + data8 sys32_setgroups16 + data8 sys32_old_select data8 sys_symlink data8 sys32_ni_syscall data8 sys_readlink /* 85 */ @@ -212,17 +266,17 @@ ia32_syscall_table: data8 sys_reboot data8 sys32_readdir data8 sys32_mmap /* 90 */ - data8 sys_munmap + data8 sys32_munmap data8 sys_truncate data8 sys_ftruncate data8 sys_fchmod - data8 sys_fchown /* 95 */ + data8 sys_fchown /* 16-bit version */ /* 95 */ data8 sys_getpriority data8 sys_setpriority data8 sys32_ni_syscall /* old profil syscall holder */ data8 sys32_statfs data8 sys32_fstatfs /* 100 */ - data8 sys_ioperm + data8 sys32_ioperm data8 sys32_socketcall data8 sys_syslog data8 sys32_setitimer @@ -231,36 +285,36 @@ ia32_syscall_table: data8 sys32_newlstat data8 sys32_newfstat data8 sys32_ni_syscall - data8 sys_iopl /* 110 */ + data8 sys32_iopl /* 110 */ data8 sys_vhangup data8 sys32_ni_syscall /* used to be sys_idle */ data8 sys32_ni_syscall data8 sys32_wait4 data8 sys_swapoff /* 115 */ - data8 sys_sysinfo + data8 sys32_sysinfo data8 sys32_ipc data8 sys_fsync data8 sys32_sigreturn - data8 sys_clone /* 120 */ + data8 ia32_clone /* 120 */ data8 sys_setdomainname data8 sys32_newuname data8 sys32_modify_ldt - data8 sys_adjtimex + data8 sys32_ni_syscall /* adjtimex */ data8 sys32_mprotect /* 125 */ - data8 sys_sigprocmask - data8 sys_create_module - data8 sys_init_module - data8 sys_delete_module - data8 sys_get_kernel_syms /* 130 */ - data8 sys_quotactl + data8 sys32_sigprocmask + data8 sys32_ni_syscall /* create_module */ + data8 sys32_ni_syscall /* init_module */ + data8 sys32_ni_syscall /* delete_module */ + data8 sys32_ni_syscall /* get_kernel_syms */ /* 130 */ + data8 sys32_quotactl data8 sys_getpgid data8 sys_fchdir - data8 sys_bdflush - data8 sys_sysfs /* 135 */ - data8 sys_personality + data8 sys32_ni_syscall /* sys_bdflush */ + data8 sys_sysfs /* 135 */ + data8 sys32_personality data8 sys32_ni_syscall /* for afs_syscall */ - data8 sys_setfsuid - data8 sys_setfsgid + data8 sys_setfsuid /* 16-bit version */ + data8 sys_setfsgid /* 16-bit version */ data8 sys_llseek /* 140 */ data8 sys32_getdents data8 sys32_select @@ -282,68 +336,75 @@ ia32_syscall_table: data8 sys_sched_yield data8 sys_sched_get_priority_max data8 sys_sched_get_priority_min /* 160 */ - data8 sys_sched_rr_get_interval + data8 sys32_sched_rr_get_interval data8 sys32_nanosleep data8 sys_mremap - data8 sys_setresuid - data8 sys32_getresuid /* 165 */ - data8 sys_vm86 - data8 sys_query_module + data8 sys_setresuid /* 16-bit version */ + data8 sys32_getresuid16 /* 16-bit version */ /* 165 */ + data8 sys32_ni_syscall /* vm86 */ + data8 sys32_ni_syscall /* sys_query_module */ data8 sys_poll - data8 sys_nfsservctl + data8 sys32_ni_syscall /* nfsservctl */ data8 sys_setresgid /* 170 */ - data8 sys32_getresgid + data8 sys32_getresgid16 data8 sys_prctl data8 sys32_rt_sigreturn data8 sys32_rt_sigaction data8 sys32_rt_sigprocmask /* 175 */ data8 sys_rt_sigpending - data8 sys_rt_sigtimedwait - data8 sys_rt_sigqueueinfo - data8 ia32_rt_sigsuspend - data8 sys_pread /* 180 */ - data8 sys_pwrite - data8 sys_chown + data8 sys32_rt_sigtimedwait + data8 sys32_rt_sigqueueinfo + data8 sys32_rt_sigsuspend + data8 sys32_pread /* 180 */ + data8 sys32_pwrite + data8 sys_chown /* 16-bit version */ data8 sys_getcwd data8 sys_capget data8 sys_capset /* 185 */ data8 sys32_sigaltstack - data8 sys_sendfile + data8 sys32_sendfile data8 sys32_ni_syscall /* streams1 */ data8 sys32_ni_syscall /* streams2 */ data8 sys32_vfork /* 190 */ + data8 sys32_getrlimit + data8 sys32_mmap2 + data8 sys32_truncate64 + data8 sys32_ftruncate64 + data8 sys32_stat64 /* 195 */ + data8 sys32_lstat64 + data8 sys32_fstat64 + data8 sys_lchown + data8 sys_getuid + data8 sys_getgid /* 200 */ + data8 sys_geteuid + data8 sys_getegid + data8 sys_setreuid + data8 sys_setregid + data8 sys_getgroups /* 205 */ + data8 sys_setgroups + data8 sys_fchown + data8 sys_setresuid + data8 sys_getresuid + data8 sys_setresgid /* 210 */ + data8 sys_getresgid + data8 sys_chown + data8 sys_setuid + data8 sys_setgid + data8 sys_setfsuid /* 215 */ + data8 sys_setfsgid + data8 sys_pivot_root + data8 sys_mincore + data8 sys_madvise + data8 sys_getdents64 /* 220 */ + data8 sys32_fcntl64 + data8 sys_ni_syscall /* reserved for TUX */ + data8 sys_ni_syscall /* reserved for Security */ + data8 sys_gettid + data8 sys_readahead /* 225 */ data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall - data8 sys_ni_syscall /* 195 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 200 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 205 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 210 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 215 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 220 */ - data8 sys_ni_syscall - data8 sys_ni_syscall /* * CAUTION: If any system calls are added beyond this point * then the check in `arch/ia64/kernel/ivt.S' will have diff --git a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c index f9093e952e20..a73a2c9e7f10 100644 --- a/arch/ia64/ia32/ia32_ioctl.c +++ b/arch/ia64/ia32/ia32_ioctl.c @@ -3,6 +3,8 @@ * * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger + * Copyright (C) 2001 Hewlett-Packard Co + * David Mosberger-Tang */ #include @@ -22,8 +24,12 @@ #include #include #include + +#include + #include <../drivers/char/drm/drm.h> + #define IOCTL_NR(a) ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) #define DO_IOCTL(fd, cmd, arg) ({ \ @@ -36,179 +42,200 @@ _ret; \ }) -#define P(i) ((void *)(long)(i)) - +#define P(i) ((void *)(unsigned long)(i)) asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); -asmlinkage long ia32_ioctl(unsigned int fd, unsigned int cmd, unsigned int arg) +static long +put_dirent32 (struct dirent *d, struct linux32_dirent *d32) +{ + size_t namelen = strlen(d->d_name); + + return (put_user(d->d_ino, &d32->d_ino) + || put_user(d->d_off, &d32->d_off) + || put_user(d->d_reclen, &d32->d_reclen) + || copy_to_user(d32->d_name, d->d_name, namelen + 1)); +} + +asmlinkage long +sys32_ioctl (unsigned int fd, unsigned int cmd, unsigned int arg) { long ret; switch (IOCTL_NR(cmd)) { - - case IOCTL_NR(DRM_IOCTL_VERSION): - { - drm_version_t ver; - struct { - int version_major; - int version_minor; - int version_patchlevel; - unsigned int name_len; - unsigned int name; /* pointer */ - unsigned int date_len; - unsigned int date; /* pointer */ - unsigned int desc_len; - unsigned int desc; /* pointer */ - } ver32; - - if (copy_from_user(&ver32, P(arg), sizeof(ver32))) - return -EFAULT; - ver.name_len = ver32.name_len; - ver.name = P(ver32.name); - ver.date_len = ver32.date_len; - ver.date = P(ver32.date); - ver.desc_len = ver32.desc_len; - ver.desc = P(ver32.desc); - ret = DO_IOCTL(fd, cmd, &ver); - if (ret >= 0) { - ver32.version_major = ver.version_major; - ver32.version_minor = ver.version_minor; - ver32.version_patchlevel = ver.version_patchlevel; - ver32.name_len = ver.name_len; - ver32.date_len = ver.date_len; - ver32.desc_len = ver.desc_len; - if (copy_to_user(P(arg), &ver32, sizeof(ver32))) - return -EFAULT; - } - return(ret); - } - - case IOCTL_NR(DRM_IOCTL_GET_UNIQUE): - { - drm_unique_t un; - struct { - unsigned int unique_len; - unsigned int unique; - } un32; - - if (copy_from_user(&un32, P(arg), sizeof(un32))) - return -EFAULT; - un.unique_len = un32.unique_len; - un.unique = P(un32.unique); - ret = DO_IOCTL(fd, cmd, &un); - if (ret >= 0) { - un32.unique_len = un.unique_len; - if (copy_to_user(P(arg), &un32, sizeof(un32))) - return -EFAULT; - } - return(ret); - } - case IOCTL_NR(DRM_IOCTL_SET_UNIQUE): - case IOCTL_NR(DRM_IOCTL_ADD_MAP): - case IOCTL_NR(DRM_IOCTL_ADD_BUFS): - case IOCTL_NR(DRM_IOCTL_MARK_BUFS): - case IOCTL_NR(DRM_IOCTL_INFO_BUFS): - case IOCTL_NR(DRM_IOCTL_MAP_BUFS): - case IOCTL_NR(DRM_IOCTL_FREE_BUFS): - case IOCTL_NR(DRM_IOCTL_ADD_CTX): - case IOCTL_NR(DRM_IOCTL_RM_CTX): - case IOCTL_NR(DRM_IOCTL_MOD_CTX): - case IOCTL_NR(DRM_IOCTL_GET_CTX): - case IOCTL_NR(DRM_IOCTL_SWITCH_CTX): - case IOCTL_NR(DRM_IOCTL_NEW_CTX): - case IOCTL_NR(DRM_IOCTL_RES_CTX): - - case IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE): - case IOCTL_NR(DRM_IOCTL_AGP_RELEASE): - case IOCTL_NR(DRM_IOCTL_AGP_ENABLE): - case IOCTL_NR(DRM_IOCTL_AGP_INFO): - case IOCTL_NR(DRM_IOCTL_AGP_ALLOC): - case IOCTL_NR(DRM_IOCTL_AGP_FREE): - case IOCTL_NR(DRM_IOCTL_AGP_BIND): - case IOCTL_NR(DRM_IOCTL_AGP_UNBIND): - - /* Mga specific ioctls */ - - case IOCTL_NR(DRM_IOCTL_MGA_INIT): - - /* I810 specific ioctls */ - - case IOCTL_NR(DRM_IOCTL_I810_GETBUF): - case IOCTL_NR(DRM_IOCTL_I810_COPY): - - /* Rage 128 specific ioctls */ - - case IOCTL_NR(DRM_IOCTL_R128_PACKET): - - case IOCTL_NR(VFAT_IOCTL_READDIR_BOTH): - case IOCTL_NR(VFAT_IOCTL_READDIR_SHORT): - case IOCTL_NR(MTIOCGET): - case IOCTL_NR(MTIOCPOS): - case IOCTL_NR(MTIOCGETCONFIG): - case IOCTL_NR(MTIOCSETCONFIG): - case IOCTL_NR(PPPIOCSCOMPRESS): - case IOCTL_NR(PPPIOCGIDLE): - case IOCTL_NR(NCP_IOC_GET_FS_INFO_V2): - case IOCTL_NR(NCP_IOC_GETOBJECTNAME): - case IOCTL_NR(NCP_IOC_SETOBJECTNAME): - case IOCTL_NR(NCP_IOC_GETPRIVATEDATA): - case IOCTL_NR(NCP_IOC_SETPRIVATEDATA): - case IOCTL_NR(NCP_IOC_GETMOUNTUID2): - case IOCTL_NR(CAPI_MANUFACTURER_CMD): - case IOCTL_NR(VIDIOCGTUNER): - case IOCTL_NR(VIDIOCSTUNER): - case IOCTL_NR(VIDIOCGWIN): - case IOCTL_NR(VIDIOCSWIN): - case IOCTL_NR(VIDIOCGFBUF): - case IOCTL_NR(VIDIOCSFBUF): - case IOCTL_NR(MGSL_IOCSPARAMS): - case IOCTL_NR(MGSL_IOCGPARAMS): - case IOCTL_NR(ATM_GETNAMES): - case IOCTL_NR(ATM_GETLINKRATE): - case IOCTL_NR(ATM_GETTYPE): - case IOCTL_NR(ATM_GETESI): - case IOCTL_NR(ATM_GETADDR): - case IOCTL_NR(ATM_RSTADDR): - case IOCTL_NR(ATM_ADDADDR): - case IOCTL_NR(ATM_DELADDR): - case IOCTL_NR(ATM_GETCIRANGE): - case IOCTL_NR(ATM_SETCIRANGE): - case IOCTL_NR(ATM_SETESI): - case IOCTL_NR(ATM_SETESIF): - case IOCTL_NR(ATM_GETSTAT): - case IOCTL_NR(ATM_GETSTATZ): - case IOCTL_NR(ATM_GETLOOP): - case IOCTL_NR(ATM_SETLOOP): - case IOCTL_NR(ATM_QUERYLOOP): - case IOCTL_NR(ENI_SETMULT): - case IOCTL_NR(NS_GETPSTAT): - /* case IOCTL_NR(NS_SETBUFLEV): This is a duplicate case with ZATM_GETPOOLZ */ - case IOCTL_NR(ZATM_GETPOOLZ): - case IOCTL_NR(ZATM_GETPOOL): - case IOCTL_NR(ZATM_SETPOOL): - case IOCTL_NR(ZATM_GETTHIST): - case IOCTL_NR(IDT77105_GETSTAT): - case IOCTL_NR(IDT77105_GETSTATZ): - case IOCTL_NR(IXJCTL_TONE_CADENCE): - case IOCTL_NR(IXJCTL_FRAMES_READ): - case IOCTL_NR(IXJCTL_FRAMES_WRITTEN): - case IOCTL_NR(IXJCTL_READ_WAIT): - case IOCTL_NR(IXJCTL_WRITE_WAIT): - case IOCTL_NR(IXJCTL_DRYBUFFER_READ): - case IOCTL_NR(I2OHRTGET): - case IOCTL_NR(I2OLCTGET): - case IOCTL_NR(I2OPARMSET): - case IOCTL_NR(I2OPARMGET): - case IOCTL_NR(I2OSWDL): - case IOCTL_NR(I2OSWUL): - case IOCTL_NR(I2OSWDEL): - case IOCTL_NR(I2OHTML): + case IOCTL_NR(VFAT_IOCTL_READDIR_SHORT): + case IOCTL_NR(VFAT_IOCTL_READDIR_BOTH): { + struct linux32_dirent *d32 = P(arg); + struct dirent d[2]; + + ret = DO_IOCTL(fd, _IOR('r', _IOC_NR(cmd), + struct dirent [2]), + (unsigned long) d); + if (ret < 0) + return ret; + + if (put_dirent32(d, d32) || put_dirent32(d + 1, d32 + 1)) + return -EFAULT; + + return ret; + } + + case IOCTL_NR(DRM_IOCTL_VERSION): + { + drm_version_t ver; + struct { + int version_major; + int version_minor; + int version_patchlevel; + unsigned int name_len; + unsigned int name; /* pointer */ + unsigned int date_len; + unsigned int date; /* pointer */ + unsigned int desc_len; + unsigned int desc; /* pointer */ + } ver32; + + if (copy_from_user(&ver32, P(arg), sizeof(ver32))) + return -EFAULT; + ver.name_len = ver32.name_len; + ver.name = P(ver32.name); + ver.date_len = ver32.date_len; + ver.date = P(ver32.date); + ver.desc_len = ver32.desc_len; + ver.desc = P(ver32.desc); + ret = DO_IOCTL(fd, DRM_IOCTL_VERSION, &ver); + if (ret >= 0) { + ver32.version_major = ver.version_major; + ver32.version_minor = ver.version_minor; + ver32.version_patchlevel = ver.version_patchlevel; + ver32.name_len = ver.name_len; + ver32.date_len = ver.date_len; + ver32.desc_len = ver.desc_len; + if (copy_to_user(P(arg), &ver32, sizeof(ver32))) + return -EFAULT; + } + return ret; + } + + case IOCTL_NR(DRM_IOCTL_GET_UNIQUE): + { + drm_unique_t un; + struct { + unsigned int unique_len; + unsigned int unique; + } un32; + + if (copy_from_user(&un32, P(arg), sizeof(un32))) + return -EFAULT; + un.unique_len = un32.unique_len; + un.unique = P(un32.unique); + ret = DO_IOCTL(fd, DRM_IOCTL_GET_UNIQUE, &un); + if (ret >= 0) { + un32.unique_len = un.unique_len; + if (copy_to_user(P(arg), &un32, sizeof(un32))) + return -EFAULT; + } + return ret; + } + case IOCTL_NR(DRM_IOCTL_SET_UNIQUE): + case IOCTL_NR(DRM_IOCTL_ADD_MAP): + case IOCTL_NR(DRM_IOCTL_ADD_BUFS): + case IOCTL_NR(DRM_IOCTL_MARK_BUFS): + case IOCTL_NR(DRM_IOCTL_INFO_BUFS): + case IOCTL_NR(DRM_IOCTL_MAP_BUFS): + case IOCTL_NR(DRM_IOCTL_FREE_BUFS): + case IOCTL_NR(DRM_IOCTL_ADD_CTX): + case IOCTL_NR(DRM_IOCTL_RM_CTX): + case IOCTL_NR(DRM_IOCTL_MOD_CTX): + case IOCTL_NR(DRM_IOCTL_GET_CTX): + case IOCTL_NR(DRM_IOCTL_SWITCH_CTX): + case IOCTL_NR(DRM_IOCTL_NEW_CTX): + case IOCTL_NR(DRM_IOCTL_RES_CTX): + + case IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE): + case IOCTL_NR(DRM_IOCTL_AGP_RELEASE): + case IOCTL_NR(DRM_IOCTL_AGP_ENABLE): + case IOCTL_NR(DRM_IOCTL_AGP_INFO): + case IOCTL_NR(DRM_IOCTL_AGP_ALLOC): + case IOCTL_NR(DRM_IOCTL_AGP_FREE): + case IOCTL_NR(DRM_IOCTL_AGP_BIND): + case IOCTL_NR(DRM_IOCTL_AGP_UNBIND): + + /* Mga specific ioctls */ + + case IOCTL_NR(DRM_IOCTL_MGA_INIT): + + /* I810 specific ioctls */ + + case IOCTL_NR(DRM_IOCTL_I810_GETBUF): + case IOCTL_NR(DRM_IOCTL_I810_COPY): + + case IOCTL_NR(MTIOCGET): + case IOCTL_NR(MTIOCPOS): + case IOCTL_NR(MTIOCGETCONFIG): + case IOCTL_NR(MTIOCSETCONFIG): + case IOCTL_NR(PPPIOCSCOMPRESS): + case IOCTL_NR(PPPIOCGIDLE): + case IOCTL_NR(NCP_IOC_GET_FS_INFO_V2): + case IOCTL_NR(NCP_IOC_GETOBJECTNAME): + case IOCTL_NR(NCP_IOC_SETOBJECTNAME): + case IOCTL_NR(NCP_IOC_GETPRIVATEDATA): + case IOCTL_NR(NCP_IOC_SETPRIVATEDATA): + case IOCTL_NR(NCP_IOC_GETMOUNTUID2): + case IOCTL_NR(CAPI_MANUFACTURER_CMD): + case IOCTL_NR(VIDIOCGTUNER): + case IOCTL_NR(VIDIOCSTUNER): + case IOCTL_NR(VIDIOCGWIN): + case IOCTL_NR(VIDIOCSWIN): + case IOCTL_NR(VIDIOCGFBUF): + case IOCTL_NR(VIDIOCSFBUF): + case IOCTL_NR(MGSL_IOCSPARAMS): + case IOCTL_NR(MGSL_IOCGPARAMS): + case IOCTL_NR(ATM_GETNAMES): + case IOCTL_NR(ATM_GETLINKRATE): + case IOCTL_NR(ATM_GETTYPE): + case IOCTL_NR(ATM_GETESI): + case IOCTL_NR(ATM_GETADDR): + case IOCTL_NR(ATM_RSTADDR): + case IOCTL_NR(ATM_ADDADDR): + case IOCTL_NR(ATM_DELADDR): + case IOCTL_NR(ATM_GETCIRANGE): + case IOCTL_NR(ATM_SETCIRANGE): + case IOCTL_NR(ATM_SETESI): + case IOCTL_NR(ATM_SETESIF): + case IOCTL_NR(ATM_GETSTAT): + case IOCTL_NR(ATM_GETSTATZ): + case IOCTL_NR(ATM_GETLOOP): + case IOCTL_NR(ATM_SETLOOP): + case IOCTL_NR(ATM_QUERYLOOP): + case IOCTL_NR(ENI_SETMULT): + case IOCTL_NR(NS_GETPSTAT): + /* case IOCTL_NR(NS_SETBUFLEV): This is a duplicate case with ZATM_GETPOOLZ */ + case IOCTL_NR(ZATM_GETPOOLZ): + case IOCTL_NR(ZATM_GETPOOL): + case IOCTL_NR(ZATM_SETPOOL): + case IOCTL_NR(ZATM_GETTHIST): + case IOCTL_NR(IDT77105_GETSTAT): + case IOCTL_NR(IDT77105_GETSTATZ): + case IOCTL_NR(IXJCTL_TONE_CADENCE): + case IOCTL_NR(IXJCTL_FRAMES_READ): + case IOCTL_NR(IXJCTL_FRAMES_WRITTEN): + case IOCTL_NR(IXJCTL_READ_WAIT): + case IOCTL_NR(IXJCTL_WRITE_WAIT): + case IOCTL_NR(IXJCTL_DRYBUFFER_READ): + case IOCTL_NR(I2OHRTGET): + case IOCTL_NR(I2OLCTGET): + case IOCTL_NR(I2OPARMSET): + case IOCTL_NR(I2OPARMGET): + case IOCTL_NR(I2OSWDL): + case IOCTL_NR(I2OSWUL): + case IOCTL_NR(I2OSWDEL): + case IOCTL_NR(I2OHTML): break; - default: - return(sys_ioctl(fd, cmd, (unsigned long)arg)); + default: + return sys_ioctl(fd, cmd, (unsigned long)arg); } printk("%x:unimplemented IA32 ioctl system call\n", cmd); - return(-EINVAL); + return -EINVAL; } diff --git a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c index 48bf44ceefce..4b0eb73dd441 100644 --- a/arch/ia64/ia32/ia32_ldt.c +++ b/arch/ia64/ia32/ia32_ldt.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang + * David Mosberger-Tang * * Adapted from arch/i386/kernel/ldt.c */ @@ -16,6 +16,8 @@ #include #include +#define P(p) ((void *) (unsigned long) (p)) + /* * read_ldt() is not really atomic - this is not a problem since synchronization of reads * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic, @@ -57,11 +59,31 @@ read_ldt (void *ptr, unsigned long bytecount) return bytecount; } +static int +read_default_ldt (void * ptr, unsigned long bytecount) +{ + unsigned long size; + int err; + + /* XXX fix me: should return equivalent of default_ldt[0] */ + err = 0; + size = 8; + if (size > bytecount) + size = bytecount; + + err = size; + if (clear_user(ptr, size)) + err = -EFAULT; + + return err; +} + static int write_ldt (void * ptr, unsigned long bytecount, int oldmode) { struct ia32_modify_ldt_ldt_s ldt_info; __u64 entry; + int ret; if (bytecount != sizeof(ldt_info)) return -EINVAL; @@ -97,23 +119,28 @@ write_ldt (void * ptr, unsigned long bytecount, int oldmode) * memory, but we still need to guard against out-of-memory, hence we must use * put_user(). */ - return __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number); + ret = __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number); + ia32_load_segment_descriptors(current); + return ret; } asmlinkage int -sys32_modify_ldt (int func, void *ptr, unsigned int bytecount) +sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount) { int ret = -ENOSYS; switch (func) { case 0: - ret = read_ldt(ptr, bytecount); + ret = read_ldt(P(ptr), bytecount); break; case 1: - ret = write_ldt(ptr, bytecount, 1); + ret = write_ldt(P(ptr), bytecount, 1); + break; + case 2: + ret = read_default_ldt(P(ptr), bytecount); break; case 0x11: - ret = write_ldt(ptr, bytecount, 0); + ret = write_ldt(P(ptr), bytecount, 0); break; } return ret; diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c index 7b2a9f3ec40d..09255fc12234 100644 --- a/arch/ia64/ia32/ia32_signal.c +++ b/arch/ia64/ia32/ia32_signal.c @@ -1,8 +1,8 @@ /* * IA32 Architecture-specific signal handling support. * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999, 2001 Hewlett-Packard Co + * David Mosberger-Tang * Copyright (C) 1999 Arun Sharma * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -28,9 +29,15 @@ #include #include +#include "../kernel/sigframe.h" + +#define A(__x) ((unsigned long)(__x)) + #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +#define __IA32_NR_sigreturn 119 +#define __IA32_NR_rt_sigreturn 173 struct sigframe_ia32 { @@ -54,12 +61,51 @@ struct rt_sigframe_ia32 char retcode[8]; }; -static int +int +copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from) +{ + unsigned long tmp; + int err; + + if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t32))) + return -EFAULT; + + err = __get_user(to->si_signo, &from->si_signo); + err |= __get_user(to->si_errno, &from->si_errno); + err |= __get_user(to->si_code, &from->si_code); + + if (from->si_code < 0) + err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); + else { + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __get_user(to->si_utime, &from->si_utime); + err |= __get_user(to->si_stime, &from->si_stime); + err |= __get_user(to->si_status, &from->si_status); + default: + err |= __get_user(to->si_pid, &from->si_pid); + err |= __get_user(to->si_uid, &from->si_uid); + break; + case __SI_FAULT >> 16: + err |= __get_user(tmp, &from->si_addr); + to->si_addr = (void *) tmp; + break; + case __SI_POLL >> 16: + err |= __get_user(to->si_band, &from->si_band); + err |= __get_user(to->si_fd, &from->si_fd); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + } + return err; +} + +int copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) { int err; - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -97,110 +143,329 @@ copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) return err; } +static inline void +sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer) +{ + if (handler + 1 <= 2) + /* SIG_DFL, SIG_IGN, or SIG_ERR: must sign-extend to 64-bits */ + sa->sa.sa_handler = (__sighandler_t) A((int) handler); + else + sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler); +} + +asmlinkage long +ia32_rt_sigsuspend (sigset32_t *uset, unsigned int sigsetsize, struct sigscratch *scr) +{ + extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall); + sigset_t oldset, set; + + scr->scratch_unat = 0; /* avoid leaking kernel bits to user level */ + memset(&set, 0, sizeof(&set)); + + if (sigsetsize > sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&set.sig, &uset->sig, sigsetsize)) + return -EFAULT; + + sigdelsetmask(&set, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + { + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); + } + spin_unlock_irq(¤t->sigmask_lock); + + /* + * The return below usually returns to the signal handler. We need to pre-set the + * correct error code here to ensure that the right values get saved in sigcontext + * by ia64_do_signal. + */ + scr->pt.r8 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (ia64_do_signal(&oldset, scr, 1)) + return -EINTR; + } +} + +asmlinkage long +ia32_sigsuspend (unsigned int mask, struct sigscratch *scr) +{ + return ia32_rt_sigsuspend((sigset32_t *)&mask, sizeof(mask), scr); +} + +asmlinkage long +sys32_signal (int sig, unsigned int handler) +{ + struct k_sigaction new_sa, old_sa; + int ret; + + sigact_set_handler(&new_sa, handler, 0); + new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; + + ret = do_sigaction(sig, &new_sa, &old_sa); + + return ret ? ret : IA32_SA_HANDLER(&old_sa); +} + +asmlinkage long +sys32_rt_sigaction (int sig, struct sigaction32 *act, + struct sigaction32 *oact, unsigned int sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + unsigned int handler, restorer; + int ret; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset32_t)) + return -EINVAL; + + if (act) { + ret = get_user(handler, &act->sa_handler); + ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= get_user(restorer, &act->sa_restorer); + ret |= copy_from_user(&new_ka.sa.sa_mask, &act->sa_mask, sizeof(sigset32_t)); + if (ret) + return -EFAULT; + + sigact_set_handler(&new_ka, handler, restorer); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler); + ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer); + ret |= copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, sizeof(sigset32_t)); + } + return ret; +} + +extern asmlinkage long sys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, + size_t sigsetsize); + +asmlinkage long +sys32_rt_sigprocmask (int how, sigset32_t *set, sigset32_t *oset, unsigned int sigsetsize) +{ + mm_segment_t old_fs = get_fs(); + sigset_t s; + long ret; + + if (sigsetsize > sizeof(s)) + return -EINVAL; + + if (set) { + memset(&s, 0, sizeof(s)); + if (copy_from_user(&s.sig, set, sigsetsize)) + return -EFAULT; + } + set_fs(KERNEL_DS); + ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sizeof(s)); + set_fs(old_fs); + if (ret) + return ret; + if (oset) { + if (copy_to_user(oset, &s.sig, sigsetsize)) + return -EFAULT; + } + return 0; +} + +asmlinkage long +sys32_sigprocmask (int how, unsigned int *set, unsigned int *oset) +{ + return sys32_rt_sigprocmask(how, (sigset32_t *) set, (sigset32_t *) oset, sizeof(*set)); +} + +asmlinkage long +sys32_rt_sigtimedwait (sigset32_t *uthese, siginfo_t32 *uinfo, struct timespec32 *uts, + unsigned int sigsetsize) +{ + extern asmlinkage long sys_rt_sigtimedwait (const sigset_t *, siginfo_t *, + const struct timespec *, size_t); + extern int copy_siginfo_to_user32 (siginfo_t32 *, siginfo_t *); + mm_segment_t old_fs = get_fs(); + struct timespec t; + siginfo_t info; + sigset_t s; + int ret; + + if (copy_from_user(&s.sig, uthese, sizeof(sigset32_t))) + return -EFAULT; + if (uts) { + ret = get_user(t.tv_sec, &uts->tv_sec); + ret |= get_user(t.tv_nsec, &uts->tv_nsec); + if (ret) + return -EFAULT; + } + set_fs(KERNEL_DS); + ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); + set_fs(old_fs); + if (ret >= 0 && uinfo) { + if (copy_siginfo_to_user32(uinfo, &info)) + return -EFAULT; + } + return ret; +} + +asmlinkage long +sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo) +{ + extern asmlinkage long sys_rt_sigqueueinfo (int, int, siginfo_t *); + extern int copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from); + mm_segment_t old_fs = get_fs(); + siginfo_t info; + int ret; + + if (copy_siginfo_from_user32(&info, uinfo)) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_rt_sigqueueinfo(pid, sig, &info); + set_fs(old_fs); + return ret; +} + +asmlinkage long +sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) +{ + struct k_sigaction new_ka, old_ka; + unsigned int handler, restorer; + int ret; + + if (act) { + old_sigset32_t mask; + + ret = get_user(handler, &act->sa_handler); + ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= get_user(restorer, &act->sa_restorer); + ret |= get_user(mask, &act->sa_mask); + if (ret) + return ret; + + sigact_set_handler(&new_ka, handler, restorer); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler); + ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer); + ret |= put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} static int -setup_sigcontext_ia32(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, - struct pt_regs *regs, unsigned long mask) +setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, + struct pt_regs *regs, unsigned long mask) { - int err = 0; - unsigned long flag; - - err |= __put_user((regs->r16 >> 32) & 0xffff , (unsigned int *)&sc->fs); - err |= __put_user((regs->r16 >> 48) & 0xffff , (unsigned int *)&sc->gs); - - err |= __put_user((regs->r16 >> 56) & 0xffff, (unsigned int *)&sc->es); - err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds); - err |= __put_user(regs->r15, &sc->edi); - err |= __put_user(regs->r14, &sc->esi); - err |= __put_user(regs->r13, &sc->ebp); - err |= __put_user(regs->r12, &sc->esp); - err |= __put_user(regs->r11, &sc->ebx); - err |= __put_user(regs->r10, &sc->edx); - err |= __put_user(regs->r9, &sc->ecx); - err |= __put_user(regs->r8, &sc->eax); + int err = 0; + unsigned long flag; + + err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs); + err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs); + err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es); + err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds); + err |= __put_user(regs->r15, &sc->edi); + err |= __put_user(regs->r14, &sc->esi); + err |= __put_user(regs->r13, &sc->ebp); + err |= __put_user(regs->r12, &sc->esp); + err |= __put_user(regs->r11, &sc->ebx); + err |= __put_user(regs->r10, &sc->edx); + err |= __put_user(regs->r9, &sc->ecx); + err |= __put_user(regs->r8, &sc->eax); #if 0 - err |= __put_user(current->tss.trap_no, &sc->trapno); - err |= __put_user(current->tss.error_code, &sc->err); + err |= __put_user(current->tss.trap_no, &sc->trapno); + err |= __put_user(current->tss.error_code, &sc->err); #endif - err |= __put_user(regs->cr_iip, &sc->eip); - err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs); - /* - * `eflags' is in an ar register for this context - */ - asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag)); - err |= __put_user((unsigned int)flag, &sc->eflags); - - err |= __put_user(regs->r12, &sc->esp_at_signal); - err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); + err |= __put_user(regs->cr_iip, &sc->eip); + err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs); + /* + * `eflags' is in an ar register for this context + */ + asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag)); + err |= __put_user((unsigned int)flag, &sc->eflags); + err |= __put_user(regs->r12, &sc->esp_at_signal); + err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); #if 0 - tmp = save_i387(fpstate); - if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + tmp = save_i387(fpstate); + if (tmp < 0) + err = 1; + else + err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); - /* non-iBCS2 extensions.. */ + /* non-iBCS2 extensions.. */ #endif - err |= __put_user(mask, &sc->oldmask); + err |= __put_user(mask, &sc->oldmask); #if 0 - err |= __put_user(current->tss.cr2, &sc->cr2); + err |= __put_user(current->tss.cr2, &sc->cr2); #endif - - return err; + return err; } static int -restore_sigcontext_ia32(struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax) +restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax) { - unsigned int err = 0; - -#define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) - -#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) tmp << 48) -#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) tmp << 32) -#define copyseg_cs(tmp) (regs->r17 |= tmp) -#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) tmp << 16) -#define copyseg_es(tmp) (regs->r16 |= (unsigned long) tmp << 16) -#define copyseg_ds(tmp) (regs->r16 |= tmp) - -#define COPY_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ - copyseg_##seg(tmp); } - -#define COPY_SEG_STRICT(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ - copyseg_##seg(tmp|3); } - - /* To make COPY_SEGs easier, we zero r16, r17 */ - regs->r16 = 0; - regs->r17 = 0; - - COPY_SEG(gs); - COPY_SEG(fs); - COPY_SEG(es); - COPY_SEG(ds); - COPY(r15, edi); - COPY(r14, esi); - COPY(r13, ebp); - COPY(r12, esp); - COPY(r11, ebx); - COPY(r10, edx); - COPY(r9, ecx); - COPY(cr_iip, eip); - COPY_SEG_STRICT(cs); - COPY_SEG_STRICT(ss); - { + unsigned int err = 0; + +#define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) + +#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) tmp << 48) +#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) tmp << 32) +#define copyseg_cs(tmp) (regs->r17 |= tmp) +#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) tmp << 16) +#define copyseg_es(tmp) (regs->r16 |= (unsigned long) tmp << 16) +#define copyseg_ds(tmp) (regs->r16 |= tmp) + +#define COPY_SEG(seg) \ + { \ + unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + copyseg_##seg(tmp); \ + } +#define COPY_SEG_STRICT(seg) \ + { \ + unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + copyseg_##seg(tmp|3); \ + } + + /* To make COPY_SEGs easier, we zero r16, r17 */ + regs->r16 = 0; + regs->r17 = 0; + + COPY_SEG(gs); + COPY_SEG(fs); + COPY_SEG(es); + COPY_SEG(ds); + COPY(r15, edi); + COPY(r14, esi); + COPY(r13, ebp); + COPY(r12, esp); + COPY(r11, ebx); + COPY(r10, edx); + COPY(r9, ecx); + COPY(cr_iip, eip); + COPY_SEG_STRICT(cs); + COPY_SEG_STRICT(ss); + ia32_load_segment_descriptors(current); + { unsigned int tmpflags; unsigned long flag; /* - * IA32 `eflags' is not part of `pt_regs', it's - * in an ar register which is part of the thread - * context. Fortunately, we are executing in the + * IA32 `eflags' is not part of `pt_regs', it's in an ar register which + * is part of the thread context. Fortunately, we are executing in the * IA32 process's context. */ err |= __get_user(tmpflags, &sc->eflags); @@ -210,186 +475,191 @@ restore_sigcontext_ia32(struct pt_regs *regs, struct sigcontext_ia32 *sc, int *p asm volatile ("mov ar.eflag=%0 ;;" :: "r"(flag)); regs->r1 = -1; /* disable syscall checks, r1 is orig_eax */ - } + } #if 0 - { - struct _fpstate * buf; - err |= __get_user(buf, &sc->fpstate); - if (buf) { - if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_i387(buf); - } - } + { + struct _fpstate * buf; + err |= __get_user(buf, &sc->fpstate); + if (buf) { + if (verify_area(VERIFY_READ, buf, sizeof(*buf))) + goto badframe; + err |= restore_i387(buf); + } + } #endif - err |= __get_user(*peax, &sc->eax); - return err; + err |= __get_user(*peax, &sc->eax); + return err; -#if 0 -badframe: - return 1; +#if 0 + badframe: + return 1; #endif - } /* * Determine which stack to use.. */ static inline void * -get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) +get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { - unsigned long esp; - unsigned int xss; - - /* Default to using normal stack */ - esp = regs->r12; - xss = regs->r16 >> 16; - - /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & SA_ONSTACK) { - if (! on_sig_stack(esp)) - esp = current->sas_ss_sp + current->sas_ss_size; - } - /* Legacy stack switching not supported */ - - return (void *)((esp - frame_size) & -8ul); + unsigned long esp; + + /* Default to using normal stack (truncate off sign-extension of bit 31: */ + esp = (unsigned int) regs->r12; + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!on_sig_stack(esp)) + esp = current->sas_ss_sp + current->sas_ss_size; + } + /* Legacy stack switching not supported */ + + return (void *)((esp - frame_size) & -8ul); } static int -setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set, - struct pt_regs * regs) -{ - struct sigframe_ia32 *frame; - int err = 0; - - frame = get_sigframe(ka, regs, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - err |= __put_user((current->exec_domain - && current->exec_domain->signal_invmap - && sig < 32 - ? (int)(current->exec_domain->signal_invmap[sig]) - : sig), - &frame->sig); - - err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); - - if (_IA32_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); - } - - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ - err |= __put_user((long)frame->retcode, &frame->pretcode); - /* This is popl %eax ; movl $,%eax ; int $0x80 */ - err |= __put_user(0xb858, (short *)(frame->retcode+0)); -#define __IA32_NR_sigreturn 119 - err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2)); - err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4)); - err |= __put_user(0x80cd, (short *)(frame->retcode+6)); +setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) +{ + struct sigframe_ia32 *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? (int)(current->exec_domain->signal_invmap[sig]) + : sig), + &frame->sig); + + err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); + + if (_IA32_NSIG_WORDS > 1) + err |= __copy_to_user(frame->extramask, (char *) &set->sig + 4, + sizeof(frame->extramask)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + unsigned int restorer = IA32_SA_RESTORER(ka); + err |= __put_user(restorer, &frame->pretcode); + } else { + err |= __put_user((long)frame->retcode, &frame->pretcode); + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + err |= __put_user(0xb858, (short *)(frame->retcode+0)); + err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2)); + err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4)); + err |= __put_user(0x80cd, (short *)(frame->retcode+6)); + } - if (err) - goto give_sigsegv; + if (err) + goto give_sigsegv; - /* Set up registers for signal handler */ - regs->r12 = (unsigned long) frame; - regs->cr_iip = (unsigned long) ka->sa.sa_handler; + /* Set up registers for signal handler */ + regs->r12 = (unsigned long) frame; + regs->cr_iip = IA32_SA_HANDLER(ka); - set_fs(USER_DS); - regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ - regs->r17 = (__USER_DS << 16) | __USER_CS; + set_fs(USER_DS); + regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; #if 0 - regs->eflags &= ~TF_MASK; + regs->eflags &= ~TF_MASK; #endif #if 0 - printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n", + printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n", current->comm, current->pid, sig, (void *) frame, regs->cr_iip, frame->pretcode); #endif - return 1; + return 1; -give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); - return 0; + give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); + return 0; } static int -setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs * regs) +setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs * regs) { - struct rt_sigframe_ia32 *frame; - int err = 0; - - frame = get_sigframe(ka, regs, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - err |= __put_user((current->exec_domain - && current->exec_domain->signal_invmap - && sig < 32 - ? current->exec_domain->signal_invmap[sig] - : sig), - &frame->sig); - err |= __put_user((long)&frame->info, &frame->pinfo); - err |= __put_user((long)&frame->uc, &frame->puc); - err |= copy_siginfo_to_user32(&frame->info, info); - - /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(regs->r12), - &frame->uc.uc_stack.ss_flags); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, - regs, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - - err |= __put_user((long)frame->retcode, &frame->pretcode); - /* This is movl $,%eax ; int $0x80 */ - err |= __put_user(0xb8, (char *)(frame->retcode+0)); -#define __IA32_NR_rt_sigreturn 173 - err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1)); - err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + struct rt_sigframe_ia32 *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + err |= __put_user((long)&frame->info, &frame->pinfo); + err |= __put_user((long)&frame->uc, &frame->puc); + err |= copy_siginfo_to_user32(&frame->info, info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->r12), &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + unsigned int restorer = IA32_SA_RESTORER(ka); + err |= __put_user(restorer, &frame->pretcode); + } else { + err |= __put_user((long)frame->retcode, &frame->pretcode); + /* This is movl $,%eax ; int $0x80 */ + err |= __put_user(0xb8, (char *)(frame->retcode+0)); + err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + } - if (err) - goto give_sigsegv; + if (err) + goto give_sigsegv; - /* Set up registers for signal handler */ - regs->r12 = (unsigned long) frame; - regs->cr_iip = (unsigned long) ka->sa.sa_handler; + /* Set up registers for signal handler */ + regs->r12 = (unsigned long) frame; + regs->cr_iip = IA32_SA_HANDLER(ka); - set_fs(USER_DS); + set_fs(USER_DS); - regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ - regs->r17 = (__USER_DS << 16) | __USER_CS; + regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; #if 0 - regs->eflags &= ~TF_MASK; + regs->eflags &= ~TF_MASK; #endif #if 0 - printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", + printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", current->comm, current->pid, (void *) frame, regs->cr_iip, frame->pretcode); #endif - return 1; + return 1; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); - return 0; + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); + return 0; } int @@ -398,95 +668,78 @@ ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, { /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) - return(setup_rt_frame_ia32(sig, ka, info, set, regs)); + return setup_rt_frame_ia32(sig, ka, info, set, regs); else - return(setup_frame_ia32(sig, ka, set, regs)); + return setup_frame_ia32(sig, ka, set, regs); } -asmlinkage int -sys32_sigreturn( -int arg0, -int arg1, -int arg2, -int arg3, -int arg4, -int arg5, -int arg6, -int arg7, -unsigned long stack) -{ - struct pt_regs *regs = (struct pt_regs *) &stack; - struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(regs->r12- 8); - sigset_t set; - int eax; - - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - - if (__get_user(set.sig[0], &frame->sc.oldmask) - || (_IA32_NSIG_WORDS > 1 - && __copy_from_user((((char *) &set.sig) + 4), - &frame->extramask, - sizeof(frame->extramask)))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); - current->blocked = (sigset_t) set; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - if (restore_sigcontext_ia32(regs, &frame->sc, &eax)) - goto badframe; - return eax; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} - -asmlinkage int -sys32_rt_sigreturn( -int arg0, -int arg1, -int arg2, -int arg3, -int arg4, -int arg5, -int arg6, -int arg7, -unsigned long stack) +asmlinkage long +sys32_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, + unsigned long stack) { - struct pt_regs *regs = (struct pt_regs *) &stack; - struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(regs->r12 - 4); - sigset_t set; - stack_t st; - int eax; - - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); - current->blocked = set; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax)) - goto badframe; - - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) - goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->r12); - - return eax; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long esp = (unsigned int) regs->r12; + struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(esp - 8); + sigset_t set; + int eax; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_IA32_NSIG_WORDS > 1 && __copy_from_user((char *) &set.sig + 4, &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = (sigset_t) set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext_ia32(regs, &frame->sc, &eax)) + goto badframe; + return eax; + + badframe: + force_sig(SIGSEGV, current); + return 0; +} +asmlinkage long +sys32_rt_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, + unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long esp = (unsigned int) regs->r12; + struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(esp - 4); + sigset_t set; + stack_t st; + int eax; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, esp); + + return eax; + + badframe: + force_sig(SIGSEGV, current); + return 0; +} diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c index 3939c8fd01f6..4f536c1aebb0 100644 --- a/arch/ia64/ia32/ia32_support.c +++ b/arch/ia64/ia32/ia32_support.c @@ -4,15 +4,18 @@ * Copyright (C) 1999 Arun Sharma * Copyright (C) 2000 Asit K. Mallick * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang + * David Mosberger-Tang * * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context * 02/19/01 D. Mosberger dropped tssd; it's not needed + * 09/14/01 D. Mosberger fixed memory management for gdt/tss page + * 09/29/01 D. Mosberger added ia32_load_segment_descriptors() */ #include #include #include +#include #include #include @@ -21,10 +24,46 @@ #include #include -extern unsigned long *ia32_gdt_table, *ia32_tss; - extern void die_if_kernel (char *str, struct pt_regs *regs, long err); +struct exec_domain ia32_exec_domain; +struct page *ia32_shared_page[(2*IA32_PAGE_SIZE + PAGE_SIZE - 1)/PAGE_SIZE]; +unsigned long *ia32_gdt; + +static unsigned long +load_desc (u16 selector) +{ + unsigned long *table, limit, index; + + if (!selector) + return 0; + if (selector & IA32_SEGSEL_TI) { + table = (unsigned long *) IA32_LDT_OFFSET; + limit = IA32_LDT_ENTRIES; + } else { + table = ia32_gdt; + limit = IA32_PAGE_SIZE / sizeof(ia32_gdt[0]); + } + index = selector >> IA32_SEGSEL_INDEX_SHIFT; + if (index >= limit) + return 0; + return IA32_SEG_UNSCRAMBLE(table[index]); +} + +void +ia32_load_segment_descriptors (struct task_struct *task) +{ + struct pt_regs *regs = ia64_task_regs(task); + + /* Setup the segment descriptors */ + regs->r24 = load_desc(regs->r16 >> 16); /* ESD */ + regs->r27 = load_desc(regs->r16 >> 0); /* DSD */ + regs->r28 = load_desc(regs->r16 >> 32); /* FSD */ + regs->r29 = load_desc(regs->r16 >> 48); /* GSD */ + task->thread.csd = load_desc(regs->r17 >> 0); /* CSD */ + task->thread.ssd = load_desc(regs->r17 >> 16); /* SSD */ +} + void ia32_save_state (struct task_struct *t) { @@ -46,14 +85,17 @@ ia32_save_state (struct task_struct *t) t->thread.csd = csd; t->thread.ssd = ssd; ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob); + ia64_set_kr(IA64_KR_TSSD, t->thread.old_k1); } void ia32_load_state (struct task_struct *t) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; + unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; struct pt_regs *regs = ia64_task_regs(t); - int nr; + int nr = smp_processor_id(); /* LDT and TSS depend on CPU number: */ + + nr = smp_processor_id(); eflag = t->thread.eflag; fsr = t->thread.fsr; @@ -62,6 +104,7 @@ ia32_load_state (struct task_struct *t) fdr = t->thread.fdr; csd = t->thread.csd; ssd = t->thread.ssd; + tssd = load_desc(_TSS(nr)); /* TSSD */ asm volatile ("mov ar.eflag=%0;" "mov ar.fsr=%1;" @@ -72,11 +115,12 @@ ia32_load_state (struct task_struct *t) "mov ar.ssd=%6;" :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd)); current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE); + current->thread.old_k1 = ia64_get_kr(IA64_KR_TSSD); ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); + ia64_set_kr(IA64_KR_TSSD, tssd); - /* load TSS and LDT while preserving SS and CS: */ - nr = smp_processor_id(); regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) | (__u32) regs->r17; + regs->r30 = load_desc(_LDT(nr)); /* LDTD */ } /* @@ -85,36 +129,34 @@ ia32_load_state (struct task_struct *t) void ia32_gdt_init (void) { - unsigned long gdt_and_tss_page, ldt_size; + unsigned long *tss; + unsigned long ldt_size; int nr; - /* allocate two IA-32 pages of memory: */ - gdt_and_tss_page = __get_free_pages(GFP_KERNEL, - (IA32_PAGE_SHIFT < PAGE_SHIFT) - ? 0 : (IA32_PAGE_SHIFT + 1) - PAGE_SHIFT); - ia32_gdt_table = (unsigned long *) gdt_and_tss_page; - ia32_tss = (unsigned long *) (gdt_and_tss_page + IA32_PAGE_SIZE); + ia32_shared_page[0] = alloc_page(GFP_KERNEL); + ia32_gdt = page_address(ia32_shared_page[0]); + tss = ia32_gdt + IA32_PAGE_SIZE/sizeof(ia32_gdt[0]); - /* Zero the gdt and tss */ - memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE); + if (IA32_PAGE_SIZE == PAGE_SIZE) { + ia32_shared_page[1] = alloc_page(GFP_KERNEL); + tss = page_address(ia32_shared_page[1]); + } /* CS descriptor in IA-32 (scrambled) format */ - ia32_gdt_table[__USER_CS >> 3] = - IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT, - 0xb, 1, 3, 1, 1, 1, 1); + ia32_gdt[__USER_CS >> 3] = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT, + 0xb, 1, 3, 1, 1, 1, 1); /* DS descriptor in IA-32 (scrambled) format */ - ia32_gdt_table[__USER_DS >> 3] = - IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT, - 0x3, 1, 3, 1, 1, 1, 1); + ia32_gdt[__USER_DS >> 3] = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT, + 0x3, 1, 3, 1, 1, 1, 1); /* We never change the TSS and LDT descriptors, so we can share them across all CPUs. */ ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); for (nr = 0; nr < NR_CPUS; ++nr) { - ia32_gdt_table[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235, - 0xb, 0, 3, 1, 1, 1, 0); - ia32_gdt_table[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1, - 0x2, 0, 3, 1, 1, 1, 0); + ia32_gdt[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235, + 0xb, 0, 3, 1, 1, 1, 0); + ia32_gdt[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1, + 0x2, 0, 3, 1, 1, 1, 0); } } @@ -133,3 +175,18 @@ ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs) siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current); } + +static int __init +ia32_init (void) +{ + ia32_exec_domain.name = "Linux/x86"; + ia32_exec_domain.handler = NULL; + ia32_exec_domain.pers_low = PER_LINUX32; + ia32_exec_domain.pers_high = PER_LINUX32; + ia32_exec_domain.signal_map = default_exec_domain.signal_map; + ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; + register_exec_domain(&ia32_exec_domain); + return 0; +} + +__initcall(ia32_init); diff --git a/arch/ia64/ia32/ia32_traps.c b/arch/ia64/ia32/ia32_traps.c index 5c1558fec1a9..8f0bb830d48d 100644 --- a/arch/ia64/ia32/ia32_traps.c +++ b/arch/ia64/ia32/ia32_traps.c @@ -1,7 +1,12 @@ /* - * IA32 exceptions handler + * IA-32 exception handlers + * + * Copyright (C) 2000 Asit K. Mallick + * Copyright (C) 2001 Hewlett-Packard Co + * David Mosberger-Tang * * 06/16/00 A. Mallick added siginfo for most cases (close to IA32) + * 09/29/00 D. Mosberger added ia32_intercept() */ #include @@ -10,6 +15,26 @@ #include #include +int +ia32_intercept (struct pt_regs *regs, unsigned long isr) +{ + switch ((isr >> 16) & 0xff) { + case 0: /* Instruction intercept fault */ + case 3: /* Locked Data reference fault */ + case 1: /* Gate intercept trap */ + return -1; + + case 2: /* System flag trap */ + if (((isr >> 14) & 0x3) >= 2) { + /* MOV SS, POP SS instructions */ + ia64_psr(regs)->id = 1; + return 0; + } else + return -1; + } + return -1; +} + int ia32_exception (struct pt_regs *regs, unsigned long isr) { diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index fa82305c0ab6..4e6d8f3b50cc 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -1,14 +1,13 @@ /* - * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on - * sys_sparc32 + * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Derived from sys_sparc32.c. * * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger * Copyright (C) 1999 Arun Sharma * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2000 Hewlett-Packard Co. - * Copyright (C) 2000 David Mosberger-Tang + * Copyright (C) 2000-2001 Hewlett-Packard Co + * David Mosberger-Tang * * These routines maintain argument size conversion between 32bit and 64bit * environment. @@ -53,31 +52,56 @@ #include #include #include -#include #include #include #include +#define DEBUG 0 + +#if DEBUG +# define DBG(fmt...) printk(KERN_DEBUG fmt) +#else +# define DBG(fmt...) +#endif + #define A(__x) ((unsigned long)(__x)) #define AA(__x) ((unsigned long)(__x)) #define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define OFFSET4K(a) ((a) & 0xfff) +#define PAGE_START(addr) ((addr) & PAGE_MASK) +#define PAGE_OFF(addr) ((addr) & ~PAGE_MASK) + extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *); extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long); +extern asmlinkage long sys_munmap (unsigned long, size_t); +extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsigned long, + unsigned long, unsigned long); + +/* forward declaration: */ +asmlinkage long sys32_mprotect (unsigned int, unsigned int, int); + +/* + * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore + * while doing so. + */ +/* XXX make per-mm: */ +static DECLARE_MUTEX(ia32_mmap_sem); static int nargs (unsigned int arg, char **ap) { - int n, err, addr; + unsigned int addr; + int n, err; if (!arg) return 0; n = 0; do { - err = get_user(addr, (int *)A(arg)); + err = get_user(addr, (unsigned int *)A(arg)); if (err) return err; if (ap) @@ -94,7 +118,7 @@ sys32_execve (char *filename, unsigned int argv, unsigned int envp, int stack) { struct pt_regs *regs = (struct pt_regs *)&stack; - unsigned long old_map_base, old_task_size; + unsigned long old_map_base, old_task_size, tssd; char **av, **ae; int na, ne, len; long r; @@ -123,15 +147,20 @@ sys32_execve (char *filename, unsigned int argv, unsigned int envp, old_map_base = current->thread.map_base; old_task_size = current->thread.task_size; + tssd = ia64_get_kr(IA64_KR_TSSD); - /* we may be exec'ing a 64-bit process: reset map base & task-size: */ + /* we may be exec'ing a 64-bit process: reset map base, task-size, and io-base: */ current->thread.map_base = DEFAULT_MAP_BASE; current->thread.task_size = DEFAULT_TASK_SIZE; + ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob); + ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1); set_fs(KERNEL_DS); r = sys_execve(filename, av, ae, regs); if (r < 0) { - /* oops, execve failed, switch back to old map base & task-size: */ + /* oops, execve failed, switch back to old values... */ + ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); + ia64_set_kr(IA64_KR_TSSD, tssd); current->thread.map_base = old_map_base; current->thread.task_size = old_task_size; set_fs(USER_DS); /* establish new task-size as the address-limit */ @@ -142,30 +171,33 @@ sys32_execve (char *filename, unsigned int argv, unsigned int envp, } static inline int -putstat(struct stat32 *ubuf, struct stat *kbuf) +putstat (struct stat32 *ubuf, struct stat *kbuf) { int err; - err = put_user (kbuf->st_dev, &ubuf->st_dev); - err |= __put_user (kbuf->st_ino, &ubuf->st_ino); - err |= __put_user (kbuf->st_mode, &ubuf->st_mode); - err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink); - err |= __put_user (kbuf->st_uid, &ubuf->st_uid); - err |= __put_user (kbuf->st_gid, &ubuf->st_gid); - err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev); - err |= __put_user (kbuf->st_size, &ubuf->st_size); - err |= __put_user (kbuf->st_atime, &ubuf->st_atime); - err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime); - err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime); - err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize); - err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks); + if (clear_user(ubuf, sizeof(*ubuf))) + return 1; + + err = __put_user(kbuf->st_dev, &ubuf->st_dev); + err |= __put_user(kbuf->st_ino, &ubuf->st_ino); + err |= __put_user(kbuf->st_mode, &ubuf->st_mode); + err |= __put_user(kbuf->st_nlink, &ubuf->st_nlink); + err |= __put_user(kbuf->st_uid, &ubuf->st_uid); + err |= __put_user(kbuf->st_gid, &ubuf->st_gid); + err |= __put_user(kbuf->st_rdev, &ubuf->st_rdev); + err |= __put_user(kbuf->st_size, &ubuf->st_size); + err |= __put_user(kbuf->st_atime, &ubuf->st_atime); + err |= __put_user(kbuf->st_mtime, &ubuf->st_mtime); + err |= __put_user(kbuf->st_ctime, &ubuf->st_ctime); + err |= __put_user(kbuf->st_blksize, &ubuf->st_blksize); + err |= __put_user(kbuf->st_blocks, &ubuf->st_blocks); return err; } -extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf); +extern asmlinkage long sys_newstat (char * filename, struct stat * statbuf); asmlinkage long -sys32_newstat(char * filename, struct stat32 *statbuf) +sys32_newstat (char *filename, struct stat32 *statbuf) { int ret; struct stat s; @@ -173,8 +205,8 @@ sys32_newstat(char * filename, struct stat32 *statbuf) set_fs(KERNEL_DS); ret = sys_newstat(filename, &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) + set_fs(old_fs); + if (putstat(statbuf, &s)) return -EFAULT; return ret; } @@ -182,16 +214,16 @@ sys32_newstat(char * filename, struct stat32 *statbuf) extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf); asmlinkage long -sys32_newlstat(char * filename, struct stat32 *statbuf) +sys32_newlstat (char *filename, struct stat32 *statbuf) { - int ret; - struct stat s; mm_segment_t old_fs = get_fs(); + struct stat s; + int ret; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_newlstat(filename, &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) + set_fs(old_fs); + if (putstat(statbuf, &s)) return -EFAULT; return ret; } @@ -199,112 +231,249 @@ sys32_newlstat(char * filename, struct stat32 *statbuf) extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf); asmlinkage long -sys32_newfstat(unsigned int fd, struct stat32 *statbuf) +sys32_newfstat (unsigned int fd, struct stat32 *statbuf) { - int ret; - struct stat s; mm_segment_t old_fs = get_fs(); + struct stat s; + int ret; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_newfstat(fd, &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) + set_fs(old_fs); + if (putstat(statbuf, &s)) return -EFAULT; return ret; } -#define OFFSET4K(a) ((a) & 0xfff) +#if PAGE_SHIFT > IA32_PAGE_SHIFT -unsigned long -do_mmap_fake(struct file *file, unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, loff_t off) + +static int +get_page_prot (unsigned long addr) +{ + struct vm_area_struct *vma = find_vma(current->mm, addr); + int prot = 0; + + if (!vma || vma->vm_start > addr) + return 0; + + if (vma->vm_flags & VM_READ) + prot |= PROT_READ; + if (vma->vm_flags & VM_WRITE) + prot |= PROT_WRITE; + if (vma->vm_flags & VM_EXEC) + prot |= PROT_EXEC; + return prot; +} + +/* + * Map a subpage by creating an anonymous page that contains the union of the old page and + * the subpage. + */ +static unsigned long +mmap_subpage (struct file *file, unsigned long start, unsigned long end, int prot, int flags, + loff_t off) { + void *page = (void *) get_zeroed_page(GFP_KERNEL); struct inode *inode; - void *front, *back; - unsigned long baddr; - int r; - char c; + unsigned long ret; + int old_prot = get_page_prot(start); - if (OFFSET4K(addr) || OFFSET4K(off)) - return -EINVAL; - prot |= PROT_WRITE; - front = NULL; - back = NULL; - if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) { - front = kmalloc(addr - baddr, GFP_KERNEL); - if (!front) - return -ENOMEM; - __copy_user(front, (void *)baddr, addr - baddr); + DBG("mmap_subpage(file=%p,start=0x%lx,end=0x%lx,prot=%x,flags=%x,off=0x%llx)\n", + file, start, end, prot, flags, off); + + if (!page) + return -ENOMEM; + + if (old_prot) + copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE); + + down_write(¤t->mm->mmap_sem); + { + ret = do_mmap(0, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE, + flags | MAP_FIXED | MAP_ANONYMOUS, 0); } - if (addr && ((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) { - back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); - if (!back) { - if (front) - kfree(front); - return -ENOMEM; + up_write(¤t->mm->mmap_sem); + + if (IS_ERR((void *) ret)) + goto out; + + if (old_prot) { + /* copy back the old page contents. */ + if (PAGE_OFF(start)) + copy_to_user((void *) PAGE_START(start), page, PAGE_OFF(start)); + if (PAGE_OFF(end)) + copy_to_user((void *) end, page + PAGE_OFF(end), + PAGE_SIZE - PAGE_OFF(end)); + } + if (!(flags & MAP_ANONYMOUS)) { + /* read the file contents */ + inode = file->f_dentry->d_inode; + if (!inode->i_fop || !file->f_op->read + || ((*file->f_op->read)(file, (char *) start, end - start, &off) < 0)) + { + ret = -EINVAL; + goto out; } - __copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); } - down_write(¤t->mm->mmap_sem); - r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0); - up_write(¤t->mm->mmap_sem); - if (r < 0) - return(r); - if (addr == 0) - addr = r; - if (back) { - __copy_user((char *)addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); - kfree(back); + if (!(prot & PROT_WRITE)) + ret = sys_mprotect(PAGE_START(start), PAGE_SIZE, prot | old_prot); + out: + free_page((unsigned long) page); + return ret; +} + +static unsigned long +emulate_mmap (struct file *file, unsigned long start, unsigned long len, int prot, int flags, + loff_t off) +{ + unsigned long tmp, end, pend, pstart, ret, is_congruent, fudge = 0; + struct inode *inode; + loff_t poff; + + end = start + len; + pstart = PAGE_START(start); + pend = PAGE_ALIGN(end); + + if (flags & MAP_FIXED) { + if (start > pstart) { + if (flags & MAP_SHARED) + printk(KERN_INFO + "%s(%d): emulate_mmap() can't share head (addr=0x%lx)\n", + current->comm, current->pid, start); + ret = mmap_subpage(file, start, min(PAGE_ALIGN(start), end), prot, flags, + off); + if (IS_ERR((void *) ret)) + return ret; + pstart += PAGE_SIZE; + if (pstart >= pend) + return start; /* done */ + } + if (end < pend) { + if (flags & MAP_SHARED) + printk(KERN_INFO + "%s(%d): emulate_mmap() can't share tail (end=0x%lx)\n", + current->comm, current->pid, end); + ret = mmap_subpage(file, max(start, PAGE_START(end)), end, prot, flags, + (off + len) - PAGE_OFF(end)); + if (IS_ERR((void *) ret)) + return ret; + pend -= PAGE_SIZE; + if (pstart >= pend) + return start; /* done */ + } + } else { + /* + * If a start address was specified, use it if the entire rounded out area + * is available. + */ + if (start && !pstart) + fudge = 1; /* handle case of mapping to range (0,PAGE_SIZE) */ + tmp = arch_get_unmapped_area(file, pstart - fudge, pend - pstart, 0, flags); + if (tmp != pstart) { + pstart = tmp; + start = pstart + PAGE_OFF(off); /* make start congruent with off */ + end = start + len; + pend = PAGE_ALIGN(end); + } } - if (front) { - __copy_user((void *)baddr, front, addr - baddr); - kfree(front); + + poff = off + (pstart - start); /* note: (pstart - start) may be negative */ + is_congruent = (flags & MAP_ANONYMOUS) || (PAGE_OFF(poff) == 0); + + if ((flags & MAP_SHARED) && !is_congruent) + printk(KERN_INFO "%s(%d): emulate_mmap() can't share contents of incongruent mmap " + "(addr=0x%lx,off=0x%llx)\n", current->comm, current->pid, start, off); + + DBG("mmap_body: mapping [0x%lx-0x%lx) %s with poff 0x%llx\n", pstart, pend, + is_congruent ? "congruent" : "not congruent", poff); + + down_write(¤t->mm->mmap_sem); + { + if (!(flags & MAP_ANONYMOUS) && is_congruent) + ret = do_mmap(file, pstart, pend - pstart, prot, flags | MAP_FIXED, poff); + else + ret = do_mmap(0, pstart, pend - pstart, + prot | ((flags & MAP_ANONYMOUS) ? 0 : PROT_WRITE), + flags | MAP_FIXED | MAP_ANONYMOUS, 0); } - if (flags & MAP_ANONYMOUS) { - clear_user((char *)addr, len); - return(addr); + up_write(¤t->mm->mmap_sem); + + if (IS_ERR((void *) ret)) + return ret; + + if (!is_congruent) { + /* read the file contents */ + inode = file->f_dentry->d_inode; + if (!inode->i_fop || !file->f_op->read + || ((*file->f_op->read)(file, (char *) pstart, pend - pstart, &poff) < 0)) + { + sys_munmap(pstart, pend - pstart); + return -EINVAL; + } + if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0) + return EINVAL; } - if (!file) - return -EINVAL; - inode = file->f_dentry->d_inode; - if (!inode->i_fop) - return -EINVAL; - if (!file->f_op->read) - return -EINVAL; - r = file->f_op->read(file, (char *)addr, len, &off); - return (r < 0) ? -EINVAL : addr; + return start; } -long -ia32_do_mmap (struct file *file, unsigned int addr, unsigned int len, unsigned int prot, - unsigned int flags, unsigned int fd, unsigned int offset) +#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */ + +static inline unsigned int +get_prot32 (unsigned int prot) { - long error = -EFAULT; - unsigned int poff; + if (prot & PROT_WRITE) + /* on x86, PROT_WRITE implies PROT_READ which implies PROT_EEC */ + prot |= PROT_READ | PROT_WRITE | PROT_EXEC; + else if (prot & (PROT_READ | PROT_EXEC)) + /* on x86, there is no distinction between PROT_READ and PROT_EXEC */ + prot |= (PROT_READ | PROT_EXEC); - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - prot |= PROT_EXEC; + return prot; +} - if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) - error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset); - else { - poff = offset & PAGE_MASK; - len += offset - poff; +unsigned long +ia32_do_mmap (struct file *file, unsigned long addr, unsigned long len, int prot, int flags, + loff_t offset) +{ + DBG("ia32_do_mmap(file=%p,addr=0x%lx,len=0x%lx,prot=%x,flags=%x,offset=0x%llx)\n", + file, addr, len, prot, flags, offset); + + if (file && (!file->f_op || !file->f_op->mmap)) + return -ENODEV; + + len = IA32_PAGE_ALIGN(len); + if (len == 0) + return addr; + + if (len > IA32_PAGE_OFFSET || addr > IA32_PAGE_OFFSET - len) + return -EINVAL; + + if (OFFSET4K(offset)) + return -EINVAL; - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); + prot = get_prot32(prot); - if (!IS_ERR((void *) error)) - error += offset - poff; +#if PAGE_SHIFT > IA32_PAGE_SHIFT + down(&ia32_mmap_sem); + { + addr = emulate_mmap(file, addr, len, prot, flags, offset); } - return error; + up(&ia32_mmap_sem); +#else + down_write(¤t->mm->mmap_sem); + { + addr = do_mmap(file, addr, len, prot, flags, offset); + } + up_write(¤t->mm->mmap_sem); +#endif + DBG("ia32_do_mmap: returning 0x%lx\n", addr); + return addr; } /* - * Linux/i386 didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory - * block for parameter passing.. + * Linux/i386 didn't use to be able to handle more than 4 system call parameters, so these + * system calls used a memory block for parameter passing.. */ struct mmap_arg_struct { @@ -317,180 +486,166 @@ struct mmap_arg_struct { }; asmlinkage long -sys32_mmap(struct mmap_arg_struct *arg) +sys32_mmap (struct mmap_arg_struct *arg) { struct mmap_arg_struct a; struct file *file = NULL; - long retval; + unsigned long addr; + int flags; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - if (PAGE_ALIGN(a.len) == 0) - return a.addr; + if (OFFSET4K(a.offset)) + return -EINVAL; + + flags = a.flags; - if (!(a.flags & MAP_ANONYMOUS)) { + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { file = fget(a.fd); if (!file) return -EBADF; } -#ifdef CONFIG_IA64_PAGE_SIZE_4KB - if ((a.offset & ~PAGE_MASK) != 0) - return -EINVAL; - down_write(¤t->mm->mmap_sem); - retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); -#else - retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset); -#endif + addr = ia32_do_mmap(file, a.addr, a.len, a.prot, flags, a.offset); + if (file) fput(file); - return retval; + return addr; } asmlinkage long -sys32_mprotect(unsigned long start, size_t len, unsigned long prot) +sys32_mmap2 (unsigned int addr, unsigned int len, unsigned int prot, unsigned int flags, + unsigned int fd, unsigned int pgoff) { + struct file *file = NULL; + unsigned long retval; -#ifdef CONFIG_IA64_PAGE_SIZE_4KB - return(sys_mprotect(start, len, prot)); -#else // CONFIG_IA64_PAGE_SIZE_4KB - if (prot == 0) - return(0); - len += start & ~PAGE_MASK; - if ((start & ~PAGE_MASK) && (prot & PROT_WRITE)) - prot |= PROT_EXEC; - return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot)); -#endif // CONFIG_IA64_PAGE_SIZE_4KB -} + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + return -EBADF; + } -asmlinkage long -sys32_pipe(int *fd) -{ - int retval; - int fds[2]; + retval = ia32_do_mmap(file, addr, len, prot, flags, + (unsigned long) pgoff << IA32_PAGE_SHIFT); - retval = do_pipe(fds); - if (retval) - goto out; - if (copy_to_user(fd, fds, sizeof(fds))) - retval = -EFAULT; - out: + if (file) + fput(file); return retval; } asmlinkage long -sys32_signal (int sig, unsigned int handler) +sys32_munmap (unsigned int start, unsigned int len) { - struct k_sigaction new_sa, old_sa; - int ret; + unsigned int end = start + len; + long ret; + +#if PAGE_SHIFT <= IA32_PAGE_SHIFT + ret = sys_munmap(start, end - start); +#else + if (start > end) + return -EINVAL; + + start = PAGE_ALIGN(start); + end = PAGE_START(end); + + if (start >= end) + return 0; + + down(&ia32_mmap_sem); + { + ret = sys_munmap(start, end - start); + } + up(&ia32_mmap_sem); +#endif + return ret; +} + +#if PAGE_SHIFT > IA32_PAGE_SHIFT - new_sa.sa.sa_handler = (__sighandler_t) A(handler); - new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; +/* + * When mprotect()ing a partial page, we set the permission to the union of the old + * settings and the new settings. In other words, it's only possible to make access to a + * partial page less restrictive. + */ +static long +mprotect_subpage (unsigned long address, int new_prot) +{ + int old_prot; - ret = do_sigaction(sig, &new_sa, &old_sa); + if (new_prot == PROT_NONE) + return 0; /* optimize case where nothing changes... */ - return ret ? ret : (unsigned long)old_sa.sa.sa_handler; + old_prot = get_page_prot(address); + return sys_mprotect(address, PAGE_SIZE, new_prot | old_prot); } +#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */ + asmlinkage long -sys32_rt_sigaction(int sig, struct sigaction32 *act, - struct sigaction32 *oact, unsigned int sigsetsize) +sys32_mprotect (unsigned int start, unsigned int len, int prot) { - struct k_sigaction new_ka, old_ka; - int ret; - sigset32_t set32; + unsigned long end = start + len; +#if PAGE_SHIFT > IA32_PAGE_SHIFT + long retval = 0; +#endif - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset32_t)) + prot = get_prot32(prot); + +#if PAGE_SHIFT <= IA32_PAGE_SHIFT + return sys_mprotect(start, end - start, prot); +#else + if (OFFSET4K(start)) return -EINVAL; - if (act) { - ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); - ret |= __copy_from_user(&set32, &act->sa_mask, - sizeof(sigset32_t)); - switch (_NSIG_WORDS) { - case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] - | (((long)set32.sig[7]) << 32); - case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] - | (((long)set32.sig[5]) << 32); - case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] - | (((long)set32.sig[3]) << 32); - case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] - | (((long)set32.sig[1]) << 32); - } - ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + end = IA32_PAGE_ALIGN(end); + if (end < start) + return -EINVAL; - if (ret) - return -EFAULT; - } + down(&ia32_mmap_sem); + { + if (PAGE_OFF(start)) { + /* start address is 4KB aligned but not page aligned. */ + retval = mprotect_subpage(PAGE_START(start), prot); + if (retval < 0) + goto out; - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - switch (_NSIG_WORDS) { - case 4: - set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); - set32.sig[6] = old_ka.sa.sa_mask.sig[3]; - case 3: - set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); - set32.sig[4] = old_ka.sa.sa_mask.sig[2]; - case 2: - set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); - set32.sig[2] = old_ka.sa.sa_mask.sig[1]; - case 1: - set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); - set32.sig[0] = old_ka.sa.sa_mask.sig[0]; + start = PAGE_ALIGN(start); + if (start >= end) + goto out; /* retval is already zero... */ } - ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); - ret |= __copy_to_user(&oact->sa_mask, &set32, - sizeof(sigset32_t)); - ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - } - return ret; + if (PAGE_OFF(end)) { + /* end address is 4KB aligned but not page aligned. */ + retval = mprotect_subpage(PAGE_START(end), prot); + if (retval < 0) + return retval; + end = PAGE_START(end); + } + retval = sys_mprotect(start, end - start, prot); + } + out: + up(&ia32_mmap_sem); + return retval; +#endif } - -extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, - size_t sigsetsize); - asmlinkage long -sys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset, - unsigned int sigsetsize) +sys32_pipe (int *fd) { - sigset_t s; - sigset32_t s32; - int ret; - mm_segment_t old_fs = get_fs(); + int retval; + int fds[2]; - if (set) { - if (copy_from_user (&s32, set, sizeof(sigset32_t))) - return -EFAULT; - switch (_NSIG_WORDS) { - case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); - case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); - case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); - case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); - } - } - set_fs (KERNEL_DS); - ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, - sigsetsize); - set_fs (old_fs); - if (ret) return ret; - if (oset) { - switch (_NSIG_WORDS) { - case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; - case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; - case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; - case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; - } - if (copy_to_user (oset, &s32, sizeof(sigset32_t))) - return -EFAULT; - } - return 0; + retval = do_pipe(fds); + if (retval) + goto out; + if (copy_to_user(fd, fds, sizeof(fds))) + retval = -EFAULT; + out: + return retval; } static inline int @@ -498,31 +653,34 @@ put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { int err; - err = put_user (kbuf->f_type, &ubuf->f_type); - err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize); - err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks); - err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree); - err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail); - err |= __put_user (kbuf->f_files, &ubuf->f_files); - err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree); - err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen); - err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]); - err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]); + if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) + return -EFAULT; + + err = __put_user(kbuf->f_type, &ubuf->f_type); + err |= __put_user(kbuf->f_bsize, &ubuf->f_bsize); + err |= __put_user(kbuf->f_blocks, &ubuf->f_blocks); + err |= __put_user(kbuf->f_bfree, &ubuf->f_bfree); + err |= __put_user(kbuf->f_bavail, &ubuf->f_bavail); + err |= __put_user(kbuf->f_files, &ubuf->f_files); + err |= __put_user(kbuf->f_ffree, &ubuf->f_ffree); + err |= __put_user(kbuf->f_namelen, &ubuf->f_namelen); + err |= __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]); + err |= __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]); return err; } extern asmlinkage long sys_statfs(const char * path, struct statfs * buf); asmlinkage long -sys32_statfs(const char * path, struct statfs32 *buf) +sys32_statfs (const char *path, struct statfs32 *buf) { int ret; struct statfs s; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_statfs((const char *)path, &s); - set_fs (old_fs); + set_fs(KERNEL_DS); + ret = sys_statfs(path, &s); + set_fs(old_fs); if (put_statfs(buf, &s)) return -EFAULT; return ret; @@ -531,15 +689,15 @@ sys32_statfs(const char * path, struct statfs32 *buf) extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf); asmlinkage long -sys32_fstatfs(unsigned int fd, struct statfs32 *buf) +sys32_fstatfs (unsigned int fd, struct statfs32 *buf) { int ret; struct statfs s; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_fstatfs(fd, &s); - set_fs (old_fs); + set_fs(old_fs); if (put_statfs(buf, &s)) return -EFAULT; return ret; @@ -557,23 +715,21 @@ struct itimerval32 }; static inline long -get_tv32(struct timeval *o, struct timeval32 *i) +get_tv32 (struct timeval *o, struct timeval32 *i) { return (!access_ok(VERIFY_READ, i, sizeof(*i)) || - (__get_user(o->tv_sec, &i->tv_sec) | - __get_user(o->tv_usec, &i->tv_usec))); + (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec))); } static inline long -put_tv32(struct timeval32 *o, struct timeval *i) +put_tv32 (struct timeval32 *o, struct timeval *i) { return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || - (__put_user(i->tv_sec, &o->tv_sec) | - __put_user(i->tv_usec, &o->tv_usec))); + (__put_user(i->tv_sec, &o->tv_sec) | __put_user(i->tv_usec, &o->tv_usec))); } static inline long -get_it32(struct itimerval *o, struct itimerval32 *i) +get_it32 (struct itimerval *o, struct itimerval32 *i) { return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | @@ -583,7 +739,7 @@ get_it32(struct itimerval *o, struct itimerval32 *i) } static inline long -put_it32(struct itimerval32 *o, struct itimerval *i) +put_it32 (struct itimerval32 *o, struct itimerval *i) { return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | @@ -592,10 +748,10 @@ put_it32(struct itimerval32 *o, struct itimerval *i) __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); } -extern int do_getitimer(int which, struct itimerval *value); +extern int do_getitimer (int which, struct itimerval *value); asmlinkage long -sys32_getitimer(int which, struct itimerval32 *it) +sys32_getitimer (int which, struct itimerval32 *it) { struct itimerval kit; int error; @@ -607,10 +763,10 @@ sys32_getitimer(int which, struct itimerval32 *it) return error; } -extern int do_setitimer(int which, struct itimerval *, struct itimerval *); +extern int do_setitimer (int which, struct itimerval *, struct itimerval *); asmlinkage long -sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out) +sys32_setitimer (int which, struct itimerval32 *in, struct itimerval32 *out) { struct itimerval kin, kout; int error; @@ -630,8 +786,9 @@ sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out) return 0; } + asmlinkage unsigned long -sys32_alarm(unsigned int seconds) +sys32_alarm (unsigned int seconds) { struct itimerval it_new, it_old; unsigned int oldalarm; @@ -660,7 +817,7 @@ extern asmlinkage long sys_utimes(char * filename, struct timeval * utimes); extern asmlinkage long sys_gettimeofday (struct timeval *tv, struct timezone *tz); asmlinkage long -ia32_utime(char * filename, struct utimbuf_32 *times32) +sys32_utime (char *filename, struct utimbuf_32 *times32) { mm_segment_t old_fs = get_fs(); struct timeval tv[2], *tvp; @@ -673,20 +830,20 @@ ia32_utime(char * filename, struct utimbuf_32 *times32) if (get_user(tv[1].tv_sec, ×32->mtime)) return -EFAULT; tv[1].tv_usec = 0; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); tvp = tv; } else tvp = NULL; ret = sys_utimes(filename, tvp); - set_fs (old_fs); + set_fs(old_fs); return ret; } extern struct timezone sys_tz; -extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); +extern int do_sys_settimeofday (struct timeval *tv, struct timezone *tz); asmlinkage long -sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz) +sys32_gettimeofday (struct timeval32 *tv, struct timezone *tz) { if (tv) { struct timeval ktv; @@ -702,7 +859,7 @@ sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz) } asmlinkage long -sys32_settimeofday(struct timeval32 *tv, struct timezone *tz) +sys32_settimeofday (struct timeval32 *tv, struct timezone *tz) { struct timeval ktv; struct timezone ktz; @@ -719,20 +876,6 @@ sys32_settimeofday(struct timeval32 *tv, struct timezone *tz) return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL); } -struct linux32_dirent { - u32 d_ino; - u32 d_off; - u16 d_reclen; - char d_name[1]; -}; - -struct old_linux32_dirent { - u32 d_ino; - u32 d_offset; - u16 d_namlen; - char d_name[1]; -}; - struct getdents32_callback { struct linux32_dirent * current_dir; struct linux32_dirent * previous; @@ -775,7 +918,7 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, } asmlinkage long -sys32_getdents (unsigned int fd, void * dirent, unsigned int count) +sys32_getdents (unsigned int fd, struct linux32_dirent *dirent, unsigned int count) { struct file * file; struct linux32_dirent * lastdirent; @@ -787,7 +930,7 @@ sys32_getdents (unsigned int fd, void * dirent, unsigned int count) if (!file) goto out; - buf.current_dir = (struct linux32_dirent *) dirent; + buf.current_dir = dirent; buf.previous = NULL; buf.count = count; buf.error = 0; @@ -831,7 +974,7 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t } asmlinkage long -sys32_readdir (unsigned int fd, void * dirent, unsigned int count) +sys32_readdir (unsigned int fd, void *dirent, unsigned int count) { int error; struct file * file; @@ -866,7 +1009,7 @@ out: #define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y)) asmlinkage long -sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32) +sys32_select (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32) { fd_set_bits fds; char *bits; @@ -878,8 +1021,7 @@ sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tv time_t sec, usec; ret = -EFAULT; - if (get_user(sec, &tvp32->tv_sec) - || get_user(usec, &tvp32->tv_usec)) + if (get_user(sec, &tvp32->tv_sec) || get_user(usec, &tvp32->tv_usec)) goto out_nofds; ret = -EINVAL; @@ -933,9 +1075,7 @@ sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tv usec = timeout % HZ; usec *= (1000000/HZ); } - if (put_user(sec, (int *)&tvp32->tv_sec) - || put_user(usec, (int *)&tvp32->tv_usec)) - { + if (put_user(sec, &tvp32->tv_sec) || put_user(usec, &tvp32->tv_usec)) { ret = -EFAULT; goto out; } @@ -969,50 +1109,43 @@ struct sel_arg_struct { }; asmlinkage long -old_select(struct sel_arg_struct *arg) +sys32_old_select (struct sel_arg_struct *arg) { struct sel_arg_struct a; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - return sys32_select(a.n, (fd_set *)A(a.inp), (fd_set *)A(a.outp), (fd_set *)A(a.exp), - (struct timeval32 *)A(a.tvp)); + return sys32_select(a.n, (fd_set *) A(a.inp), (fd_set *) A(a.outp), (fd_set *) A(a.exp), + (struct timeval32 *) A(a.tvp)); } -struct timespec32 { - int tv_sec; - int tv_nsec; -}; - -extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); +extern asmlinkage long sys_nanosleep (struct timespec *rqtp, struct timespec *rmtp); asmlinkage long -sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) +sys32_nanosleep (struct timespec32 *rqtp, struct timespec32 *rmtp) { struct timespec t; int ret; - mm_segment_t old_fs = get_fs (); + mm_segment_t old_fs = get_fs(); - if (get_user (t.tv_sec, &rqtp->tv_sec) || - __get_user (t.tv_nsec, &rqtp->tv_nsec)) + if (get_user (t.tv_sec, &rqtp->tv_sec) || get_user (t.tv_nsec, &rqtp->tv_nsec)) return -EFAULT; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_nanosleep(&t, rmtp ? &t : NULL); - set_fs (old_fs); + set_fs(old_fs); if (rmtp && ret == -EINTR) { - if (__put_user (t.tv_sec, &rmtp->tv_sec) || - __put_user (t.tv_nsec, &rmtp->tv_nsec)) + if (put_user(t.tv_sec, &rmtp->tv_sec) || put_user(t.tv_nsec, &rmtp->tv_nsec)) return -EFAULT; } return ret; } struct iovec32 { unsigned int iov_base; int iov_len; }; -asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long); -asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long); +asmlinkage ssize_t sys_readv (unsigned long,const struct iovec *,unsigned long); +asmlinkage ssize_t sys_writev (unsigned long,const struct iovec *,unsigned long); static struct iovec * -get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) +get_iovec32 (struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) { int i; u32 buf, len; @@ -1022,24 +1155,23 @@ get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) if (!count) return 0; - if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count)) - return(struct iovec *)0; + if (verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count)) + return NULL; if (count > UIO_MAXIOV) - return(struct iovec *)0; + return NULL; if (count > UIO_FASTIOV) { iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); if (!iov) - return((struct iovec *)0); + return NULL; } else iov = iov_buf; ivp = iov; for (i = 0; i < count; i++) { - if (__get_user(len, &iov32->iov_len) || - __get_user(buf, &iov32->iov_base)) { + if (__get_user(len, &iov32->iov_len) || __get_user(buf, &iov32->iov_base)) { if (iov != iov_buf) kfree(iov); - return((struct iovec *)0); + return NULL; } if (verify_area(type, (void *)A(buf), len)) { if (iov != iov_buf) @@ -1047,22 +1179,23 @@ get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) return((struct iovec *)0); } ivp->iov_base = (void *)A(buf); - ivp->iov_len = (__kernel_size_t)len; + ivp->iov_len = (__kernel_size_t) len; iov32++; ivp++; } - return(iov); + return iov; } asmlinkage long -sys32_readv(int fd, struct iovec32 *vector, u32 count) +sys32_readv (int fd, struct iovec32 *vector, u32 count) { struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov; - int ret; + long ret; mm_segment_t old_fs = get_fs(); - if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0) + iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE); + if (!iov) return -EFAULT; set_fs(KERNEL_DS); ret = sys_readv(fd, iov, count); @@ -1073,14 +1206,15 @@ sys32_readv(int fd, struct iovec32 *vector, u32 count) } asmlinkage long -sys32_writev(int fd, struct iovec32 *vector, u32 count) +sys32_writev (int fd, struct iovec32 *vector, u32 count) { struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov; - int ret; + long ret; mm_segment_t old_fs = get_fs(); - if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0) + iov = get_iovec32(vector, iovstack, count, VERIFY_READ); + if (!iov) return -EFAULT; set_fs(KERNEL_DS); ret = sys_writev(fd, iov, count); @@ -1098,45 +1232,66 @@ struct rlimit32 { int rlim_max; }; -extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim); +extern asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim); asmlinkage long -sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim) +sys32_old_getrlimit (unsigned int resource, struct rlimit32 *rlim) { + mm_segment_t old_fs = get_fs(); + struct rlimit r; + int ret; + + set_fs(KERNEL_DS); + ret = sys_getrlimit(resource, &r); + set_fs(old_fs); + if (!ret) { + ret = put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur); + ret |= put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max); + } + return ret; +} + +asmlinkage long +sys32_getrlimit (unsigned int resource, struct rlimit32 *rlim) +{ + mm_segment_t old_fs = get_fs(); struct rlimit r; int ret; - mm_segment_t old_fs = get_fs (); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_getrlimit(resource, &r); - set_fs (old_fs); + set_fs(old_fs); if (!ret) { - ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur); - ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max); + if (r.rlim_cur >= 0xffffffff) + r.rlim_cur = 0xffffffff; + if (r.rlim_max >= 0xffffffff) + r.rlim_max = 0xffffffff; + ret = put_user(r.rlim_cur, &rlim->rlim_cur); + ret |= put_user(r.rlim_max, &rlim->rlim_max); } return ret; } -extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim); +extern asmlinkage long sys_setrlimit (unsigned int resource, struct rlimit *rlim); asmlinkage long -sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim) +sys32_setrlimit (unsigned int resource, struct rlimit32 *rlim) { struct rlimit r; int ret; - mm_segment_t old_fs = get_fs (); + mm_segment_t old_fs = get_fs(); - if (resource >= RLIM_NLIMITS) return -EINVAL; - if (get_user (r.rlim_cur, &rlim->rlim_cur) || - __get_user (r.rlim_max, &rlim->rlim_max)) + if (resource >= RLIM_NLIMITS) + return -EINVAL; + if (get_user(r.rlim_cur, &rlim->rlim_cur) || get_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; if (r.rlim_cur == RLIM_INFINITY32) r.rlim_cur = RLIM_INFINITY; if (r.rlim_max == RLIM_INFINITY32) r.rlim_max = RLIM_INFINITY; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_setrlimit(resource, &r); - set_fs (old_fs); + set_fs(old_fs); return ret; } @@ -1154,16 +1309,52 @@ struct msghdr32 { unsigned msg_flags; }; -static inline int -shape_msg(struct msghdr *mp, struct msghdr32 *mp32) -{ - int ret; - unsigned int i; +struct cmsghdr32 { + __kernel_size_t32 cmsg_len; + int cmsg_level; + int cmsg_type; +}; - if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) - return(-EFAULT); - ret = __get_user(i, &mp32->msg_name); - mp->msg_name = (void *)A(i); +/* Bleech... */ +#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) +#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) +#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) +#define CMSG32_DATA(cmsg) \ + ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32)))) +#define CMSG32_SPACE(len) \ + (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len)) +#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len)) +#define __CMSG32_FIRSTHDR(ctl,len) \ + ((len) >= sizeof(struct cmsghdr32) ? (struct cmsghdr32 *)(ctl) : (struct cmsghdr32 *)NULL) +#define CMSG32_FIRSTHDR(msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) + +static inline struct cmsghdr32 * +__cmsg32_nxthdr (void *ctl, __kernel_size_t size, struct cmsghdr32 *cmsg, int cmsg_len) +{ + struct cmsghdr32 * ptr; + + ptr = (struct cmsghdr32 *)(((unsigned char *) cmsg) + CMSG32_ALIGN(cmsg_len)); + if ((unsigned long)((char*)(ptr+1) - (char *) ctl) > size) + return NULL; + return ptr; +} + +static inline struct cmsghdr32 * +cmsg32_nxthdr (struct msghdr *msg, struct cmsghdr32 *cmsg, int cmsg_len) +{ + return __cmsg32_nxthdr(msg->msg_control, msg->msg_controllen, cmsg, cmsg_len); +} + +static inline int +get_msghdr32 (struct msghdr *mp, struct msghdr32 *mp32) +{ + int ret; + unsigned int i; + + if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) + return -EFAULT; + ret = __get_user(i, &mp32->msg_name); + mp->msg_name = (void *)A(i); ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen); ret |= __get_user(i, &mp32->msg_iov); mp->msg_iov = (struct iovec *)A(i); @@ -1172,7 +1363,87 @@ shape_msg(struct msghdr *mp, struct msghdr32 *mp32) mp->msg_control = (void *)A(i); ret |= __get_user(mp->msg_controllen, &mp32->msg_controllen); ret |= __get_user(mp->msg_flags, &mp32->msg_flags); - return(ret ? -EFAULT : 0); + return ret ? -EFAULT : 0; +} + +/* + * There is a lot of hair here because the alignment rules (and thus placement) of cmsg + * headers and length are different for 32-bit apps. -DaveM + */ +static int +get_cmsghdr32 (struct msghdr *kmsg, unsigned char *stackbuf, struct sock *sk, size_t *bufsize) +{ + struct cmsghdr *kcmsg, *kcmsg_base; + __kernel_size_t kcmlen, tmp; + __kernel_size_t32 ucmlen; + struct cmsghdr32 *ucmsg; + long err; + + kcmlen = 0; + kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; + ucmsg = CMSG32_FIRSTHDR(kmsg); + while (ucmsg != NULL) { + if (get_user(ucmlen, &ucmsg->cmsg_len)) + return -EFAULT; + + /* Catch bogons. */ + if (CMSG32_ALIGN(ucmlen) < CMSG32_ALIGN(sizeof(struct cmsghdr32))) + return -EINVAL; + if ((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) + ucmlen) + > kmsg->msg_controllen) + return -EINVAL; + + tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + + CMSG_ALIGN(sizeof(struct cmsghdr))); + kcmlen += tmp; + ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); + } + if (kcmlen == 0) + return -EINVAL; + + /* + * The kcmlen holds the 64-bit version of the control length. It may not be + * modified as we do not stick it into the kmsg until we have successfully copied + * over all of the data from the user. + */ + if (kcmlen > *bufsize) { + *bufsize = kcmlen; + kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL); + } + if (kcmsg == NULL) + return -ENOBUFS; + + /* Now copy them over neatly. */ + memset(kcmsg, 0, kcmlen); + ucmsg = CMSG32_FIRSTHDR(kmsg); + while (ucmsg != NULL) { + err = get_user(ucmlen, &ucmsg->cmsg_len); + tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + + CMSG_ALIGN(sizeof(struct cmsghdr))); + kcmsg->cmsg_len = tmp; + err |= get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); + err |= get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); + + /* Copy over the data. */ + err |= copy_from_user(CMSG_DATA(kcmsg), CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))); + if (err) + goto out_free_efault; + + /* Advance. */ + kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); + } + + /* Ok, looks like we made it. Hook it up and return success. */ + kmsg->msg_control = kcmsg_base; + kmsg->msg_controllen = kcmlen; + return 0; + +out_free_efault: + if (kcmsg_base != (struct cmsghdr *)stackbuf) + sock_kfree_s(sk, kcmsg_base, kcmlen); + return -EFAULT; } /* @@ -1187,20 +1458,17 @@ shape_msg(struct msghdr *mp, struct msghdr32 *mp32) */ static inline int -verify_iovec32(struct msghdr *m, struct iovec *iov, char *address, int mode) +verify_iovec32 (struct msghdr *m, struct iovec *iov, char *address, int mode) { int size, err, ct; struct iovec32 *iov32; - if(m->msg_namelen) - { - if(mode==VERIFY_READ) - { - err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); - if(err<0) + if (m->msg_namelen) { + if (mode == VERIFY_READ) { + err = move_addr_to_kernel(m->msg_name, m->msg_namelen, address); + if (err < 0) goto out; } - m->msg_name = address; } else m->msg_name = NULL; @@ -1209,7 +1477,7 @@ verify_iovec32(struct msghdr *m, struct iovec *iov, char *address, int mode) size = m->msg_iovlen * sizeof(struct iovec32); if (copy_from_user(iov, m->msg_iov, size)) goto out; - m->msg_iov=iov; + m->msg_iov = iov; err = 0; iov32 = (struct iovec32 *)iov; @@ -1222,8 +1490,188 @@ out: return err; } -extern __inline__ void -sockfd_put(struct socket *sock) +static void +put_cmsg32(struct msghdr *kmsg, int level, int type, int len, void *data) +{ + struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; + struct cmsghdr32 cmhdr; + int cmlen = CMSG32_LEN(len); + + if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { + kmsg->msg_flags |= MSG_CTRUNC; + return; + } + + if(kmsg->msg_controllen < cmlen) { + kmsg->msg_flags |= MSG_CTRUNC; + cmlen = kmsg->msg_controllen; + } + cmhdr.cmsg_level = level; + cmhdr.cmsg_type = type; + cmhdr.cmsg_len = cmlen; + + if(copy_to_user(cm, &cmhdr, sizeof cmhdr)) + return; + if(copy_to_user(CMSG32_DATA(cm), data, + cmlen - sizeof(struct cmsghdr32))) + return; + cmlen = CMSG32_SPACE(len); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; +} + +static void +scm_detach_fds32 (struct msghdr *kmsg, struct scm_cookie *scm) +{ + struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; + int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) + / sizeof(int); + int fdnum = scm->fp->count; + struct file **fp = scm->fp->fp; + int *cmfptr; + int err = 0, i; + + if (fdnum < fdmax) + fdmax = fdnum; + + for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); + i < fdmax; + i++, cmfptr++) { + int new_fd; + err = get_unused_fd(); + if (err < 0) + break; + new_fd = err; + err = put_user(new_fd, cmfptr); + if (err) { + put_unused_fd(new_fd); + break; + } + /* Bump the usage count and install the file. */ + get_file(fp[i]); + current->files->fd[new_fd] = fp[i]; + } + + if (i > 0) { + int cmlen = CMSG32_LEN(i * sizeof(int)); + if (!err) + err = put_user(SOL_SOCKET, &cm->cmsg_level); + if (!err) + err = put_user(SCM_RIGHTS, &cm->cmsg_type); + if (!err) + err = put_user(cmlen, &cm->cmsg_len); + if (!err) { + cmlen = CMSG32_SPACE(i * sizeof(int)); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; + } + } + if (i < fdnum) + kmsg->msg_flags |= MSG_CTRUNC; + + /* + * All of the files that fit in the message have had their + * usage counts incremented, so we just free the list. + */ + __scm_destroy(scm); +} + +/* + * In these cases we (currently) can just copy to data over verbatim because all CMSGs + * created by the kernel have well defined types which have the same layout in both the + * 32-bit and 64-bit API. One must add some special cased conversions here if we start + * sending control messages with incompatible types. + * + * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after + * we do our work. The remaining cases are: + * + * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean + * IP_TTL int 32-bit clean + * IP_TOS __u8 32-bit clean + * IP_RECVOPTS variable length 32-bit clean + * IP_RETOPTS variable length 32-bit clean + * (these last two are clean because the types are defined + * by the IPv4 protocol) + * IP_RECVERR struct sock_extended_err + + * struct sockaddr_in 32-bit clean + * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + + * struct sockaddr_in6 32-bit clean + * IPV6_PKTINFO struct in6_pktinfo 32-bit clean + * IPV6_HOPLIMIT int 32-bit clean + * IPV6_FLOWINFO u32 32-bit clean + * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean + * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean + * IPV6_RTHDR ipv6 routing exthdr 32-bit clean + * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean + */ +static void +cmsg32_recvmsg_fixup (struct msghdr *kmsg, unsigned long orig_cmsg_uptr) +{ + unsigned char *workbuf, *wp; + unsigned long bufsz, space_avail; + struct cmsghdr *ucmsg; + long err; + + bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; + space_avail = kmsg->msg_controllen + bufsz; + wp = workbuf = kmalloc(bufsz, GFP_KERNEL); + if (workbuf == NULL) + goto fail; + + /* To make this more sane we assume the kernel sends back properly + * formatted control messages. Because of how the kernel will truncate + * the cmsg_len for MSG_TRUNC cases, we need not check that case either. + */ + ucmsg = (struct cmsghdr *) orig_cmsg_uptr; + while (((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { + struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; + int clen64, clen32; + + /* + * UCMSG is the 64-bit format CMSG entry in user-space. KCMSG32 is within + * the kernel space temporary buffer we use to convert into a 32-bit style + * CMSG. + */ + err = get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); + err |= get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); + err |= get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); + if (err) + goto fail2; + + clen64 = kcmsg32->cmsg_len; + copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), + clen64 - CMSG_ALIGN(sizeof(*ucmsg))); + clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + + CMSG32_ALIGN(sizeof(struct cmsghdr32))); + kcmsg32->cmsg_len = clen32; + + ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64)); + wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); + } + + /* Copy back fixed up data, and adjust pointers. */ + bufsz = (wp - workbuf); + if (copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz)) + goto fail2; + + kmsg->msg_control = (struct cmsghdr *) (((char *)orig_cmsg_uptr) + bufsz); + kmsg->msg_controllen = space_avail - bufsz; + kfree(workbuf); + return; + + fail2: + kfree(workbuf); + fail: + /* + * If we leave the 64-bit format CMSG chunks in there, the application could get + * confused and crash. So to ensure greater recovery, we report no CMSGs. + */ + kmsg->msg_controllen += bufsz; + kmsg->msg_control = (void *) orig_cmsg_uptr; +} + +static inline void +sockfd_put (struct socket *sock) { fput(sock->file); } @@ -1234,13 +1682,14 @@ sockfd_put(struct socket *sock) 24 for IPv6, about 80 for AX.25 */ -extern struct socket *sockfd_lookup(int fd, int *err); +extern struct socket *sockfd_lookup (int fd, int *err); /* * BSD sendmsg interface */ -int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags) +int +sys32_sendmsg (int fd, struct msghdr32 *msg, unsigned flags) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1248,10 +1697,11 @@ int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags) unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */ unsigned char *ctl_buf = ctl; struct msghdr msg_sys; - int err, ctl_len, iov_size, total_len; + int err, iov_size, total_len; + size_t ctl_len; err = -EFAULT; - if (shape_msg(&msg_sys, msg)) + if (get_msghdr32(&msg_sys, msg)) goto out; sock = sockfd_lookup(fd, &err); @@ -1282,20 +1732,12 @@ int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags) if (msg_sys.msg_controllen > INT_MAX) goto out_freeiov; - ctl_len = msg_sys.msg_controllen; - if (ctl_len) - { - if (ctl_len > sizeof(ctl)) - { - err = -ENOBUFS; - ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); - if (ctl_buf == NULL) - goto out_freeiov; - } - err = -EFAULT; - if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len)) - goto out_freectl; - msg_sys.msg_control = ctl_buf; + if (msg_sys.msg_controllen) { + ctl_len = sizeof(ctl); + err = get_cmsghdr32(&msg_sys, ctl_buf, sock->sk, &ctl_len); + if (err) + goto out_freeiov; + ctl_buf = msg_sys.msg_control; } msg_sys.msg_flags = flags; @@ -1303,7 +1745,6 @@ int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags) msg_sys.msg_flags |= MSG_DONTWAIT; err = sock_sendmsg(sock, &msg_sys, total_len); -out_freectl: if (ctl_buf != ctl) sock_kfree_s(sock->sk, ctl_buf, ctl_len); out_freeiov: @@ -1328,6 +1769,7 @@ sys32_recvmsg (int fd, struct msghdr32 *msg, unsigned int flags) struct msghdr msg_sys; unsigned long cmsg_ptr; int err, iov_size, total_len, len; + struct scm_cookie scm; /* kernel mode address */ char addr[MAX_SOCK_ADDR]; @@ -1336,8 +1778,8 @@ sys32_recvmsg (int fd, struct msghdr32 *msg, unsigned int flags) struct sockaddr *uaddr; int *uaddr_len; - err=-EFAULT; - if (shape_msg(&msg_sys, msg)) + err = -EFAULT; + if (get_msghdr32(&msg_sys, msg)) goto out; sock = sockfd_lookup(fd, &err); @@ -1374,15 +1816,44 @@ sys32_recvmsg (int fd, struct msghdr32 *msg, unsigned int flags) if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; - err = sock_recvmsg(sock, &msg_sys, total_len, flags); - if (err < 0) - goto out_freeiov; - len = err; - if (uaddr != NULL) { - err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); + memset(&scm, 0, sizeof(scm)); + + lock_kernel(); + { + err = sock->ops->recvmsg(sock, &msg_sys, total_len, flags, &scm); if (err < 0) - goto out_freeiov; + goto out_unlock_freeiov; + + len = err; + if (!msg_sys.msg_control) { + if (sock->passcred || scm.fp) + msg_sys.msg_flags |= MSG_CTRUNC; + if (scm.fp) + __scm_destroy(&scm); + } else { + /* + * If recvmsg processing itself placed some control messages into + * user space, it's is using 64-bit CMSG processing, so we need to + * fix it up before we tack on more stuff. + */ + if ((unsigned long) msg_sys.msg_control != cmsg_ptr) + cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr); + + /* Wheee... */ + if (sock->passcred) + put_cmsg32(&msg_sys, SOL_SOCKET, SCM_CREDENTIALS, + sizeof(scm.creds), &scm.creds); + if (scm.fp != NULL) + scm_detach_fds32(&msg_sys, &scm); + } + } + unlock_kernel(); + + if (uaddr != NULL) { + err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); + if (err < 0) + goto out_freeiov; } err = __put_user(msg_sys.msg_flags, &msg->msg_flags); if (err) @@ -1393,20 +1864,23 @@ sys32_recvmsg (int fd, struct msghdr32 *msg, unsigned int flags) goto out_freeiov; err = len; -out_freeiov: + out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); -out_put: + out_put: sockfd_put(sock); -out: + out: return err; + + out_unlock_freeiov: + goto out_freeiov; } /* Argument list sizes for sys_socketcall */ #define AL(x) ((x) * sizeof(u32)) -static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), - AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), - AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; +static const unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), + AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), + AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; #undef AL extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); @@ -1435,7 +1909,8 @@ extern asmlinkage long sys_socketpair(int family, int type, int protocol, extern asmlinkage long sys_shutdown(int fd, int how); extern asmlinkage long sys_listen(int fd, int backlog); -asmlinkage long sys32_socketcall(int call, u32 *args) +asmlinkage long +sys32_socketcall (int call, u32 *args) { int ret; u32 a[6]; @@ -1463,16 +1938,13 @@ asmlinkage long sys32_socketcall(int call, u32 *args) ret = sys_listen(a0, a1); break; case SYS_ACCEPT: - ret = sys_accept(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); + ret = sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_GETSOCKNAME: - ret = sys_getsockname(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); + ret = sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_GETPEERNAME: - ret = sys_getpeername(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); + ret = sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_SOCKETPAIR: ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3])); @@ -1500,12 +1972,10 @@ asmlinkage long sys32_socketcall(int call, u32 *args) ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]); break; case SYS_SENDMSG: - ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1), - a[2]); + ret = sys32_sendmsg(a0, (struct msghdr32 *) A(a1), a[2]); break; case SYS_RECVMSG: - ret = sys32_recvmsg(a0, (struct msghdr32 *)A(a1), - a[2]); + ret = sys32_recvmsg(a0, (struct msghdr32 *) A(a1), a[2]); break; default: ret = EINVAL; @@ -1522,15 +1992,28 @@ asmlinkage long sys32_socketcall(int call, u32 *args) struct msgbuf32 { s32 mtype; char mtext[1]; }; -struct ipc_perm32 -{ - key_t key; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_uid_t32 cuid; - __kernel_gid_t32 cgid; +struct ipc_perm32 { + key_t key; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_uid_t32 cuid; + __kernel_gid_t32 cgid; __kernel_mode_t32 mode; - unsigned short seq; + unsigned short seq; +}; + +struct ipc64_perm32 { + key_t key; + __kernel_uid32_t32 uid; + __kernel_gid32_t32 gid; + __kernel_uid32_t32 cuid; + __kernel_gid32_t32 cgid; + __kernel_mode_t32 mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned int unused1; + unsigned int unused2; }; struct semid_ds32 { @@ -1544,8 +2027,18 @@ struct semid_ds32 { unsigned short sem_nsems; /* no. of semaphores in array */ }; -struct msqid_ds32 -{ +struct semid64_ds32 { + struct ipc64_perm32 sem_perm; + __kernel_time_t32 sem_otime; + unsigned int __unused1; + __kernel_time_t32 sem_ctime; + unsigned int __unused2; + unsigned int sem_nsems; + unsigned int __unused3; + unsigned int __unused4; +}; + +struct msqid_ds32 { struct ipc_perm32 msg_perm; u32 msg_first; u32 msg_last; @@ -1561,110 +2054,206 @@ struct msqid_ds32 __kernel_ipc_pid_t32 msg_lrpid; }; +struct msqid64_ds32 { + struct ipc64_perm32 msg_perm; + __kernel_time_t32 msg_stime; + unsigned int __unused1; + __kernel_time_t32 msg_rtime; + unsigned int __unused2; + __kernel_time_t32 msg_ctime; + unsigned int __unused3; + unsigned int msg_cbytes; + unsigned int msg_qnum; + unsigned int msg_qbytes; + __kernel_pid_t32 msg_lspid; + __kernel_pid_t32 msg_lrpid; + unsigned int __unused4; + unsigned int __unused5; +}; + struct shmid_ds32 { - struct ipc_perm32 shm_perm; - int shm_segsz; - __kernel_time_t32 shm_atime; - __kernel_time_t32 shm_dtime; - __kernel_time_t32 shm_ctime; - __kernel_ipc_pid_t32 shm_cpid; - __kernel_ipc_pid_t32 shm_lpid; - unsigned short shm_nattch; + struct ipc_perm32 shm_perm; + int shm_segsz; + __kernel_time_t32 shm_atime; + __kernel_time_t32 shm_dtime; + __kernel_time_t32 shm_ctime; + __kernel_ipc_pid_t32 shm_cpid; + __kernel_ipc_pid_t32 shm_lpid; + unsigned short shm_nattch; +}; + +struct shmid64_ds32 { + struct ipc64_perm shm_perm; + __kernel_size_t32 shm_segsz; + __kernel_time_t32 shm_atime; + unsigned int __unused1; + __kernel_time_t32 shm_dtime; + unsigned int __unused2; + __kernel_time_t32 shm_ctime; + unsigned int __unused3; + __kernel_pid_t32 shm_cpid; + __kernel_pid_t32 shm_lpid; + unsigned int shm_nattch; + unsigned int __unused4; + unsigned int __unused5; +}; + +struct shminfo64_32 { + unsigned int shmmax; + unsigned int shmmin; + unsigned int shmmni; + unsigned int shmseg; + unsigned int shmall; + unsigned int __unused1; + unsigned int __unused2; + unsigned int __unused3; + unsigned int __unused4; +}; + +struct shm_info32 { + int used_ids; + u32 shm_tot, shm_rss, shm_swp; + u32 swap_attempts, swap_successes; +}; + +struct ipc_kludge { + struct msgbuf *msgp; + long msgtyp; }; +#define SEMOP 1 +#define SEMGET 2 +#define SEMCTL 3 +#define MSGSND 11 +#define MSGRCV 12 +#define MSGGET 13 +#define MSGCTL 14 +#define SHMAT 21 +#define SHMDT 22 +#define SHMGET 23 +#define SHMCTL 24 + #define IPCOP_MASK(__x) (1UL << (__x)) static int -do_sys32_semctl(int first, int second, int third, void *uptr) +ipc_parse_version32 (int *cmd) +{ + if (*cmd & IPC_64) { + *cmd ^= IPC_64; + return IPC_64; + } else { + return IPC_OLD; + } +} + +static int +semctl32 (int first, int second, int third, void *uptr) { union semun fourth; u32 pad; int err = 0, err2; struct semid64_ds s; - struct semid_ds32 *usp; mm_segment_t old_fs; + int version = ipc_parse_version32(&third); if (!uptr) return -EINVAL; if (get_user(pad, (u32 *)uptr)) return -EFAULT; - if(third == SETVAL) + if (third == SETVAL) fourth.val = (int)pad; else fourth.__pad = (void *)A(pad); switch (third) { - - case IPC_INFO: - case IPC_RMID: - case IPC_SET: - case SEM_INFO: - case GETVAL: - case GETPID: - case GETNCNT: - case GETZCNT: - case GETALL: - case SETVAL: - case SETALL: - err = sys_semctl (first, second, third, fourth); + case IPC_INFO: + case IPC_RMID: + case IPC_SET: + case SEM_INFO: + case GETVAL: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETALL: + case SETVAL: + case SETALL: + err = sys_semctl(first, second, third, fourth); break; - case IPC_STAT: - case SEM_STAT: - usp = (struct semid_ds32 *)A(pad); + case IPC_STAT: + case SEM_STAT: fourth.__pad = &s; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_semctl (first, second, third, fourth); - set_fs (old_fs); - err2 = put_user(s.sem_perm.key, &usp->sem_perm.key); - err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid); - err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid); - err2 |= __put_user(s.sem_perm.cuid, - &usp->sem_perm.cuid); - err2 |= __put_user (s.sem_perm.cgid, - &usp->sem_perm.cgid); - err2 |= __put_user (s.sem_perm.mode, - &usp->sem_perm.mode); - err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); - err2 |= __put_user (s.sem_otime, &usp->sem_otime); - err2 |= __put_user (s.sem_ctime, &usp->sem_ctime); - err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_semctl(first, second, third, fourth); + set_fs(old_fs); + + if (version == IPC_64) { + struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad); + + if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) { + err = -EFAULT; + break; + } + err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key); + err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid); + err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid); + err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid); + err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid); + err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode); + err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq); + err2 |= __put_user(s.sem_otime, &usp64->sem_otime); + err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime); + err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems); + } else { + struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad); + + if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) { + err = -EFAULT; + break; + } + err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key); + err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid); + err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid); + err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid); + err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid); + err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode); + err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq); + err2 |= __put_user(s.sem_otime, &usp32->sem_otime); + err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime); + err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems); + } if (err2) - err = -EFAULT; + err = -EFAULT; break; - } - return err; } static int do_sys32_msgsnd (int first, int second, int third, void *uptr) { - struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) - + 4, GFP_USER); + struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); struct msgbuf32 *up = (struct msgbuf32 *)uptr; mm_segment_t old_fs; int err; if (!p) return -ENOMEM; - err = get_user (p->mtype, &up->mtype); - err |= __copy_from_user (p->mtext, &up->mtext, second); + err = get_user(p->mtype, &up->mtype); + err |= copy_from_user(p->mtext, &up->mtext, second); if (err) goto out; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgsnd (first, p, second, third); - set_fs (old_fs); -out: - kfree (p); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgsnd(first, p, second, third); + set_fs(old_fs); + out: + kfree(p); return err; } static int -do_sys32_msgrcv (int first, int second, int msgtyp, int third, - int version, void *uptr) +do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void *uptr) { struct msgbuf32 *up; struct msgbuf *p; @@ -1679,185 +2268,281 @@ do_sys32_msgrcv (int first, int second, int msgtyp, int third, if (!uptr) goto out; err = -EFAULT; - if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge))) + if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge))) goto out; uptr = (void *)A(ipck.msgp); msgtyp = ipck.msgtyp; } err = -ENOMEM; - p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); + p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); if (!p) goto out; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgrcv (first, p, second + 4, msgtyp, third); - set_fs (old_fs); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgrcv(first, p, second + 4, msgtyp, third); + set_fs(old_fs); if (err < 0) goto free_then_out; up = (struct msgbuf32 *)uptr; - if (put_user (p->mtype, &up->mtype) || - __copy_to_user (&up->mtext, p->mtext, err)) + if (put_user(p->mtype, &up->mtype) || copy_to_user(&up->mtext, p->mtext, err)) err = -EFAULT; free_then_out: - kfree (p); + kfree(p); out: return err; } static int -do_sys32_msgctl (int first, int second, void *uptr) +msgctl32 (int first, int second, void *uptr) { int err = -EINVAL, err2; struct msqid_ds m; struct msqid64_ds m64; - struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; + struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr; + struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr; mm_segment_t old_fs; + int version = ipc_parse_version32(&second); switch (second) { - - case IPC_INFO: - case IPC_RMID: - case MSG_INFO: - err = sys_msgctl (first, second, (struct msqid_ds *)uptr); + case IPC_INFO: + case IPC_RMID: + case MSG_INFO: + err = sys_msgctl(first, second, (struct msqid_ds *)uptr); break; - case IPC_SET: - err = get_user (m.msg_perm.uid, &up->msg_perm.uid); - err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid); - err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode); - err |= __get_user (m.msg_qbytes, &up->msg_qbytes); + case IPC_SET: + if (version == IPC_64) { + err = get_user(m.msg_perm.uid, &up64->msg_perm.uid); + err |= get_user(m.msg_perm.gid, &up64->msg_perm.gid); + err |= get_user(m.msg_perm.mode, &up64->msg_perm.mode); + err |= get_user(m.msg_qbytes, &up64->msg_qbytes); + } else { + err = get_user(m.msg_perm.uid, &up32->msg_perm.uid); + err |= get_user(m.msg_perm.gid, &up32->msg_perm.gid); + err |= get_user(m.msg_perm.mode, &up32->msg_perm.mode); + err |= get_user(m.msg_qbytes, &up32->msg_qbytes); + } if (err) break; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgctl (first, second, &m); - set_fs (old_fs); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgctl(first, second, &m); + set_fs(old_fs); break; - case IPC_STAT: - case MSG_STAT: - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgctl (first, second, (void *) &m64); - set_fs (old_fs); - err2 = put_user (m64.msg_perm.key, &up->msg_perm.key); - err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid); - err2 |= __put_user(m64.msg_perm.gid, &up->msg_perm.gid); - err2 |= __put_user(m64.msg_perm.cuid, &up->msg_perm.cuid); - err2 |= __put_user(m64.msg_perm.cgid, &up->msg_perm.cgid); - err2 |= __put_user(m64.msg_perm.mode, &up->msg_perm.mode); - err2 |= __put_user(m64.msg_perm.seq, &up->msg_perm.seq); - err2 |= __put_user(m64.msg_stime, &up->msg_stime); - err2 |= __put_user(m64.msg_rtime, &up->msg_rtime); - err2 |= __put_user(m64.msg_ctime, &up->msg_ctime); - err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes); - err2 |= __put_user(m64.msg_qnum, &up->msg_qnum); - err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes); - err2 |= __put_user(m64.msg_lspid, &up->msg_lspid); - err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid); - if (err2) - err = -EFAULT; - break; + case IPC_STAT: + case MSG_STAT: + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgctl(first, second, (void *) &m64); + set_fs(old_fs); + if (version == IPC_64) { + if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { + err = -EFAULT; + break; + } + err2 = __put_user(m64.msg_perm.key, &up64->msg_perm.key); + err2 |= __put_user(m64.msg_perm.uid, &up64->msg_perm.uid); + err2 |= __put_user(m64.msg_perm.gid, &up64->msg_perm.gid); + err2 |= __put_user(m64.msg_perm.cuid, &up64->msg_perm.cuid); + err2 |= __put_user(m64.msg_perm.cgid, &up64->msg_perm.cgid); + err2 |= __put_user(m64.msg_perm.mode, &up64->msg_perm.mode); + err2 |= __put_user(m64.msg_perm.seq, &up64->msg_perm.seq); + err2 |= __put_user(m64.msg_stime, &up64->msg_stime); + err2 |= __put_user(m64.msg_rtime, &up64->msg_rtime); + err2 |= __put_user(m64.msg_ctime, &up64->msg_ctime); + err2 |= __put_user(m64.msg_cbytes, &up64->msg_cbytes); + err2 |= __put_user(m64.msg_qnum, &up64->msg_qnum); + err2 |= __put_user(m64.msg_qbytes, &up64->msg_qbytes); + err2 |= __put_user(m64.msg_lspid, &up64->msg_lspid); + err2 |= __put_user(m64.msg_lrpid, &up64->msg_lrpid); + if (err2) + err = -EFAULT; + } else { + if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { + err = -EFAULT; + break; + } + err2 = __put_user(m64.msg_perm.key, &up32->msg_perm.key); + err2 |= __put_user(m64.msg_perm.uid, &up32->msg_perm.uid); + err2 |= __put_user(m64.msg_perm.gid, &up32->msg_perm.gid); + err2 |= __put_user(m64.msg_perm.cuid, &up32->msg_perm.cuid); + err2 |= __put_user(m64.msg_perm.cgid, &up32->msg_perm.cgid); + err2 |= __put_user(m64.msg_perm.mode, &up32->msg_perm.mode); + err2 |= __put_user(m64.msg_perm.seq, &up32->msg_perm.seq); + err2 |= __put_user(m64.msg_stime, &up32->msg_stime); + err2 |= __put_user(m64.msg_rtime, &up32->msg_rtime); + err2 |= __put_user(m64.msg_ctime, &up32->msg_ctime); + err2 |= __put_user(m64.msg_cbytes, &up32->msg_cbytes); + err2 |= __put_user(m64.msg_qnum, &up32->msg_qnum); + err2 |= __put_user(m64.msg_qbytes, &up32->msg_qbytes); + err2 |= __put_user(m64.msg_lspid, &up32->msg_lspid); + err2 |= __put_user(m64.msg_lrpid, &up32->msg_lrpid); + if (err2) + err = -EFAULT; + } + break; } - return err; } static int -do_sys32_shmat (int first, int second, int third, int version, void *uptr) +shmat32 (int first, int second, int third, int version, void *uptr) { unsigned long raddr; u32 *uaddr = (u32 *)A((u32)third); int err; if (version == 1) - return -EINVAL; - err = sys_shmat (first, uptr, second, &raddr); + return -EINVAL; /* iBCS2 emulator entry point: unsupported */ + err = sys_shmat(first, uptr, second, &raddr); if (err) return err; return put_user(raddr, uaddr); } static int -do_sys32_shmctl (int first, int second, void *uptr) +shmctl32 (int first, int second, void *uptr) { int err = -EFAULT, err2; struct shmid_ds s; struct shmid64_ds s64; - struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; + struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr; + struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr; mm_segment_t old_fs; - struct shm_info32 { - int used_ids; - u32 shm_tot, shm_rss, shm_swp; - u32 swap_attempts, swap_successes; - } *uip = (struct shm_info32 *)uptr; + struct shm_info32 *uip = (struct shm_info32 *)uptr; struct shm_info si; + int version = ipc_parse_version32(&second); + struct shminfo64 smi; + struct shminfo *usi32 = (struct shminfo *) uptr; + struct shminfo64_32 *usi64 = (struct shminfo64_32 *) uptr; switch (second) { + case IPC_INFO: + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, (struct shmid_ds *)&smi); + set_fs(old_fs); + + if (version == IPC_64) { + if (!access_ok(VERIFY_WRITE, usi64, sizeof(*usi64))) { + err = -EFAULT; + break; + } + err2 = __put_user(smi.shmmax, &usi64->shmmax); + err2 |= __put_user(smi.shmmin, &usi64->shmmin); + err2 |= __put_user(smi.shmmni, &usi64->shmmni); + err2 |= __put_user(smi.shmseg, &usi64->shmseg); + err2 |= __put_user(smi.shmall, &usi64->shmall); + } else { + if (!access_ok(VERIFY_WRITE, usi32, sizeof(*usi32))) { + err = -EFAULT; + break; + } + err2 = __put_user(smi.shmmax, &usi32->shmmax); + err2 |= __put_user(smi.shmmin, &usi32->shmmin); + err2 |= __put_user(smi.shmmni, &usi32->shmmni); + err2 |= __put_user(smi.shmseg, &usi32->shmseg); + err2 |= __put_user(smi.shmall, &usi32->shmall); + } + if (err2) + err = -EFAULT; + break; - case IPC_INFO: - case IPC_RMID: - case SHM_LOCK: - case SHM_UNLOCK: - err = sys_shmctl (first, second, (struct shmid_ds *)uptr); + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + err = sys_shmctl(first, second, (struct shmid_ds *)uptr); break; - case IPC_SET: - err = get_user (s.shm_perm.uid, &up->shm_perm.uid); - err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); - err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode); + + case IPC_SET: + if (version == IPC_64) { + err = get_user(s.shm_perm.uid, &up64->shm_perm.uid); + err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid); + err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode); + } else { + err = get_user(s.shm_perm.uid, &up32->shm_perm.uid); + err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid); + err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode); + } if (err) break; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_shmctl (first, second, &s); - set_fs (old_fs); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, &s); + set_fs(old_fs); break; - case IPC_STAT: - case SHM_STAT: - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_shmctl (first, second, (void *) &s64); - set_fs (old_fs); + case IPC_STAT: + case SHM_STAT: + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, (void *) &s64); + set_fs(old_fs); if (err < 0) break; - err2 = put_user (s64.shm_perm.key, &up->shm_perm.key); - err2 |= __put_user (s64.shm_perm.uid, &up->shm_perm.uid); - err2 |= __put_user (s64.shm_perm.gid, &up->shm_perm.gid); - err2 |= __put_user (s64.shm_perm.cuid, - &up->shm_perm.cuid); - err2 |= __put_user (s64.shm_perm.cgid, - &up->shm_perm.cgid); - err2 |= __put_user (s64.shm_perm.mode, - &up->shm_perm.mode); - err2 |= __put_user (s64.shm_perm.seq, &up->shm_perm.seq); - err2 |= __put_user (s64.shm_atime, &up->shm_atime); - err2 |= __put_user (s64.shm_dtime, &up->shm_dtime); - err2 |= __put_user (s64.shm_ctime, &up->shm_ctime); - err2 |= __put_user (s64.shm_segsz, &up->shm_segsz); - err2 |= __put_user (s64.shm_nattch, &up->shm_nattch); - err2 |= __put_user (s64.shm_cpid, &up->shm_cpid); - err2 |= __put_user (s64.shm_lpid, &up->shm_lpid); + if (version == IPC_64) { + if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { + err = -EFAULT; + break; + } + err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key); + err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid); + err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid); + err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid); + err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid); + err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode); + err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq); + err2 |= __put_user(s64.shm_atime, &up64->shm_atime); + err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime); + err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime); + err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz); + err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch); + err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid); + err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid); + } else { + if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { + err = -EFAULT; + break; + } + err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key); + err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid); + err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid); + err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid); + err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid); + err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode); + err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq); + err2 |= __put_user(s64.shm_atime, &up32->shm_atime); + err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime); + err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime); + err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz); + err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch); + err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid); + err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid); + } if (err2) err = -EFAULT; break; - case SHM_INFO: - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_shmctl (first, second, (void *)&si); - set_fs (old_fs); + case SHM_INFO: + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, (void *)&si); + set_fs(old_fs); if (err < 0) break; - err2 = put_user (si.used_ids, &uip->used_ids); - err2 |= __put_user (si.shm_tot, &uip->shm_tot); - err2 |= __put_user (si.shm_rss, &uip->shm_rss); - err2 |= __put_user (si.shm_swp, &uip->shm_swp); - err2 |= __put_user (si.swap_attempts, - &uip->swap_attempts); - err2 |= __put_user (si.swap_successes, - &uip->swap_successes); + + if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip))) { + err = -EFAULT; + break; + } + err2 = __put_user(si.used_ids, &uip->used_ids); + err2 |= __put_user(si.shm_tot, &uip->shm_tot); + err2 |= __put_user(si.shm_rss, &uip->shm_rss); + err2 |= __put_user(si.shm_swp, &uip->shm_swp); + err2 |= __put_user(si.swap_attempts, &uip->swap_attempts); + err2 |= __put_user(si.swap_successes, &uip->swap_successes); if (err2) err = -EFAULT; break; @@ -1869,59 +2554,42 @@ do_sys32_shmctl (int first, int second, void *uptr) asmlinkage long sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) { - int version, err; + int version; version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; switch (call) { - - case SEMOP: + case SEMOP: /* struct sembuf is the same on 32 and 64bit :)) */ - err = sys_semop (first, (struct sembuf *)AA(ptr), - second); - break; - case SEMGET: - err = sys_semget (first, second, third); - break; - case SEMCTL: - err = do_sys32_semctl (first, second, third, - (void *)AA(ptr)); - break; - - case MSGSND: - err = do_sys32_msgsnd (first, second, third, - (void *)AA(ptr)); - break; - case MSGRCV: - err = do_sys32_msgrcv (first, second, fifth, third, - version, (void *)AA(ptr)); - break; - case MSGGET: - err = sys_msgget ((key_t) first, second); - break; - case MSGCTL: - err = do_sys32_msgctl (first, second, (void *)AA(ptr)); + return sys_semop(first, (struct sembuf *)AA(ptr), second); + case SEMGET: + return sys_semget(first, second, third); + case SEMCTL: + return semctl32(first, second, third, (void *)AA(ptr)); + + case MSGSND: + return do_sys32_msgsnd(first, second, third, (void *)AA(ptr)); + case MSGRCV: + return do_sys32_msgrcv(first, second, fifth, third, version, (void *)AA(ptr)); + case MSGGET: + return sys_msgget((key_t) first, second); + case MSGCTL: + return msgctl32(first, second, (void *)AA(ptr)); + + case SHMAT: + return shmat32(first, second, third, version, (void *)AA(ptr)); break; + case SHMDT: + return sys_shmdt((char *)AA(ptr)); + case SHMGET: + return sys_shmget(first, second, third); + case SHMCTL: + return shmctl32(first, second, (void *)AA(ptr)); - case SHMAT: - err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr)); - break; - case SHMDT: - err = sys_shmdt ((char *)AA(ptr)); - break; - case SHMGET: - err = sys_shmget (first, second, third); - break; - case SHMCTL: - err = do_sys32_shmctl (first, second, (void *)AA(ptr)); - break; - default: - err = -EINVAL; - break; + default: + return -EINVAL; } - - return err; } /* @@ -1929,7 +2597,8 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) * sys_gettimeofday(). IA64 did this but i386 Linux did not * so we have to implement this system call here. */ -asmlinkage long sys32_time(int * tloc) +asmlinkage long +sys32_time (int *tloc) { int i; @@ -1937,7 +2606,7 @@ asmlinkage long sys32_time(int * tloc) stuff it to user space. No side effects */ i = CURRENT_TIME; if (tloc) { - if (put_user(i,tloc)) + if (put_user(i, tloc)) i = -EFAULT; } return i; @@ -1967,7 +2636,10 @@ put_rusage (struct rusage32 *ru, struct rusage *r) { int err; - err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); + if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru))) + return -EFAULT; + + err = __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); @@ -1989,8 +2661,7 @@ put_rusage (struct rusage32 *ru, struct rusage *r) } asmlinkage long -sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, - struct rusage32 *ru) +sys32_wait4 (int pid, unsigned int *stat_addr, int options, struct rusage32 *ru) { if (!ru) return sys_wait4(pid, stat_addr, options, NULL); @@ -2000,37 +2671,38 @@ sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, unsigned int status; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); - set_fs (old_fs); - if (put_rusage (ru, &r)) return -EFAULT; - if (stat_addr && put_user (status, stat_addr)) + set_fs(old_fs); + if (put_rusage(ru, &r)) + return -EFAULT; + if (stat_addr && put_user(status, stat_addr)) return -EFAULT; return ret; } } asmlinkage long -sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options) +sys32_waitpid (int pid, unsigned int *stat_addr, int options) { return sys32_wait4(pid, stat_addr, options, NULL); } -extern asmlinkage long -sys_getrusage(int who, struct rusage *ru); +extern asmlinkage long sys_getrusage (int who, struct rusage *ru); asmlinkage long -sys32_getrusage(int who, struct rusage32 *ru) +sys32_getrusage (int who, struct rusage32 *ru) { struct rusage r; int ret; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_getrusage(who, &r); - set_fs (old_fs); - if (put_rusage (ru, &r)) return -EFAULT; + set_fs(old_fs); + if (put_rusage (ru, &r)) + return -EFAULT; return ret; } @@ -2041,41 +2713,41 @@ struct tms32 { __kernel_clock_t32 tms_cstime; }; -extern asmlinkage long sys_times(struct tms * tbuf); +extern asmlinkage long sys_times (struct tms * tbuf); asmlinkage long -sys32_times(struct tms32 *tbuf) +sys32_times (struct tms32 *tbuf) { + mm_segment_t old_fs = get_fs(); struct tms t; long ret; - mm_segment_t old_fs = get_fs (); int err; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_times(tbuf ? &t : NULL); - set_fs (old_fs); + set_fs(old_fs); if (tbuf) { err = put_user (IA32_TICK(t.tms_utime), &tbuf->tms_utime); - err |= __put_user (IA32_TICK(t.tms_stime), &tbuf->tms_stime); - err |= __put_user (IA32_TICK(t.tms_cutime), &tbuf->tms_cutime); - err |= __put_user (IA32_TICK(t.tms_cstime), &tbuf->tms_cstime); + err |= put_user (IA32_TICK(t.tms_stime), &tbuf->tms_stime); + err |= put_user (IA32_TICK(t.tms_cutime), &tbuf->tms_cutime); + err |= put_user (IA32_TICK(t.tms_cstime), &tbuf->tms_cstime); if (err) ret = -EFAULT; } return IA32_TICK(ret); } -unsigned int +static unsigned int ia32_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int *val) { size_t copied; unsigned int ret; copied = access_process_vm(child, addr, val, sizeof(*val), 0); - return(copied != sizeof(ret) ? -EIO : 0); + return (copied != sizeof(ret)) ? -EIO : 0; } -unsigned int +static unsigned int ia32_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int val) { @@ -2105,135 +2777,87 @@ ia32_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, #define PT_UESP 15 #define PT_SS 16 -unsigned int -getreg(struct task_struct *child, int regno) +static unsigned int +getreg (struct task_struct *child, int regno) { struct pt_regs *child_regs; child_regs = ia64_task_regs(child); switch (regno / sizeof(int)) { - - case PT_EBX: - return(child_regs->r11); - case PT_ECX: - return(child_regs->r9); - case PT_EDX: - return(child_regs->r10); - case PT_ESI: - return(child_regs->r14); - case PT_EDI: - return(child_regs->r15); - case PT_EBP: - return(child_regs->r13); - case PT_EAX: - case PT_ORIG_EAX: - return(child_regs->r8); - case PT_EIP: - return(child_regs->cr_iip); - case PT_UESP: - return(child_regs->r12); - case PT_EFL: - return(child->thread.eflag); - case PT_DS: - case PT_ES: - case PT_FS: - case PT_GS: - case PT_SS: - return((unsigned int)__USER_DS); - case PT_CS: - return((unsigned int)__USER_CS); - default: - printk(KERN_ERR "getregs:unknown register %d\n", regno); + case PT_EBX: return child_regs->r11; + case PT_ECX: return child_regs->r9; + case PT_EDX: return child_regs->r10; + case PT_ESI: return child_regs->r14; + case PT_EDI: return child_regs->r15; + case PT_EBP: return child_regs->r13; + case PT_EAX: return child_regs->r8; + case PT_ORIG_EAX: return child_regs->r1; /* see dispatch_to_ia32_handler() */ + case PT_EIP: return child_regs->cr_iip; + case PT_UESP: return child_regs->r12; + case PT_EFL: return child->thread.eflag; + case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS: + return __USER_DS; + case PT_CS: return __USER_CS; + default: + printk(KERN_ERR "ia32.getreg(): unknown register %d\n", regno); break; - } - return(0); + return 0; } -void -putreg(struct task_struct *child, int regno, unsigned int value) +static void +putreg (struct task_struct *child, int regno, unsigned int value) { struct pt_regs *child_regs; child_regs = ia64_task_regs(child); switch (regno / sizeof(int)) { - - case PT_EBX: - child_regs->r11 = value; - break; - case PT_ECX: - child_regs->r9 = value; - break; - case PT_EDX: - child_regs->r10 = value; - break; - case PT_ESI: - child_regs->r14 = value; - break; - case PT_EDI: - child_regs->r15 = value; - break; - case PT_EBP: - child_regs->r13 = value; - break; - case PT_EAX: - case PT_ORIG_EAX: - child_regs->r8 = value; - break; - case PT_EIP: - child_regs->cr_iip = value; - break; - case PT_UESP: - child_regs->r12 = value; - break; - case PT_EFL: - child->thread.eflag = value; - break; - case PT_DS: - case PT_ES: - case PT_FS: - case PT_GS: - case PT_SS: + case PT_EBX: child_regs->r11 = value; break; + case PT_ECX: child_regs->r9 = value; break; + case PT_EDX: child_regs->r10 = value; break; + case PT_ESI: child_regs->r14 = value; break; + case PT_EDI: child_regs->r15 = value; break; + case PT_EBP: child_regs->r13 = value; break; + case PT_EAX: child_regs->r8 = value; break; + case PT_ORIG_EAX: child_regs->r1 = value; break; + case PT_EIP: child_regs->cr_iip = value; break; + case PT_UESP: child_regs->r12 = value; break; + case PT_EFL: child->thread.eflag = value; break; + case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS: if (value != __USER_DS) - printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n", + printk(KERN_ERR + "ia32.putreg: attempt to set invalid segment register %d = %x\n", regno, value); break; - case PT_CS: + case PT_CS: if (value != __USER_CS) - printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n", + printk(KERN_ERR + "ia32.putreg: attempt to to set invalid segment register %d = %x\n", regno, value); break; - default: - printk(KERN_ERR "getregs:unknown register %d\n", regno); + default: + printk(KERN_ERR "ia32.putreg: unknown register %d\n", regno); break; - } } static inline void -ia32f2ia64f(void *dst, void *src) +ia32f2ia64f (void *dst, void *src) { - - __asm__ ("ldfe f6=[%1] ;;\n\t" - "stf.spill [%0]=f6" - : - : "r"(dst), "r"(src)); + asm volatile ("ldfe f6=[%1];; stf.spill [%0]=f6" :: "r"(dst), "r"(src) : "memory"); return; } static inline void -ia64f2ia32f(void *dst, void *src) +ia64f2ia32f (void *dst, void *src) { - - __asm__ ("ldf.fill f6=[%1] ;;\n\t" - "stfe [%0]=f6" - : - : "r"(dst), "r"(src)); + asm volatile ("ldf.fill f6=[%1];; stfe [%0]=f6" :: "r"(dst), "r"(src) : "memory"); return; } -void -put_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos) +static void +put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, + int tos) { struct _fpreg_ia32 *f; char buf[32]; @@ -2242,62 +2866,59 @@ put_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch if ((regno += tos) >= 8) regno -= 8; switch (regno) { - - case 0: + case 0: ia64f2ia32f(f, &ptp->f8); break; - case 1: + case 1: ia64f2ia32f(f, &ptp->f9); break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: ia64f2ia32f(f, &swp->f10 + (regno - 2)); break; - } - __copy_to_user(reg, f, sizeof(*reg)); + copy_to_user(reg, f, sizeof(*reg)); } -void -get_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos) +static void +get_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, + int tos) { if ((regno += tos) >= 8) regno -= 8; switch (regno) { - - case 0: - __copy_from_user(&ptp->f8, reg, sizeof(*reg)); + case 0: + copy_from_user(&ptp->f8, reg, sizeof(*reg)); break; - case 1: - __copy_from_user(&ptp->f9, reg, sizeof(*reg)); + case 1: + copy_from_user(&ptp->f9, reg, sizeof(*reg)); break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - __copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg)); + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg)); break; - } return; } -int -save_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save) +static int +save_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save) { struct switch_stack *swp; struct pt_regs *ptp; int i, tos; if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) - return(-EIO); + return -EIO; __put_user(tsk->thread.fcr, &save->cw); __put_user(tsk->thread.fsr, &save->sw); __put_user(tsk->thread.fsr >> 32, &save->tag); @@ -2313,11 +2934,11 @@ save_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save) tos = (tsk->thread.fsr >> 11) & 3; for (i = 0; i < 8; i++) put_fpreg(i, &save->_st[i], ptp, swp, tos); - return(0); + return 0; } -int -restore_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save) +static int +restore_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -2340,10 +2961,11 @@ restore_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save) tos = (tsk->thread.fsr >> 11) & 3; for (i = 0; i < 8; i++) get_fpreg(i, &save->_st[i], ptp, swp, tos); - return(ret ? -EFAULT : 0); + return ret ? -EFAULT : 0; } -asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long); +extern asmlinkage long sys_ptrace (long, pid_t, unsigned long, unsigned long, long, long, long, + long, long); /* * Note that the IA32 version of `ptrace' calls the IA64 routine for @@ -2358,13 +2980,12 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, { struct pt_regs *regs = (struct pt_regs *) &stack; struct task_struct *child; + unsigned int value, tmp; long i, ret; - unsigned int value; lock_kernel(); if (request == PTRACE_TRACEME) { - ret = sys_ptrace(request, pid, addr, data, - arg4, arg5, arg6, arg7, stack); + ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); goto out; } @@ -2379,8 +3000,7 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, goto out; if (request == PTRACE_ATTACH) { - ret = sys_ptrace(request, pid, addr, data, - arg4, arg5, arg6, arg7, stack); + ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); goto out; } ret = -ESRCH; @@ -2398,21 +3018,32 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, case PTRACE_PEEKDATA: /* read word at location addr */ ret = ia32_peek(regs, child, addr, &value); if (ret == 0) - ret = put_user(value, (unsigned int *)A(data)); + ret = put_user(value, (unsigned int *) A(data)); else ret = -EIO; goto out; case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ - ret = ia32_poke(regs, child, addr, (unsigned int)data); + ret = ia32_poke(regs, child, addr, data); goto out; case PTRACE_PEEKUSR: /* read word at addr in USER area */ - ret = 0; + ret = -EIO; + if ((addr & 3) || addr > 17*sizeof(int)) + break; + + tmp = getreg(child, addr); + if (!put_user(tmp, (unsigned int *) A(data))) + ret = 0; break; case PTRACE_POKEUSR: /* write word at addr in USER area */ + ret = -EIO; + if ((addr & 3) || addr > 17*sizeof(int)) + break; + + putreg(child, addr, data); ret = 0; break; @@ -2421,28 +3052,25 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, ret = -EIO; break; } - for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { - __put_user(getreg(child, i), (unsigned int *) A(data)); + for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) { + put_user(getreg(child, i), (unsigned int *) A(data)); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_SETREGS: - { - unsigned int tmp; if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) { ret = -EIO; break; } - for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { - __get_user(tmp, (unsigned int *) A(data)); + for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) { + get_user(tmp, (unsigned int *) A(data)); putreg(child, i, tmp); data += sizeof(int); } ret = 0; break; - } case IA32_PTRACE_GETFPREGS: ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data)); @@ -2457,10 +3085,8 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, case PTRACE_KILL: case PTRACE_SINGLESTEP: /* execute chile for one instruction */ case PTRACE_DETACH: /* detach a process */ - unlock_kernel(); - ret = sys_ptrace(request, pid, addr, data, - arg4, arg5, arg6, arg7, stack); - return(ret); + ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); + break; default: ret = -EIO; @@ -2477,7 +3103,10 @@ get_flock32(struct flock *kfl, struct flock32 *ufl) { int err; - err = get_user(kfl->l_type, &ufl->l_type); + if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl))) + return -EFAULT; + + err = __get_user(kfl->l_type, &ufl->l_type); err |= __get_user(kfl->l_whence, &ufl->l_whence); err |= __get_user(kfl->l_start, &ufl->l_start); err |= __get_user(kfl->l_len, &ufl->l_len); @@ -2490,6 +3119,9 @@ put_flock32(struct flock *kfl, struct flock32 *ufl) { int err; + if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl))) + return -EFAULT; + err = __put_user(kfl->l_type, &ufl->l_type); err |= __put_user(kfl->l_whence, &ufl->l_whence); err |= __put_user(kfl->l_start, &ufl->l_start); @@ -2498,71 +3130,43 @@ put_flock32(struct flock *kfl, struct flock32 *ufl) return err; } -extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, - unsigned long arg); +extern asmlinkage long sys_fcntl (unsigned int fd, unsigned int cmd, unsigned long arg); asmlinkage long -sys32_fcntl(unsigned int fd, unsigned int cmd, int arg) +sys32_fcntl (unsigned int fd, unsigned int cmd, unsigned int arg) { - struct flock f; mm_segment_t old_fs; + struct flock f; long ret; switch (cmd) { - case F_GETLK: - case F_SETLK: - case F_SETLKW: - if(get_flock32(&f, (struct flock32 *)((long)arg))) + case F_GETLK: + case F_SETLK: + case F_SETLKW: + if (get_flock32(&f, (struct flock32 *) A(arg))) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_fcntl(fd, cmd, (unsigned long)&f); + ret = sys_fcntl(fd, cmd, (unsigned long) &f); set_fs(old_fs); - if(cmd == F_GETLK && put_flock32(&f, (struct flock32 *)((long)arg))) + if (cmd == F_GETLK && put_flock32(&f, (struct flock32 *) A(arg))) return -EFAULT; return ret; - default: + + default: /* * `sys_fcntl' lies about arg, for the F_SETOWN * sub-function arg can have a negative value. */ - return sys_fcntl(fd, cmd, (unsigned long)((long)arg)); - } -} - -asmlinkage long -sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset32_t mask; - - ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); - ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - ret |= __get_user(mask, &act->sa_mask); - if (ret) - return ret; - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); - ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + return sys_fcntl(fd, cmd, arg); } - - return ret; } asmlinkage long sys_ni_syscall(void); asmlinkage long -sys32_ni_syscall(int dummy0, int dummy1, int dummy2, int dummy3, - int dummy4, int dummy5, int dummy6, int dummy7, int stack) +sys32_ni_syscall (int dummy0, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, + int dummy6, int dummy7, int stack) { struct pt_regs *regs = (struct pt_regs *)&stack; @@ -2577,7 +3181,7 @@ sys32_ni_syscall(int dummy0, int dummy1, int dummy2, int dummy3, #define IOLEN ((65536 / 4) * 4096) asmlinkage long -sys_iopl (int level) +sys32_iopl (int level) { extern unsigned long ia64_iobase; int fd; @@ -2612,9 +3216,8 @@ sys_iopl (int level) up_write(¤t->mm->mmap_sem); if (addr >= 0) { - ia64_set_kr(IA64_KR_IO_BASE, addr); old = (old & ~0x3000) | (level << 12); - __asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old)); + asm volatile ("mov ar.eflag=%0;;" :: "r"(old)); } fput(file); @@ -2623,7 +3226,7 @@ sys_iopl (int level) } asmlinkage long -sys_ioperm (unsigned int from, unsigned int num, int on) +sys32_ioperm (unsigned int from, unsigned int num, int on) { /* @@ -2636,7 +3239,7 @@ sys_ioperm (unsigned int from, unsigned int num, int on) * XXX proper ioperm() support should be emulated by * manipulating the page protections... */ - return sys_iopl(3); + return sys32_iopl(3); } typedef struct { @@ -2646,10 +3249,8 @@ typedef struct { } ia32_stack_t; asmlinkage long -sys32_sigaltstack (const ia32_stack_t *uss32, ia32_stack_t *uoss32, -long arg2, long arg3, long arg4, -long arg5, long arg6, long arg7, -long stack) +sys32_sigaltstack (ia32_stack_t *uss32, ia32_stack_t *uoss32, + long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt = (struct pt_regs *) &stack; stack_t uss, uoss; @@ -2658,8 +3259,8 @@ long stack) mm_segment_t old_fs = get_fs(); if (uss32) - if (copy_from_user(&buf32, (void *)A(uss32), sizeof(ia32_stack_t))) - return(-EFAULT); + if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t))) + return -EFAULT; uss.ss_sp = (void *) (long) buf32.ss_sp; uss.ss_flags = buf32.ss_flags; uss.ss_size = buf32.ss_size; @@ -2672,34 +3273,34 @@ long stack) buf32.ss_sp = (long) uoss.ss_sp; buf32.ss_flags = uoss.ss_flags; buf32.ss_size = uoss.ss_size; - if (copy_to_user((void*)A(uoss32), &buf32, sizeof(ia32_stack_t))) - return(-EFAULT); + if (copy_to_user(uoss32, &buf32, sizeof(ia32_stack_t))) + return -EFAULT; } - return(ret); + return ret; } asmlinkage int -sys_pause (void) +sys32_pause (void) { current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND; } -asmlinkage long sys_msync(unsigned long start, size_t len, int flags); +asmlinkage long sys_msync (unsigned long start, size_t len, int flags); asmlinkage int -sys32_msync(unsigned int start, unsigned int len, int flags) +sys32_msync (unsigned int start, unsigned int len, int flags) { unsigned int addr; if (OFFSET4K(start)) return -EINVAL; - addr = start & PAGE_MASK; - return(sys_msync(addr, len + (start - addr), flags)); + addr = PAGE_START(start); + return sys_msync(addr, len + (start - addr), flags); } -struct sysctl_ia32 { +struct sysctl32 { unsigned int name; int nlen; unsigned int oldval; @@ -2712,16 +3313,16 @@ struct sysctl_ia32 { extern asmlinkage long sys_sysctl(struct __sysctl_args *args); asmlinkage long -sys32_sysctl(struct sysctl_ia32 *args32) +sys32_sysctl (struct sysctl32 *args) { - struct sysctl_ia32 a32; + struct sysctl32 a32; mm_segment_t old_fs = get_fs (); void *oldvalp, *newvalp; size_t oldlen; int *namep; long ret; - if (copy_from_user(&a32, args32, sizeof (a32))) + if (copy_from_user(&a32, args, sizeof(a32))) return -EFAULT; /* @@ -2754,7 +3355,7 @@ sys32_sysctl(struct sysctl_ia32 *args32) } asmlinkage long -sys32_newuname(struct new_utsname * name) +sys32_newuname (struct new_utsname *name) { extern asmlinkage long sys_newuname(struct new_utsname * name); int ret = sys_newuname(name); @@ -2765,10 +3366,10 @@ sys32_newuname(struct new_utsname * name) return ret; } -extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +extern asmlinkage long sys_getresuid (uid_t *ruid, uid_t *euid, uid_t *suid); asmlinkage long -sys32_getresuid (u16 *ruid, u16 *euid, u16 *suid) +sys32_getresuid16 (u16 *ruid, u16 *euid, u16 *suid) { uid_t a, b, c; int ret; @@ -2786,7 +3387,7 @@ sys32_getresuid (u16 *ruid, u16 *euid, u16 *suid) extern asmlinkage long sys_getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid); asmlinkage long -sys32_getresgid(u16 *rgid, u16 *egid, u16 *sgid) +sys32_getresgid16 (u16 *rgid, u16 *egid, u16 *sgid) { gid_t a, b, c; int ret; @@ -2796,15 +3397,13 @@ sys32_getresgid(u16 *rgid, u16 *egid, u16 *sgid) ret = sys_getresgid(&a, &b, &c); set_fs(old_fs); - if (!ret) { - ret = put_user(a, rgid); - ret |= put_user(b, egid); - ret |= put_user(c, sgid); - } - return ret; + if (ret) + return ret; + + return put_user(a, rgid) | put_user(b, egid) | put_user(c, sgid); } -int +asmlinkage long sys32_lseek (unsigned int fd, int offset, unsigned int whence) { extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin); @@ -2813,37 +3412,273 @@ sys32_lseek (unsigned int fd, int offset, unsigned int whence) return sys_lseek(fd, offset, whence); } -#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ +extern asmlinkage long sys_getgroups (int gidsetsize, gid_t *grouplist); -/* In order to reduce some races, while at the same time doing additional - * checking and hopefully speeding things up, we copy filenames to the - * kernel data space before using them.. - * - * POSIX.1 2.4: an empty pathname is invalid (ENOENT). - */ -static inline int -do_getname32(const char *filename, char *page) +asmlinkage long +sys32_getgroups16 (int gidsetsize, short *grouplist) { - int retval; + mm_segment_t old_fs = get_fs(); + gid_t gl[NGROUPS]; + int ret, i; - /* 32bit pointer will be always far below TASK_SIZE :)) */ - retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE); - if (retval > 0) { - if (retval < PAGE_SIZE) - return 0; - return -ENAMETOOLONG; - } else if (!retval) - retval = -ENOENT; - return retval; + set_fs(KERNEL_DS); + ret = sys_getgroups(gidsetsize, gl); + set_fs(old_fs); + + if (gidsetsize && ret > 0 && ret <= NGROUPS) + for (i = 0; i < ret; i++, grouplist++) + if (put_user(gl[i], grouplist)) + return -EFAULT; + return ret; } -char * -getname32(const char *filename) +extern asmlinkage long sys_setgroups (int gidsetsize, gid_t *grouplist); + +asmlinkage long +sys32_setgroups16 (int gidsetsize, short *grouplist) { - char *tmp, *result; + mm_segment_t old_fs = get_fs(); + gid_t gl[NGROUPS]; + int ret, i; - result = ERR_PTR(-ENOMEM); - tmp = (char *)__get_free_page(GFP_KERNEL); + if ((unsigned) gidsetsize > NGROUPS) + return -EINVAL; + for (i = 0; i < gidsetsize; i++, grouplist++) + if (get_user(gl[i], grouplist)) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_setgroups(gidsetsize, gl); + set_fs(old_fs); + return ret; +} + +/* + * Unfortunately, the x86 compiler aligns variables of type "long long" to a 4 byte boundary + * only, which means that the x86 version of "struct flock64" doesn't match the ia64 version + * of struct flock. + */ + +static inline long +ia32_put_flock (struct flock *l, unsigned long addr) +{ + return (put_user(l->l_type, (short *) addr) + | put_user(l->l_whence, (short *) (addr + 2)) + | put_user(l->l_start, (long *) (addr + 4)) + | put_user(l->l_len, (long *) (addr + 12)) + | put_user(l->l_pid, (int *) (addr + 20))); +} + +static inline long +ia32_get_flock (struct flock *l, unsigned long addr) +{ + unsigned int start_lo, start_hi, len_lo, len_hi; + int err = (get_user(l->l_type, (short *) addr) + | get_user(l->l_whence, (short *) (addr + 2)) + | get_user(start_lo, (int *) (addr + 4)) + | get_user(start_hi, (int *) (addr + 8)) + | get_user(len_lo, (int *) (addr + 12)) + | get_user(len_hi, (int *) (addr + 16)) + | get_user(l->l_pid, (int *) (addr + 20))); + l->l_start = ((unsigned long) start_hi << 32) | start_lo; + l->l_len = ((unsigned long) len_hi << 32) | len_lo; + return err; +} + +asmlinkage long +sys32_fcntl64 (unsigned int fd, unsigned int cmd, unsigned int arg) +{ + mm_segment_t old_fs; + struct flock f; + long ret; + + switch (cmd) { + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + if (ia32_get_flock(&f, arg)) + return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_fcntl(fd, cmd, (unsigned long) &f); + set_fs(old_fs); + if (cmd == F_GETLK && ia32_put_flock(&f, arg)) + return -EFAULT; + break; + + default: + ret = sys32_fcntl(fd, cmd, arg); + break; + } + return ret; +} + +asmlinkage long +sys32_truncate64 (unsigned int path, unsigned int len_lo, unsigned int len_hi) +{ + extern asmlinkage long sys_truncate (const char *path, unsigned long length); + + return sys_truncate((const char *) A(path), ((unsigned long) len_hi << 32) | len_lo); +} + +asmlinkage long +sys32_ftruncate64 (int fd, unsigned int len_lo, unsigned int len_hi) +{ + extern asmlinkage long sys_ftruncate (int fd, unsigned long length); + + return sys_ftruncate(fd, ((unsigned long) len_hi << 32) | len_lo); +} + +static int +putstat64 (struct stat64 *ubuf, struct stat *kbuf) +{ + int err; + + if (clear_user(ubuf, sizeof(*ubuf))) + return 1; + + err = __put_user(kbuf->st_dev, &ubuf->st_dev); + err |= __put_user(kbuf->st_ino, &ubuf->__st_ino); + err |= __put_user(kbuf->st_ino, &ubuf->st_ino_lo); + err |= __put_user(kbuf->st_ino >> 32, &ubuf->st_ino_hi); + err |= __put_user(kbuf->st_mode, &ubuf->st_mode); + err |= __put_user(kbuf->st_nlink, &ubuf->st_nlink); + err |= __put_user(kbuf->st_uid, &ubuf->st_uid); + err |= __put_user(kbuf->st_gid, &ubuf->st_gid); + err |= __put_user(kbuf->st_rdev, &ubuf->st_rdev); + err |= __put_user(kbuf->st_size, &ubuf->st_size_lo); + err |= __put_user((kbuf->st_size >> 32), &ubuf->st_size_hi); + err |= __put_user(kbuf->st_atime, &ubuf->st_atime); + err |= __put_user(kbuf->st_mtime, &ubuf->st_mtime); + err |= __put_user(kbuf->st_ctime, &ubuf->st_ctime); + err |= __put_user(kbuf->st_blksize, &ubuf->st_blksize); + err |= __put_user(kbuf->st_blocks, &ubuf->st_blocks); + return err; +} + +asmlinkage long +sys32_stat64 (char *filename, struct stat64 *statbuf) +{ + mm_segment_t old_fs = get_fs(); + struct stat s; + long ret; + + set_fs(KERNEL_DS); + ret = sys_newstat(filename, &s); + set_fs(old_fs); + if (putstat64(statbuf, &s)) + return -EFAULT; + return ret; +} + +asmlinkage long +sys32_lstat64 (char *filename, struct stat64 *statbuf) +{ + mm_segment_t old_fs = get_fs(); + struct stat s; + long ret; + + set_fs(KERNEL_DS); + ret = sys_newlstat(filename, &s); + set_fs(old_fs); + if (putstat64(statbuf, &s)) + return -EFAULT; + return ret; +} + +asmlinkage long +sys32_fstat64 (unsigned int fd, struct stat64 *statbuf) +{ + mm_segment_t old_fs = get_fs(); + struct stat s; + long ret; + + set_fs(KERNEL_DS); + ret = sys_newfstat(fd, &s); + set_fs(old_fs); + if (putstat64(statbuf, &s)) + return -EFAULT; + return ret; +} + +asmlinkage long +sys32_sigpending (unsigned int *set) +{ + return do_sigpending(set, sizeof(*set)); +} + +struct sysinfo32 { + s32 uptime; + u32 loads[3]; + u32 totalram; + u32 freeram; + u32 sharedram; + u32 bufferram; + u32 totalswap; + u32 freeswap; + unsigned short procs; + char _f[22]; +}; + +asmlinkage long +sys32_sysinfo (struct sysinfo32 *info) +{ + extern asmlinkage long sys_sysinfo (struct sysinfo *); + mm_segment_t old_fs = get_fs(); + struct sysinfo s; + long ret, err; + + set_fs(KERNEL_DS); + ret = sys_sysinfo(&s); + set_fs(old_fs); + + if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) + return -EFAULT; + + err = __put_user(s.uptime, &info->uptime); + err |= __put_user(s.loads[0], &info->loads[0]); + err |= __put_user(s.loads[1], &info->loads[1]); + err |= __put_user(s.loads[2], &info->loads[2]); + err |= __put_user(s.totalram, &info->totalram); + err |= __put_user(s.freeram, &info->freeram); + err |= __put_user(s.sharedram, &info->sharedram); + err |= __put_user(s.bufferram, &info->bufferram); + err |= __put_user(s.totalswap, &info->totalswap); + err |= __put_user(s.freeswap, &info->freeswap); + err |= __put_user(s.procs, &info->procs); + if (err) + return -EFAULT; + return ret; +} + +/* In order to reduce some races, while at the same time doing additional + * checking and hopefully speeding things up, we copy filenames to the + * kernel data space before using them.. + * + * POSIX.1 2.4: an empty pathname is invalid (ENOENT). + */ +static inline int +do_getname32 (const char *filename, char *page) +{ + int retval; + + /* 32bit pointer will be always far below TASK_SIZE :)) */ + retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE); + if (retval > 0) { + if (retval < PAGE_SIZE) + return 0; + return -ENAMETOOLONG; + } else if (!retval) + retval = -ENOENT; + return retval; +} + +static char * +getname32 (const char *filename) +{ + char *tmp, *result; + + result = ERR_PTR(-ENOMEM); + tmp = (char *)__get_free_page(GFP_KERNEL); if (tmp) { int retval = do_getname32(filename, tmp); @@ -2856,178 +3691,132 @@ getname32(const char *filename) return result; } -/* 32-bit timeval and related flotsam. */ - -extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); - -asmlinkage long -sys32_ioperm(u32 from, u32 num, int on) -{ - return sys_ioperm((unsigned long)from, (unsigned long)num, on); -} - struct dqblk32 { - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u32 dqb_curblocks; - __u32 dqb_ihardlimit; - __u32 dqb_isoftlimit; - __u32 dqb_curinodes; - __kernel_time_t32 dqb_btime; - __kernel_time_t32 dqb_itime; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; }; -extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, - caddr_t addr); - asmlinkage long -sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) +sys32_quotactl (int cmd, unsigned int special, int id, struct dqblk32 *addr) { + extern asmlinkage long sys_quotactl (int, const char *, int, caddr_t); int cmds = cmd >> SUBCMDSHIFT; - int err; - struct dqblk d; mm_segment_t old_fs; + struct dqblk d; char *spec; + long err; switch (cmds) { - case Q_GETQUOTA: + case Q_GETQUOTA: break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)addr, - sizeof (struct dqblk32))) + case Q_SETQUOTA: + case Q_SETUSE: + case Q_SETQLIM: + if (copy_from_user (&d, addr, sizeof(struct dqblk32))) return -EFAULT; d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; break; - default: - return sys_quotactl(cmd, special, - id, (caddr_t)addr); + default: + return sys_quotactl(cmd, (void *) A(special), id, (caddr_t) addr); } - spec = getname32 (special); + spec = getname32((void *) A(special)); err = PTR_ERR(spec); - if (IS_ERR(spec)) return err; + if (IS_ERR(spec)) + return err; old_fs = get_fs (); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); - set_fs (old_fs); - putname (spec); + set_fs(old_fs); + putname(spec); if (cmds == Q_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; ((struct dqblk32 *)&d)->dqb_itime = i; ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)addr, &d, - sizeof (struct dqblk32))) + if (copy_to_user(addr, &d, sizeof(struct dqblk32))) return -EFAULT; } return err; } -extern asmlinkage long sys_utime(char * filename, struct utimbuf * times); - -struct utimbuf32 { - __kernel_time_t32 actime, modtime; -}; - asmlinkage long -sys32_utime(char * filename, struct utimbuf32 *times) +sys32_sched_rr_get_interval (pid_t pid, struct timespec32 *interval) { - struct utimbuf t; - mm_segment_t old_fs; - int ret; - char *filenam; + extern asmlinkage long sys_sched_rr_get_interval (pid_t, struct timespec *); + mm_segment_t old_fs = get_fs(); + struct timespec t; + long ret; - if (!times) - return sys_utime(filename, NULL); - if (get_user (t.actime, ×->actime) || - __get_user (t.modtime, ×->modtime)) + set_fs(KERNEL_DS); + ret = sys_sched_rr_get_interval(pid, &t); + set_fs(old_fs); + if (put_user (t.tv_sec, &interval->tv_sec) || put_user (t.tv_nsec, &interval->tv_nsec)) return -EFAULT; - filenam = getname32 (filename); - ret = PTR_ERR(filenam); - if (!IS_ERR(filenam)) { - old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_utime(filenam, &t); - set_fs (old_fs); - putname (filenam); - } return ret; } -/* - * Ooo, nasty. We need here to frob 32-bit unsigned longs to - * 64-bit unsigned longs. - */ - -static inline int -get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset) +asmlinkage long +sys32_pread (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi) { - if (ufdset) { - unsigned long odd; - - if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32))) - return -EFAULT; + extern asmlinkage long sys_pread (unsigned int, char *, size_t, loff_t); + return sys_pread(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo); +} - odd = n & 1UL; - n &= ~1UL; - while (n) { - unsigned long h, l; - __get_user(l, ufdset); - __get_user(h, ufdset+1); - ufdset += 2; - *fdset++ = h << 32 | l; - n -= 2; - } - if (odd) - __get_user(*fdset, ufdset); - } else { - /* Tricky, must clear full unsigned long in the - * kernel fdset at the end, this makes sure that - * actually happens. - */ - memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32)); - } - return 0; +asmlinkage long +sys32_pwrite (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi) +{ + extern asmlinkage long sys_pwrite (unsigned int, const char *, size_t, loff_t); + return sys_pwrite(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo); } -static inline void -set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset) +asmlinkage long +sys32_sendfile (int out_fd, int in_fd, int *offset, unsigned int count) { - unsigned long odd; + extern asmlinkage long sys_sendfile (int, int, off_t *, size_t); + mm_segment_t old_fs = get_fs(); + long ret; + off_t of; - if (!ufdset) - return; + if (offset && get_user(of, offset)) + return -EFAULT; - odd = n & 1UL; - n &= ~1UL; - while (n) { - unsigned long h, l; - l = *fdset++; - h = l >> 32; - __put_user(l, ufdset); - __put_user(h, ufdset+1); - ufdset += 2; - n -= 2; - } - if (odd) - __put_user(*fdset, ufdset); -} + set_fs(KERNEL_DS); + ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); + set_fs(old_fs); -extern asmlinkage long sys_sysfs(int option, unsigned long arg1, - unsigned long arg2); + if (!ret && offset && put_user(of, offset)) + return -EFAULT; + + return ret; +} asmlinkage long -sys32_sysfs(int option, u32 arg1, u32 arg2) +sys32_personality (unsigned int personality) { - return sys_sysfs(option, arg1, arg2); + extern asmlinkage long sys_personality (unsigned long); + long ret; + + if (current->personality == PER_LINUX32 && personality == PER_LINUX) + personality = PER_LINUX32; + ret = sys_personality(personality); + if (ret == PER_LINUX32) + ret = PER_LINUX; + return ret; } +#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ + struct ncp_mount_data32 { int version; unsigned int ncp_fd; __kernel_uid_t32 mounted_uid; - __kernel_pid_t32 wdog_pid; + int wdog_pid; unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; unsigned int time_out; unsigned int retry_count; @@ -3060,1486 +3849,170 @@ struct smb_mount_data32 { __kernel_uid_t32 mounted_uid; __kernel_uid_t32 uid; __kernel_gid_t32 gid; - __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; -}; - -static void * -do_smb_super_data_conv(void *raw_data) -{ - struct smb_mount_data *s = (struct smb_mount_data *)raw_data; - struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; - - s->version = s32->version; - s->mounted_uid = s32->mounted_uid; - s->uid = s32->uid; - s->gid = s32->gid; - s->file_mode = s32->file_mode; - s->dir_mode = s32->dir_mode; - return raw_data; -} - -static int -copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel) -{ - int i; - unsigned long page; - struct vm_area_struct *vma; - - *kernel = 0; - if(!user) - return 0; - vma = find_vma(current->mm, (unsigned long)user); - if(!vma || (unsigned long)user < vma->vm_start) - return -EFAULT; - if(!(vma->vm_flags & VM_READ)) - return -EFAULT; - i = vma->vm_end - (unsigned long) user; - if(PAGE_SIZE <= (unsigned long) i) - i = PAGE_SIZE - 1; - if(!(page = __get_free_page(GFP_KERNEL))) - return -ENOMEM; - if(copy_from_user((void *) page, user, i)) { - free_page(page); - return -EFAULT; - } - *kernel = page; - return 0; -} - -extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void *data); - -#define SMBFS_NAME "smbfs" -#define NCPFS_NAME "ncpfs" - -asmlinkage long -sys32_mount(char *dev_name, char *dir_name, char *type, - unsigned long new_flags, u32 data) -{ - unsigned long type_page; - int err, is_smb, is_ncp; - - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - is_smb = is_ncp = 0; - err = copy_mount_stuff_to_kernel((const void *)type, &type_page); - if(err) - return err; - if(type_page) { - is_smb = !strcmp((char *)type_page, SMBFS_NAME); - is_ncp = !strcmp((char *)type_page, NCPFS_NAME); - } - if(!is_smb && !is_ncp) { - if(type_page) - free_page(type_page); - return sys_mount(dev_name, dir_name, type, new_flags, - (void *)AA(data)); - } else { - unsigned long dev_page, dir_page, data_page; - - err = copy_mount_stuff_to_kernel((const void *)dev_name, - &dev_page); - if(err) - goto out; - err = copy_mount_stuff_to_kernel((const void *)dir_name, - &dir_page); - if(err) - goto dev_out; - err = copy_mount_stuff_to_kernel((const void *)AA(data), - &data_page); - if(err) - goto dir_out; - if(is_ncp) - do_ncp_super_data_conv((void *)data_page); - else if(is_smb) - do_smb_super_data_conv((void *)data_page); - else - panic("The problem is here..."); - err = do_mount((char *)dev_page, (char *)dir_page, - (char *)type_page, new_flags, - (void *)data_page); - if(data_page) - free_page(data_page); - dir_out: - if(dir_page) - free_page(dir_page); - dev_out: - if(dev_page) - free_page(dev_page); - out: - if(type_page) - free_page(type_page); - return err; - } -} - -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - char _f[22]; -}; - -extern asmlinkage long sys_sysinfo(struct sysinfo *info); - -asmlinkage long -sys32_sysinfo(struct sysinfo32 *info) -{ - struct sysinfo s; - int ret, err; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_sysinfo(&s); - set_fs (old_fs); - err = put_user (s.uptime, &info->uptime); - err |= __put_user (s.loads[0], &info->loads[0]); - err |= __put_user (s.loads[1], &info->loads[1]); - err |= __put_user (s.loads[2], &info->loads[2]); - err |= __put_user (s.totalram, &info->totalram); - err |= __put_user (s.freeram, &info->freeram); - err |= __put_user (s.sharedram, &info->sharedram); - err |= __put_user (s.bufferram, &info->bufferram); - err |= __put_user (s.totalswap, &info->totalswap); - err |= __put_user (s.freeswap, &info->freeswap); - err |= __put_user (s.procs, &info->procs); - if (err) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_sched_rr_get_interval(pid_t pid, - struct timespec *interval); - -asmlinkage long -sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval) -{ - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_sched_rr_get_interval(pid, &t); - set_fs (old_fs); - if (put_user (t.tv_sec, &interval->tv_sec) || - __put_user (t.tv_nsec, &interval->tv_nsec)) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_sigprocmask(int how, old_sigset_t *set, - old_sigset_t *oset); - -asmlinkage long -sys32_sigprocmask(int how, old_sigset_t32 *set, old_sigset_t32 *oset) -{ - old_sigset_t s; - int ret; - mm_segment_t old_fs = get_fs(); - - if (set && get_user (s, set)) return -EFAULT; - set_fs (KERNEL_DS); - ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); - set_fs (old_fs); - if (ret) return ret; - if (oset && put_user (s, oset)) return -EFAULT; - return 0; -} - -extern asmlinkage long sys_sigpending(old_sigset_t *set); - -asmlinkage long -sys32_sigpending(old_sigset_t32 *set) -{ - old_sigset_t s; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_sigpending(&s); - set_fs (old_fs); - if (put_user (s, set)) return -EFAULT; - return ret; -} - -extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize); - -asmlinkage long -sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize) -{ - sigset_t s; - sigset_t32 s32; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_rt_sigpending(&s, sigsetsize); - set_fs (old_fs); - if (!ret) { - switch (_NSIG_WORDS) { - case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; - case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; - case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; - case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; - } - if (copy_to_user (set, &s32, sizeof(sigset_t32))) - return -EFAULT; - } - return ret; -} - -siginfo_t32 * -siginfo64to32(siginfo_t32 *d, siginfo_t *s) -{ - memset(d, 0, sizeof(siginfo_t32)); - d->si_signo = s->si_signo; - d->si_errno = s->si_errno; - d->si_code = s->si_code; - if (s->si_signo >= SIGRTMIN) { - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - /* XXX: Ouch, how to find this out??? */ - d->si_int = s->si_int; - } else switch (s->si_signo) { - /* XXX: What about POSIX1.b timers */ - case SIGCHLD: - d->si_pid = s->si_pid; - d->si_status = s->si_status; - d->si_utime = s->si_utime; - d->si_stime = s->si_stime; - break; - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - d->si_addr = (long)(s->si_addr); - /* XXX: Do we need to translate this from ia64 to ia32 traps? */ - d->si_trapno = s->si_trapno; - break; - case SIGPOLL: - d->si_band = s->si_band; - d->si_fd = s->si_fd; - break; - default: - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - break; - } - return d; -} - -siginfo_t * -siginfo32to64(siginfo_t *d, siginfo_t32 *s) -{ - d->si_signo = s->si_signo; - d->si_errno = s->si_errno; - d->si_code = s->si_code; - if (s->si_signo >= SIGRTMIN) { - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - /* XXX: Ouch, how to find this out??? */ - d->si_int = s->si_int; - } else switch (s->si_signo) { - /* XXX: What about POSIX1.b timers */ - case SIGCHLD: - d->si_pid = s->si_pid; - d->si_status = s->si_status; - d->si_utime = s->si_utime; - d->si_stime = s->si_stime; - break; - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - d->si_addr = (void *)A(s->si_addr); - /* XXX: Do we need to translate this from ia32 to ia64 traps? */ - d->si_trapno = s->si_trapno; - break; - case SIGPOLL: - d->si_band = s->si_band; - d->si_fd = s->si_fd; - break; - default: - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - break; - } - return d; -} - -extern asmlinkage long -sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, - const struct timespec *uts, size_t sigsetsize); - -asmlinkage long -sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, - struct timespec32 *uts, __kernel_size_t32 sigsetsize) -{ - sigset_t s; - sigset_t32 s32; - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs(); - siginfo_t info; - siginfo_t32 info32; - - if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) - return -EFAULT; - switch (_NSIG_WORDS) { - case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); - case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); - case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); - case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); - } - if (uts) { - ret = get_user (t.tv_sec, &uts->tv_sec); - ret |= __get_user (t.tv_nsec, &uts->tv_nsec); - if (ret) - return -EFAULT; - } - set_fs (KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); - set_fs (old_fs); - if (ret >= 0 && uinfo) { - if (copy_to_user (uinfo, siginfo64to32(&info32, &info), - sizeof(siginfo_t32))) - return -EFAULT; - } - return ret; -} - -extern asmlinkage long -sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); - -asmlinkage long -sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) -{ - siginfo_t info; - siginfo_t32 info32; - int ret; - mm_segment_t old_fs = get_fs(); - - if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) - return -EFAULT; - /* XXX: Is this correct? */ - siginfo32to64(&info, &info32); - set_fs (KERNEL_DS); - ret = sys_rt_sigqueueinfo(pid, sig, &info); - set_fs (old_fs); - return ret; -} - -extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid); - -asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) -{ - uid_t sruid, seuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - return sys_setreuid(sruid, seuid); -} - -extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); - -asmlinkage long -sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid, - __kernel_uid_t32 suid) -{ - uid_t sruid, seuid, ssuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); - return sys_setresuid(sruid, seuid, ssuid); -} - -extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); - -asmlinkage long -sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid, - __kernel_uid_t32 *suid) -{ - uid_t a, b, c; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_getresuid(&a, &b, &c); - set_fs (old_fs); - if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid)) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid); - -asmlinkage long -sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) -{ - gid_t srgid, segid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - return sys_setregid(srgid, segid); -} - -extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); - -asmlinkage long -sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid, - __kernel_gid_t32 sgid) -{ - gid_t srgid, segid, ssgid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); - return sys_setresgid(srgid, segid, ssgid); -} - -extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist); - -asmlinkage long -sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist) -{ - gid_t gl[NGROUPS]; - int ret, i; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_getgroups(gidsetsize, gl); - set_fs (old_fs); - if (gidsetsize && ret > 0 && ret <= NGROUPS) - for (i = 0; i < ret; i++, grouplist++) - if (__put_user (gl[i], grouplist)) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist); - -asmlinkage long -sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist) -{ - gid_t gl[NGROUPS]; - int ret, i; - mm_segment_t old_fs = get_fs (); - - if ((unsigned) gidsetsize > NGROUPS) - return -EINVAL; - for (i = 0; i < gidsetsize; i++, grouplist++) - if (__get_user (gl[i], grouplist)) - return -EFAULT; - set_fs (KERNEL_DS); - ret = sys_setgroups(gidsetsize, gl); - set_fs (old_fs); - return ret; -} - - -/* XXX These as well... */ -extern __inline__ struct socket * -socki_lookup(struct inode *inode) -{ - return &inode->u.socket_i; -} - -extern __inline__ struct socket * -sockfd_lookup(int fd, int *err) -{ - struct file *file; - struct inode *inode; - - if (!(file = fget(fd))) - { - *err = -EBADF; - return NULL; - } - - inode = file->f_dentry->d_inode; - if (!inode->i_sock || !socki_lookup(inode)) - { - *err = -ENOTSOCK; - fput(file); - return NULL; - } - - return socki_lookup(inode); -} - -struct msghdr32 { - u32 msg_name; - int msg_namelen; - u32 msg_iov; - __kernel_size_t32 msg_iovlen; - u32 msg_control; - __kernel_size_t32 msg_controllen; - unsigned msg_flags; -}; - -struct cmsghdr32 { - __kernel_size_t32 cmsg_len; - int cmsg_level; - int cmsg_type; -}; - -/* Bleech... */ -#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) \ - __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) -#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) \ - cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) - -#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) - -#define CMSG32_DATA(cmsg) \ - ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32)))) -#define CMSG32_SPACE(len) \ - (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len)) -#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len)) - -#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \ - (struct cmsghdr32 *)(ctl) : \ - (struct cmsghdr32 *)NULL) -#define CMSG32_FIRSTHDR(msg) \ - __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) - -__inline__ struct cmsghdr32 * -__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size, - struct cmsghdr32 *__cmsg, int __cmsg_len) -{ - struct cmsghdr32 * __ptr; - - __ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) + - CMSG32_ALIGN(__cmsg_len)); - if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) - return NULL; - - return __ptr; -} - -__inline__ struct cmsghdr32 * -cmsg32_nxthdr (struct msghdr *__msg, struct cmsghdr32 *__cmsg, int __cmsg_len) -{ - return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen, - __cmsg, __cmsg_len); -} - -static inline int -iov_from_user32_to_kern(struct iovec *kiov, struct iovec32 *uiov32, int niov) -{ - int tot_len = 0; - - while(niov > 0) { - u32 len, buf; - - if(get_user(len, &uiov32->iov_len) || - get_user(buf, &uiov32->iov_base)) { - tot_len = -EFAULT; - break; - } - tot_len += len; - kiov->iov_base = (void *)A(buf); - kiov->iov_len = (__kernel_size_t) len; - uiov32++; - kiov++; - niov--; - } - return tot_len; -} - -static inline int -msghdr_from_user32_to_kern(struct msghdr *kmsg, struct msghdr32 *umsg) -{ - u32 tmp1, tmp2, tmp3; - int err; - - err = get_user(tmp1, &umsg->msg_name); - err |= __get_user(tmp2, &umsg->msg_iov); - err |= __get_user(tmp3, &umsg->msg_control); - if (err) - return -EFAULT; - - kmsg->msg_name = (void *)A(tmp1); - kmsg->msg_iov = (struct iovec *)A(tmp2); - kmsg->msg_control = (void *)A(tmp3); - - err = get_user(kmsg->msg_namelen, &umsg->msg_namelen); - err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen); - err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); - err |= get_user(kmsg->msg_flags, &umsg->msg_flags); - - return err; -} - -/* I've named the args so it is easy to tell whose space the pointers are in. */ -static int -verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov, - char *kern_address, int mode) -{ - int tot_len; - - if(kern_msg->msg_namelen) { - if(mode==VERIFY_READ) { - int err = move_addr_to_kernel(kern_msg->msg_name, - kern_msg->msg_namelen, - kern_address); - if(err < 0) - return err; - } - kern_msg->msg_name = kern_address; - } else - kern_msg->msg_name = NULL; - - if(kern_msg->msg_iovlen > UIO_FASTIOV) { - kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec), - GFP_KERNEL); - if(!kern_iov) - return -ENOMEM; - } - - tot_len = iov_from_user32_to_kern(kern_iov, - (struct iovec32 *)kern_msg->msg_iov, - kern_msg->msg_iovlen); - if(tot_len >= 0) - kern_msg->msg_iov = kern_iov; - else if(kern_msg->msg_iovlen > UIO_FASTIOV) - kfree(kern_iov); - - return tot_len; -} - -/* There is a lot of hair here because the alignment rules (and - * thus placement) of cmsg headers and length are different for - * 32-bit apps. -DaveM - */ -static int -cmsghdr_from_user32_to_kern(struct msghdr *kmsg, unsigned char *stackbuf, - int stackbuf_size) -{ - struct cmsghdr32 *ucmsg; - struct cmsghdr *kcmsg, *kcmsg_base; - __kernel_size_t32 ucmlen; - __kernel_size_t kcmlen, tmp; - - kcmlen = 0; - kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; - ucmsg = CMSG32_FIRSTHDR(kmsg); - while(ucmsg != NULL) { - if(get_user(ucmlen, &ucmsg->cmsg_len)) - return -EFAULT; - - /* Catch bogons. */ - if(CMSG32_ALIGN(ucmlen) < - CMSG32_ALIGN(sizeof(struct cmsghdr32))) - return -EINVAL; - if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) - + ucmlen) > kmsg->msg_controllen) - return -EINVAL; - - tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + - CMSG_ALIGN(sizeof(struct cmsghdr))); - kcmlen += tmp; - ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); - } - if(kcmlen == 0) - return -EINVAL; - - /* The kcmlen holds the 64-bit version of the control length. - * It may not be modified as we do not stick it into the kmsg - * until we have successfully copied over all of the data - * from the user. - */ - if(kcmlen > stackbuf_size) - kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL); - if(kcmsg == NULL) - return -ENOBUFS; - - /* Now copy them over neatly. */ - memset(kcmsg, 0, kcmlen); - ucmsg = CMSG32_FIRSTHDR(kmsg); - while(ucmsg != NULL) { - __get_user(ucmlen, &ucmsg->cmsg_len); - tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + - CMSG_ALIGN(sizeof(struct cmsghdr))); - kcmsg->cmsg_len = tmp; - __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); - - /* Copy over the data. */ - if(copy_from_user(CMSG_DATA(kcmsg), - CMSG32_DATA(ucmsg), - (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) - goto out_free_efault; - - /* Advance. */ - kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); - ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); - } - - /* Ok, looks like we made it. Hook it up and return success. */ - kmsg->msg_control = kcmsg_base; - kmsg->msg_controllen = kcmlen; - return 0; - -out_free_efault: - if(kcmsg_base != (struct cmsghdr *)stackbuf) - kfree(kcmsg_base); - return -EFAULT; -} - -static void -put_cmsg32(struct msghdr *kmsg, int level, int type, int len, void *data) -{ - struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; - struct cmsghdr32 cmhdr; - int cmlen = CMSG32_LEN(len); - - if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { - kmsg->msg_flags |= MSG_CTRUNC; - return; - } - - if(kmsg->msg_controllen < cmlen) { - kmsg->msg_flags |= MSG_CTRUNC; - cmlen = kmsg->msg_controllen; - } - cmhdr.cmsg_level = level; - cmhdr.cmsg_type = type; - cmhdr.cmsg_len = cmlen; - - if(copy_to_user(cm, &cmhdr, sizeof cmhdr)) - return; - if(copy_to_user(CMSG32_DATA(cm), data, - cmlen - sizeof(struct cmsghdr32))) - return; - cmlen = CMSG32_SPACE(len); - kmsg->msg_control += cmlen; - kmsg->msg_controllen -= cmlen; -} - -static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm) -{ - struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; - int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) - / sizeof(int); - int fdnum = scm->fp->count; - struct file **fp = scm->fp->fp; - int *cmfptr; - int err = 0, i; - - if (fdnum < fdmax) - fdmax = fdnum; - - for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); - i < fdmax; - i++, cmfptr++) { - int new_fd; - err = get_unused_fd(); - if (err < 0) - break; - new_fd = err; - err = put_user(new_fd, cmfptr); - if (err) { - put_unused_fd(new_fd); - break; - } - /* Bump the usage count and install the file. */ - fp[i]->f_count++; - current->files->fd[new_fd] = fp[i]; - } - - if (i > 0) { - int cmlen = CMSG32_LEN(i * sizeof(int)); - if (!err) - err = put_user(SOL_SOCKET, &cm->cmsg_level); - if (!err) - err = put_user(SCM_RIGHTS, &cm->cmsg_type); - if (!err) - err = put_user(cmlen, &cm->cmsg_len); - if (!err) { - cmlen = CMSG32_SPACE(i * sizeof(int)); - kmsg->msg_control += cmlen; - kmsg->msg_controllen -= cmlen; - } - } - if (i < fdnum) - kmsg->msg_flags |= MSG_CTRUNC; - - /* - * All of the files that fit in the message have had their - * usage counts incremented, so we just free the list. - */ - __scm_destroy(scm); -} - -/* In these cases we (currently) can just copy to data over verbatim - * because all CMSGs created by the kernel have well defined types which - * have the same layout in both the 32-bit and 64-bit API. One must add - * some special cased conversions here if we start sending control messages - * with incompatible types. - * - * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after - * we do our work. The remaining cases are: - * - * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean - * IP_TTL int 32-bit clean - * IP_TOS __u8 32-bit clean - * IP_RECVOPTS variable length 32-bit clean - * IP_RETOPTS variable length 32-bit clean - * (these last two are clean because the types are defined - * by the IPv4 protocol) - * IP_RECVERR struct sock_extended_err + - * struct sockaddr_in 32-bit clean - * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + - * struct sockaddr_in6 32-bit clean - * IPV6_PKTINFO struct in6_pktinfo 32-bit clean - * IPV6_HOPLIMIT int 32-bit clean - * IPV6_FLOWINFO u32 32-bit clean - * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean - * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean - * IPV6_RTHDR ipv6 routing exthdr 32-bit clean - * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean - */ -static void -cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr) -{ - unsigned char *workbuf, *wp; - unsigned long bufsz, space_avail; - struct cmsghdr *ucmsg; - - bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; - space_avail = kmsg->msg_controllen + bufsz; - wp = workbuf = kmalloc(bufsz, GFP_KERNEL); - if(workbuf == NULL) - goto fail; - - /* To make this more sane we assume the kernel sends back properly - * formatted control messages. Because of how the kernel will truncate - * the cmsg_len for MSG_TRUNC cases, we need not check that case either. - */ - ucmsg = (struct cmsghdr *) orig_cmsg_uptr; - while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { - struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; - int clen64, clen32; - - /* UCMSG is the 64-bit format CMSG entry in user-space. - * KCMSG32 is within the kernel space temporary buffer - * we use to convert into a 32-bit style CMSG. - */ - __get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); - __get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); - - clen64 = kcmsg32->cmsg_len; - copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), - clen64 - CMSG_ALIGN(sizeof(*ucmsg))); - clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + - CMSG32_ALIGN(sizeof(struct cmsghdr32))); - kcmsg32->cmsg_len = clen32; - - ucmsg = (struct cmsghdr *) (((char *)ucmsg) + - CMSG_ALIGN(clen64)); - wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); - } - - /* Copy back fixed up data, and adjust pointers. */ - bufsz = (wp - workbuf); - copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz); - - kmsg->msg_control = (struct cmsghdr *) - (((char *)orig_cmsg_uptr) + bufsz); - kmsg->msg_controllen = space_avail - bufsz; - - kfree(workbuf); - return; - -fail: - /* If we leave the 64-bit format CMSG chunks in there, - * the application could get confused and crash. So to - * ensure greater recovery, we report no CMSGs. - */ - kmsg->msg_controllen += bufsz; - kmsg->msg_control = (void *) orig_cmsg_uptr; -} - -asmlinkage long -sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) -{ - struct socket *sock; - char address[MAX_SOCK_ADDR]; - struct iovec iov[UIO_FASTIOV]; - unsigned char ctl[sizeof(struct cmsghdr) + 20]; - unsigned char *ctl_buf = ctl; - struct msghdr kern_msg; - int err, total_len; - - if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) - return -EFAULT; - if(kern_msg.msg_iovlen > UIO_MAXIOV) - return -EINVAL; - err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ); - if (err < 0) - goto out; - total_len = err; - - if(kern_msg.msg_controllen) { - err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl)); - if(err) - goto out_freeiov; - ctl_buf = kern_msg.msg_control; - } - kern_msg.msg_flags = user_flags; - - sock = sockfd_lookup(fd, &err); - if (sock != NULL) { - if (sock->file->f_flags & O_NONBLOCK) - kern_msg.msg_flags |= MSG_DONTWAIT; - err = sock_sendmsg(sock, &kern_msg, total_len); - sockfd_put(sock); - } - - /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ - if(ctl_buf != ctl) - kfree(ctl_buf); -out_freeiov: - if(kern_msg.msg_iov != iov) - kfree(kern_msg.msg_iov); -out: - return err; -} - -asmlinkage long -sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags) -{ - struct iovec iovstack[UIO_FASTIOV]; - struct msghdr kern_msg; - char addr[MAX_SOCK_ADDR]; - struct socket *sock; - struct iovec *iov = iovstack; - struct sockaddr *uaddr; - int *uaddr_len; - unsigned long cmsg_ptr; - int err, total_len, len = 0; - - if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) - return -EFAULT; - if(kern_msg.msg_iovlen > UIO_MAXIOV) - return -EINVAL; - - uaddr = kern_msg.msg_name; - uaddr_len = &user_msg->msg_namelen; - err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); - if (err < 0) - goto out; - total_len = err; - - cmsg_ptr = (unsigned long) kern_msg.msg_control; - kern_msg.msg_flags = 0; - - sock = sockfd_lookup(fd, &err); - if (sock != NULL) { - struct scm_cookie scm; - - if (sock->file->f_flags & O_NONBLOCK) - user_flags |= MSG_DONTWAIT; - memset(&scm, 0, sizeof(scm)); - lock_kernel(); - err = sock->ops->recvmsg(sock, &kern_msg, total_len, - user_flags, &scm); - if(err >= 0) { - len = err; - if(!kern_msg.msg_control) { - if(sock->passcred || scm.fp) - kern_msg.msg_flags |= MSG_CTRUNC; - if(scm.fp) - __scm_destroy(&scm); - } else { - /* If recvmsg processing itself placed some - * control messages into user space, it's is - * using 64-bit CMSG processing, so we need - * to fix it up before we tack on more stuff. - */ - if((unsigned long) kern_msg.msg_control - != cmsg_ptr) - cmsg32_recvmsg_fixup(&kern_msg, - cmsg_ptr); - - /* Wheee... */ - if(sock->passcred) - put_cmsg32(&kern_msg, - SOL_SOCKET, SCM_CREDENTIALS, - sizeof(scm.creds), - &scm.creds); - if(scm.fp != NULL) - scm_detach_fds32(&kern_msg, &scm); - } - } - unlock_kernel(); - sockfd_put(sock); - } - - if(uaddr != NULL && err >= 0) - err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, - uaddr_len); - if(cmsg_ptr != 0 && err >= 0) { - unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); - __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - - cmsg_ptr); - err |= __put_user(uclen, &user_msg->msg_controllen); - } - if(err >= 0) - err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); - if(kern_msg.msg_iov != iov) - kfree(kern_msg.msg_iov); -out: - if(err < 0) - return err; - return len; -} - -extern void check_pending(int signum); - -#ifdef CONFIG_MODULES - -extern asmlinkage unsigned long sys_create_module(const char *name_user, - size_t size); - -asmlinkage unsigned long -sys32_create_module(const char *name_user, __kernel_size_t32 size) -{ - return sys_create_module(name_user, (size_t)size); -} - -extern asmlinkage long sys_init_module(const char *name_user, - struct module *mod_user); - -/* Hey, when you're trying to init module, take time and prepare us a nice 64bit - * module structure, even if from 32bit modutils... Why to pollute kernel... :)) - */ -asmlinkage long -sys32_init_module(const char *name_user, struct module *mod_user) -{ - return sys_init_module(name_user, mod_user); -} - -extern asmlinkage long sys_delete_module(const char *name_user); - -asmlinkage long -sys32_delete_module(const char *name_user) -{ - return sys_delete_module(name_user); -} - -struct module_info32 { - u32 addr; - u32 size; - u32 flags; - s32 usecount; -}; - -/* Query various bits about modules. */ - -static inline long -get_mod_name(const char *user_name, char **buf) -{ - unsigned long page; - long retval; - - if ((unsigned long)user_name >= TASK_SIZE - && !segment_eq(get_fs (), KERNEL_DS)) - return -EFAULT; - - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE); - if (retval > 0) { - if (retval < PAGE_SIZE) { - *buf = (char *)page; - return retval; - } - retval = -ENAMETOOLONG; - } else if (!retval) - retval = -EINVAL; - - free_page(page); - return retval; -} - -static inline void -put_mod_name(char *buf) -{ - free_page((unsigned long)buf); -} - -static __inline__ struct module * -find_module(const char *name) -{ - struct module *mod; - - for (mod = module_list; mod ; mod = mod->next) { - if (mod->flags & MOD_DELETED) - continue; - if (!strcmp(mod->name, name)) - break; - } - - return mod; -} - -static int -qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) -{ - struct module *mod; - size_t nmod, space, len; - - nmod = space = 0; - - for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) { - len = strlen(mod->name)+1; - if (len > bufsize) - goto calc_space_needed; - if (copy_to_user(buf, mod->name, len)) - return -EFAULT; - buf += len; - bufsize -= len; - space += len; - } - - if (put_user(nmod, ret)) - return -EFAULT; - else - return 0; - -calc_space_needed: - space += len; - while ((mod = mod->next)->next != NULL) - space += strlen(mod->name)+1; - - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; -} - -static int -qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) -{ - size_t i, space, len; - - if (mod->next == NULL) - return -EINVAL; - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; - - space = 0; - for (i = 0; i < mod->ndeps; ++i) { - const char *dep_name = mod->deps[i].dep->name; - - len = strlen(dep_name)+1; - if (len > bufsize) - goto calc_space_needed; - if (copy_to_user(buf, dep_name, len)) - return -EFAULT; - buf += len; - bufsize -= len; - space += len; - } - - if (put_user(i, ret)) - return -EFAULT; - else - return 0; - -calc_space_needed: - space += len; - while (++i < mod->ndeps) - space += strlen(mod->deps[i].dep->name)+1; - - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; -} - -static int -qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) -{ - size_t nrefs, space, len; - struct module_ref *ref; - - if (mod->next == NULL) - return -EINVAL; - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; - - space = 0; - for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) { - const char *ref_name = ref->ref->name; - - len = strlen(ref_name)+1; - if (len > bufsize) - goto calc_space_needed; - if (copy_to_user(buf, ref_name, len)) - return -EFAULT; - buf += len; - bufsize -= len; - space += len; - } - - if (put_user(nrefs, ret)) - return -EFAULT; - else - return 0; - -calc_space_needed: - space += len; - while ((ref = ref->next_ref) != NULL) - space += strlen(ref->ref->name)+1; - - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; -} - -static inline int -qm_symbols(struct module *mod, char *buf, size_t bufsize, - __kernel_size_t32 *ret) -{ - size_t i, space, len; - struct module_symbol *s; - char *strings; - unsigned *vals; - - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; - - space = mod->nsyms * 2*sizeof(u32); - - i = len = 0; - s = mod->syms; - - if (space > bufsize) - goto calc_space_needed; - - if (!access_ok(VERIFY_WRITE, buf, space)) - return -EFAULT; - - bufsize -= space; - vals = (unsigned *)buf; - strings = buf+space; - - for (; i < mod->nsyms ; ++i, ++s, vals += 2) { - len = strlen(s->name)+1; - if (len > bufsize) - goto calc_space_needed; - - if (copy_to_user(strings, s->name, len) - || __put_user(s->value, vals+0) - || __put_user(space, vals+1)) - return -EFAULT; - - strings += len; - bufsize -= len; - space += len; - } - - if (put_user(i, ret)) - return -EFAULT; - else - return 0; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; +}; -calc_space_needed: - for (; i < mod->nsyms; ++i, ++s) - space += strlen(s->name)+1; +static void * +do_smb_super_data_conv(void *raw_data) +{ + struct smb_mount_data *s = (struct smb_mount_data *)raw_data; + struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; + s->version = s32->version; + s->mounted_uid = s32->mounted_uid; + s->uid = s32->uid; + s->gid = s32->gid; + s->file_mode = s32->file_mode; + s->dir_mode = s32->dir_mode; + return raw_data; } -static inline int -qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +static int +copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel) { - int error = 0; - - if (mod->next == NULL) - return -EINVAL; - - if (sizeof(struct module_info32) <= bufsize) { - struct module_info32 info; - info.addr = (unsigned long)mod; - info.size = mod->size; - info.flags = mod->flags; - info.usecount = - ((mod_member_present(mod, can_unload) - && mod->can_unload) - ? -1 : atomic_read(&mod->uc.usecount)); - - if (copy_to_user(buf, &info, sizeof(struct module_info32))) - return -EFAULT; - } else - error = -ENOSPC; + int i; + unsigned long page; + struct vm_area_struct *vma; - if (put_user(sizeof(struct module_info32), ret)) + *kernel = 0; + if(!user) + return 0; + vma = find_vma(current->mm, (unsigned long)user); + if(!vma || (unsigned long)user < vma->vm_start) return -EFAULT; - - return error; + if(!(vma->vm_flags & VM_READ)) + return -EFAULT; + i = vma->vm_end - (unsigned long) user; + if(PAGE_SIZE <= (unsigned long) i) + i = PAGE_SIZE - 1; + if(!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + if(copy_from_user((void *) page, user, i)) { + free_page(page); + return -EFAULT; + } + *kernel = page; + return 0; } +extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void *data); + +#define SMBFS_NAME "smbfs" +#define NCPFS_NAME "ncpfs" + asmlinkage long -sys32_query_module(char *name_user, int which, char *buf, - __kernel_size_t32 bufsize, u32 ret) +sys32_mount(char *dev_name, char *dir_name, char *type, + unsigned long new_flags, u32 data) { - struct module *mod; - int err; + unsigned long type_page; + int err, is_smb, is_ncp; - lock_kernel(); - if (name_user == 0) { - /* This finds "kernel_module" which is not exported. */ - for(mod = module_list; mod->next != NULL; mod = mod->next) - ; + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + is_smb = is_ncp = 0; + err = copy_mount_stuff_to_kernel((const void *)type, &type_page); + if(err) + return err; + if(type_page) { + is_smb = !strcmp((char *)type_page, SMBFS_NAME); + is_ncp = !strcmp((char *)type_page, NCPFS_NAME); + } + if(!is_smb && !is_ncp) { + if(type_page) + free_page(type_page); + return sys_mount(dev_name, dir_name, type, new_flags, + (void *)AA(data)); } else { - long namelen; - char *name; + unsigned long dev_page, dir_page, data_page; - if ((namelen = get_mod_name(name_user, &name)) < 0) { - err = namelen; - goto out; - } - err = -ENOENT; - if (namelen == 0) { - /* This finds "kernel_module" which is not exported. */ - for(mod = module_list; - mod->next != NULL; - mod = mod->next) ; - } else if ((mod = find_module(name)) == NULL) { - put_mod_name(name); + err = copy_mount_stuff_to_kernel((const void *)dev_name, + &dev_page); + if(err) goto out; - } - put_mod_name(name); - } - - switch (which) - { - case 0: - err = 0; - break; - case QM_MODULES: - err = qm_modules(buf, bufsize, (__kernel_size_t32 *)AA(ret)); - break; - case QM_DEPS: - err = qm_deps(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); - break; - case QM_REFS: - err = qm_refs(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); - break; - case QM_SYMBOLS: - err = qm_symbols(mod, buf, bufsize, - (__kernel_size_t32 *)AA(ret)); - break; - case QM_INFO: - err = qm_info(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); - break; - default: - err = -EINVAL; - break; + err = copy_mount_stuff_to_kernel((const void *)dir_name, + &dir_page); + if(err) + goto dev_out; + err = copy_mount_stuff_to_kernel((const void *)AA(data), + &data_page); + if(err) + goto dir_out; + if(is_ncp) + do_ncp_super_data_conv((void *)data_page); + else if(is_smb) + do_smb_super_data_conv((void *)data_page); + else + panic("The problem is here..."); + err = do_mount((char *)dev_page, (char *)dir_page, + (char *)type_page, new_flags, + (void *)data_page); + if(data_page) + free_page(data_page); + dir_out: + if(dir_page) + free_page(dir_page); + dev_out: + if(dev_page) + free_page(dev_page); + out: + if(type_page) + free_page(type_page); + return err; } -out: - unlock_kernel(); - return err; } -struct kernel_sym32 { - u32 value; - char name[60]; -}; - -extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table); +extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid); -asmlinkage long -sys32_get_kernel_syms(struct kernel_sym32 *table) +asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) { - int len, i; - struct kernel_sym *tbl; - mm_segment_t old_fs; + uid_t sruid, seuid; - len = sys_get_kernel_syms(NULL); - if (!table) return len; - tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL); - if (!tbl) return -ENOMEM; - old_fs = get_fs(); - set_fs (KERNEL_DS); - sys_get_kernel_syms(tbl); - set_fs (old_fs); - for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) { - if (put_user (tbl[i].value, &table->value) || - copy_to_user (table->name, tbl[i].name, 60)) - break; - } - kfree (tbl); - return i; + sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); + seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); + return sys_setreuid(sruid, seuid); } -#else /* CONFIG_MODULES */ - -asmlinkage unsigned long -sys32_create_module(const char *name_user, size_t size) -{ - return -ENOSYS; -} +extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); asmlinkage long -sys32_init_module(const char *name_user, struct module *mod_user) +sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid, + __kernel_uid_t32 suid) { - return -ENOSYS; -} + uid_t sruid, seuid, ssuid; -asmlinkage long -sys32_delete_module(const char *name_user) -{ - return -ENOSYS; + sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); + seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); + ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); + return sys_setresuid(sruid, seuid, ssuid); } +extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid); + asmlinkage long -sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize, - size_t *ret) +sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) { - /* Let the program know about the new interface. Not that - it'll do them much good. */ - if (which == 0) - return 0; + gid_t srgid, segid; - return -ENOSYS; + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + return sys_setregid(srgid, segid); } +extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); + asmlinkage long -sys32_get_kernel_syms(struct kernel_sym *table) +sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid, + __kernel_gid_t32 sgid) { - return -ENOSYS; -} + gid_t srgid, segid, ssgid; -#endif /* CONFIG_MODULES */ + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); + return sys_setresgid(srgid, segid, ssgid); +} /* Stuff for NFS server syscalls... */ struct nfsctl_svc32 { @@ -4820,154 +4293,6 @@ done: return err; } -asmlinkage long sys_utimes(char *, struct timeval *); - -asmlinkage long -sys32_utimes(char *filename, struct timeval32 *tvs) -{ - char *kfilename; - struct timeval ktvs[2]; - mm_segment_t old_fs; - int ret; - - kfilename = getname32(filename); - ret = PTR_ERR(kfilename); - if (!IS_ERR(kfilename)) { - if (tvs) { - if (get_tv32(&ktvs[0], tvs) || - get_tv32(&ktvs[1], 1+tvs)) - return -EFAULT; - } - - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_utimes(kfilename, &ktvs[0]); - set_fs(old_fs); - - putname(kfilename); - } - return ret; -} - -/* These are here just in case some old ia32 binary calls it. */ -asmlinkage long -sys32_pause(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule(); - return -ERESTARTNOHAND; -} - -/* PCI config space poking. */ -extern asmlinkage long sys_pciconfig_read(unsigned long bus, - unsigned long dfn, - unsigned long off, - unsigned long len, - unsigned char *buf); - -extern asmlinkage long sys_pciconfig_write(unsigned long bus, - unsigned long dfn, - unsigned long off, - unsigned long len, - unsigned char *buf); - -asmlinkage long -sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) -{ - return sys_pciconfig_read((unsigned long) bus, - (unsigned long) dfn, - (unsigned long) off, - (unsigned long) len, - (unsigned char *)AA(ubuf)); -} - -asmlinkage long -sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) -{ - return sys_pciconfig_write((unsigned long) bus, - (unsigned long) dfn, - (unsigned long) off, - (unsigned long) len, - (unsigned char *)AA(ubuf)); -} - -extern asmlinkage long sys_prctl(int option, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5); - -asmlinkage long -sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) -{ - return sys_prctl(option, - (unsigned long) arg2, - (unsigned long) arg3, - (unsigned long) arg4, - (unsigned long) arg5); -} - - -extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf, - size_t count, loff_t pos); - -extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf, - size_t count, loff_t pos); - -typedef __kernel_ssize_t32 ssize_t32; - -asmlinkage ssize_t32 -sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count, - u32 poshi, u32 poslo) -{ - return sys_pread(fd, ubuf, count, - ((loff_t)AA(poshi) << 32) | AA(poslo)); -} - -asmlinkage ssize_t32 -sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count, - u32 poshi, u32 poslo) -{ - return sys_pwrite(fd, ubuf, count, - ((loff_t)AA(poshi) << 32) | AA(poslo)); -} - - -extern asmlinkage long sys_personality(unsigned long); - -asmlinkage long -sys32_personality(unsigned long personality) -{ - int ret; - if (current->personality == PER_LINUX32 && personality == PER_LINUX) - personality = PER_LINUX32; - ret = sys_personality(personality); - if (ret == PER_LINUX32) - ret = PER_LINUX; - return ret; -} - -extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, - size_t count); - -asmlinkage long -sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) -{ - mm_segment_t old_fs = get_fs(); - int ret; - off_t of; - - if (offset && get_user(of, offset)) - return -EFAULT; - - set_fs(KERNEL_DS); - ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); - set_fs(old_fs); - - if (!ret && offset && put_user(of, offset)) - return -EFAULT; - - return ret; -} - /* Handle adjtimex compatability. */ struct timex32 { @@ -5041,4 +4366,4 @@ sys32_adjtimex(struct timex32 *utp) return ret; } -#endif // NOTYET +#endif /* NOTYET */ diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 5f61c2063425..add409f97abc 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -16,7 +16,7 @@ export-objs := ia64_ksyms.o obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o ivt.o \ machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o -obj-$(CONFIG_IA64_GENERIC) += machvec.o iosapic.o +obj-$(CONFIG_IA64_GENERIC) += iosapic.o obj-$(CONFIG_IA64_DIG) += iosapic.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_EFI_VARS) += efivars.o diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 2ef86a8a4025..501411199347 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -9,7 +9,7 @@ * Copyright (C) 2000 Hewlett-Packard Co. * Copyright (C) 2000 David Mosberger-Tang * Copyright (C) 2000 Intel Corp. - * Copyright (C) 2000 J.I. Lee + * Copyright (C) 2000,2001 J.I. Lee * ACPI based kernel configuration manager. * ACPI 2.0 & IA64 ext 0.71 */ @@ -23,6 +23,9 @@ #include #include #include +#ifdef CONFIG_SERIAL_ACPI +#include +#endif #include #include @@ -34,6 +37,9 @@ #undef ACPI_DEBUG /* Guess what this does? */ +/* global array to record platform interrupt vectors for generic int routing */ +int platform_irq_list[ACPI_MAX_PLATFORM_IRQS]; + /* These are ugly but will be reclaimed by the kernel */ int __initdata available_cpus; int __initdata total_cpus; @@ -41,8 +47,11 @@ int __initdata total_cpus; void (*pm_idle) (void); void (*pm_power_off) (void); +asm (".weak iosapic_register_irq"); asm (".weak iosapic_register_legacy_irq"); +asm (".weak iosapic_register_platform_irq"); asm (".weak iosapic_init"); +asm (".weak iosapic_version"); const char * acpi_get_sysname (void) @@ -55,6 +64,8 @@ acpi_get_sysname (void) return "hpsim"; # elif defined (CONFIG_IA64_SGI_SN1) return "sn1"; +# elif defined (CONFIG_IA64_SGI_SN2) + return "sn2"; # elif defined (CONFIG_IA64_DIG) return "dig"; # else @@ -64,6 +75,25 @@ acpi_get_sysname (void) } +/* + * Interrupt routing API for device drivers. + * Provides the interrupt vector for a generic platform event + * (currently only CPEI implemented) + */ +int +acpi_request_vector(u32 int_type) +{ + int vector = -1; + + if (int_type < ACPI_MAX_PLATFORM_IRQS) { + /* correctable platform error interrupt */ + vector = platform_irq_list[int_type]; + } else + printk("acpi_request_vector(): invalid interrupt type\n"); + + return vector; +} + /* * Configure legacy IRQ information. */ @@ -139,15 +169,93 @@ acpi20_lsapic (char *p) } /* - * Info on platform interrupt sources: NMI. PMI, INIT, etc. + * Extract iosapic info from madt (again) to determine which iosapic + * this platform interrupt resides in + */ +static int __init +acpi20_which_iosapic (int global_vector, acpi_madt_t *madt, u32 *irq_base, char **iosapic_address) +{ + acpi_entry_iosapic_t *iosapic; + char *p, *end; + int ver, max_pin; + + p = (char *) (madt + 1); + end = p + (madt->header.length - sizeof(acpi_madt_t)); + + while (p < end) { + switch (*p) { + case ACPI20_ENTRY_IO_SAPIC: + /* collect IOSAPIC info for platform int use later */ + iosapic = (acpi_entry_iosapic_t *)p; + *irq_base = iosapic->irq_base; + *iosapic_address = ioremap(iosapic->address, 0); + /* is this the iosapic we're looking for? */ + ver = iosapic_version(*iosapic_address); + max_pin = (ver >> 16) & 0xff; + if ((global_vector - *irq_base) <= max_pin) + return 0; /* found it! */ + break; + default: + break; + } + p += p[1]; + } + return 1; +} + +/* + * Info on platform interrupt sources: NMI, PMI, INIT, etc. */ static void __init -acpi20_platform (char *p) +acpi20_platform (char *p, acpi_madt_t *madt) { + int vector; + u32 irq_base; + char *iosapic_address; + unsigned long polarity = 0, trigger = 0; acpi20_entry_platform_src_t *plat = (acpi20_entry_platform_src_t *) p; printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n", plat->iosapic_vector, plat->global_vector, plat->eid, plat->id); + + /* record platform interrupt vectors for generic int routing code */ + + if (!iosapic_register_platform_irq) { + printk("acpi20_platform(): no ACPI platform IRQ support\n"); + return; + } + + /* extract polarity and trigger info from flags */ + switch (plat->flags) { + case 0x5: polarity = 1; trigger = 1; break; + case 0x7: polarity = 0; trigger = 1; break; + case 0xd: polarity = 1; trigger = 0; break; + case 0xf: polarity = 0; trigger = 0; break; + default: + printk("acpi20_platform(): unknown flags 0x%x\n", plat->flags); + break; + } + + /* which iosapic does this IRQ belong to? */ + if (acpi20_which_iosapic(plat->global_vector, madt, &irq_base, &iosapic_address)) { + printk("acpi20_platform(): I/O SAPIC not found!\n"); + return; + } + + /* + * get vector assignment for this IRQ, set attributes, and program the IOSAPIC + * routing table + */ + vector = iosapic_register_platform_irq(plat->int_type, + plat->global_vector, + plat->iosapic_vector, + plat->eid, + plat->id, + polarity, + trigger, + irq_base, + iosapic_address); + platform_irq_list[plat->int_type] = vector; } /* @@ -173,8 +281,10 @@ acpi20_lapic_addr_override (char *p) static void __init acpi20_parse_madt (acpi_madt_t *madt) { - acpi_entry_iosapic_t *iosapic; + acpi_entry_iosapic_t *iosapic = NULL; + acpi20_entry_lsapic_t *lsapic = NULL; char *p, *end; + int i; /* Base address of IPI Message Block */ if (madt->lapic_address) { @@ -186,23 +296,27 @@ acpi20_parse_madt (acpi_madt_t *madt) p = (char *) (madt + 1); end = p + (madt->header.length - sizeof(acpi_madt_t)); + /* Initialize platform interrupt vector array */ + for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++) + platform_irq_list[i] = -1; + /* - * Splitted entry parsing to ensure ordering. + * Split-up entry parsing to ensure ordering. */ - while (p < end) { switch (*p) { - case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE: + case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE: printk("ACPI 2.0 MADT: LOCAL APIC Override\n"); acpi20_lapic_addr_override(p); break; - case ACPI20_ENTRY_LOCAL_SAPIC: + case ACPI20_ENTRY_LOCAL_SAPIC: printk("ACPI 2.0 MADT: LOCAL SAPIC\n"); + lsapic = (acpi20_entry_lsapic_t *) p; acpi20_lsapic(p); break; - case ACPI20_ENTRY_IO_SAPIC: + case ACPI20_ENTRY_IO_SAPIC: iosapic = (acpi_entry_iosapic_t *) p; if (iosapic_init) /* @@ -218,26 +332,25 @@ acpi20_parse_madt (acpi_madt_t *madt) ); break; - case ACPI20_ENTRY_PLATFORM_INT_SOURCE: + case ACPI20_ENTRY_PLATFORM_INT_SOURCE: printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n"); - acpi20_platform(p); + acpi20_platform(p, madt); break; - case ACPI20_ENTRY_LOCAL_APIC: + case ACPI20_ENTRY_LOCAL_APIC: printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); break; - case ACPI20_ENTRY_IO_APIC: + case ACPI20_ENTRY_IO_APIC: printk("ACPI 2.0 MADT: IO APIC entry\n"); break; - case ACPI20_ENTRY_NMI_SOURCE: + case ACPI20_ENTRY_NMI_SOURCE: printk("ACPI 2.0 MADT: NMI SOURCE entry\n"); break; - case ACPI20_ENTRY_LOCAL_APIC_NMI: + case ACPI20_ENTRY_LOCAL_APIC_NMI: printk("ACPI 2.0 MADT: LOCAL APIC NMI entry\n"); break; - case ACPI20_ENTRY_INT_SRC_OVERRIDE: + case ACPI20_ENTRY_INT_SRC_OVERRIDE: break; - default: + default: printk("ACPI 2.0 MADT: unknown entry skip\n"); break; break; } - p += p[1]; } @@ -245,16 +358,35 @@ acpi20_parse_madt (acpi_madt_t *madt) end = p + (madt->header.length - sizeof(acpi_madt_t)); while (p < end) { + switch (*p) { + case ACPI20_ENTRY_LOCAL_APIC: + if (lsapic) break; + printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); + /* parse local apic if there's no local Sapic */ + break; + case ACPI20_ENTRY_IO_APIC: + if (iosapic) break; + printk("ACPI 2.0 MADT: IO APIC entry\n"); + /* parse ioapic if there's no ioSapic */ + break; + default: + break; + } + p += p[1]; + } + p = (char *) (madt + 1); + end = p + (madt->header.length - sizeof(acpi_madt_t)); + + while (p < end) { switch (*p) { - case ACPI20_ENTRY_INT_SRC_OVERRIDE: + case ACPI20_ENTRY_INT_SRC_OVERRIDE: printk("ACPI 2.0 MADT: INT SOURCE Override\n"); acpi_legacy_irq(p); break; - default: + default: break; } - p += p[1]; } @@ -269,6 +401,7 @@ acpi20_parse (acpi20_rsdp_t *rsdp20) # ifdef CONFIG_ACPI acpi_xsdt_t *xsdt; acpi_desc_table_hdr_t *hdrp; + acpi_madt_t *madt; int tables, i; if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) { @@ -310,9 +443,76 @@ acpi20_parse (acpi20_rsdp_t *rsdp20) ACPI_MADT_SIG, ACPI_MADT_SIG_LEN) != 0) continue; - acpi20_parse_madt((acpi_madt_t *) hdrp); + /* Save MADT pointer for later */ + madt = (acpi_madt_t *) hdrp; + acpi20_parse_madt(madt); } +#ifdef CONFIG_SERIAL_ACPI + /* + * Now we're interested in other tables. We want the iosapics already + * initialized, so we do it in a separate loop. + */ + for (i = 0; i < tables; i++) { + hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i])); + /* + * search for SPCR and DBGP table entries so we can enable + * non-pci interrupts to IO-SAPICs. + */ + if (!strncmp(hdrp->signature, ACPI_SPCRT_SIG, ACPI_SPCRT_SIG_LEN) || + !strncmp(hdrp->signature, ACPI_DBGPT_SIG, ACPI_DBGPT_SIG_LEN)) + { + acpi_ser_t *spcr = (void *)hdrp; + unsigned long global_int; + + setup_serial_acpi(hdrp); + + /* + * ACPI is able to describe serial ports that live at non-standard + * memory space addresses and use SAPIC interrupts. If not also + * PCI devices, there would be no interrupt vector information for + * them. This checks for and fixes that situation. + */ + if (spcr->length < sizeof(acpi_ser_t)) + /* table is not long enough for full info, thus no int */ + break; + + /* + * If the device is not in PCI space, but uses a SAPIC interrupt, + * we need to program the SAPIC so that serial can autoprobe for + * the IA64 interrupt vector later on. If the device is in PCI + * space, it should already be setup via the PCI vectors + */ + if (spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE && + spcr->int_type == ACPI_SERIAL_INT_SAPIC) + { + u32 irq_base; + char *iosapic_address; + int vector; + + /* We have a UART in memory space with a SAPIC interrupt */ + global_int = ( (spcr->global_int[3] << 24) + | (spcr->global_int[2] << 16) + | (spcr->global_int[1] << 8) + | spcr->global_int[0]); + + if (!iosapic_register_irq) + continue; + + /* which iosapic does this IRQ belong to? */ + if (acpi20_which_iosapic(global_int, madt, &irq_base, + &iosapic_address) == 0) + { + vector = iosapic_register_irq(global_int, + 1, /* active high polarity */ + 1, /* edge triggered */ + irq_base, + iosapic_address); + } + } + } + } +#endif acpi_cf_terminate(); # ifdef CONFIG_SMP diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 761bba3b3ca7..9f961ed9e455 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -6,8 +6,8 @@ * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond * Copyright (C) 1999-2001 Hewlett-Packard Co. - * Copyright (C) 1999 David Mosberger-Tang - * Copyright (C) 1999-2001 Stephane Eranian + * David Mosberger-Tang + * Stephane Eranian * * All EFI Runtime Services are not implemented yet as EFI only * supports physical mode addressing on SoftSDV. This is to be fixed @@ -234,7 +234,7 @@ efi_map_pal_code (void) * The only ITLB entry in region 7 that is used is the one installed by * __start(). That entry covers a 64MB range. */ - mask = ~((1 << KERNEL_PG_SHIFT) - 1); + mask = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1); vaddr = PAGE_OFFSET + md->phys_addr; /* @@ -242,29 +242,32 @@ efi_map_pal_code (void) * mapping. * * PAL code is guaranteed to be aligned on a power of 2 between 4k and - * 256KB. Also from the documentation, it seems like there is an implicit - * guarantee that you will need only ONE ITR to map it. This implies that - * the PAL code is always aligned on its size, i.e., the closest matching - * page size supported by the TLB. Therefore PAL code is guaranteed never - * to cross a 64MB unless it is bigger than 64MB (very unlikely!). So for + * 256KB and that only one ITR is needed to map it. This implies that the + * PAL code is always aligned on its size, i.e., the closest matching page + * size supported by the TLB. Therefore PAL code is guaranteed never to + * cross a 64MB unless it is bigger than 64MB (very unlikely!). So for * now the following test is enough to determine whether or not we need a * dedicated ITR for the PAL code. */ if ((vaddr & mask) == (KERNEL_START & mask)) { - printk(__FUNCTION__ " : no need to install ITR for PAL code\n"); + printk(__FUNCTION__ ": no need to install ITR for PAL code\n"); continue; } + if (md->num_pages << 12 > IA64_GRANULE_SIZE) + panic("Woah! PAL code size bigger than a granule!"); + + mask = ~((1 << IA64_GRANULE_SHIFT) - 1); printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12), - vaddr & mask, (vaddr & mask) + KERNEL_PG_SIZE); + vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE); /* * Cannot write to CRx with PSR.ic=1 */ ia64_clear_ic(flags); ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask, - pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), KERNEL_PG_SHIFT); + pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), IA64_GRANULE_SHIFT); local_irq_restore(flags); ia64_srlz_i(); } @@ -482,5 +485,7 @@ efi_get_iobase (void) static void __exit efivars_exit(void) { +#ifdef CONFIG_PROC_FS remove_proc_entry(efi_dir->name, NULL); +#endif } diff --git a/arch/ia64/kernel/efi_stub.S b/arch/ia64/kernel/efi_stub.S index 3b6d0b95ac33..6ba03d7409ab 100644 --- a/arch/ia64/kernel/efi_stub.S +++ b/arch/ia64/kernel/efi_stub.S @@ -1,8 +1,8 @@ /* * EFI call stub. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger + * Copyright (C) 1999-2001 Hewlett-Packard Co + * David Mosberger * * This stub allows us to make EFI calls in physical mode with interrupts * turned off. We need this because we can't call SetVirtualMap() until @@ -68,17 +68,17 @@ GLOBAL_ENTRY(efi_call_phys) ;; andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared mov out3=in4 - br.call.sptk.few rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode .ret0: mov out4=in5 mov out5=in6 mov out6=in7 - br.call.sptk.few rp=b6 // call the EFI function + br.call.sptk.many rp=b6 // call the EFI function .ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 - br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode // return to virtual mode .ret2: mov ar.rsc=loc4 // restore RSE configuration mov ar.pfs=loc1 mov rp=loc0 mov gp=loc2 - br.ret.sptk.few rp + br.ret.sptk.many rp END(efi_call_phys) diff --git a/arch/ia64/kernel/efivars.c b/arch/ia64/kernel/efivars.c index 14254e8bf401..369a3fd7f0a6 100644 --- a/arch/ia64/kernel/efivars.c +++ b/arch/ia64/kernel/efivars.c @@ -65,6 +65,7 @@ MODULE_AUTHOR("Matt Domsch "); MODULE_DESCRIPTION("/proc interface to EFI Variables"); +MODULE_LICENSE("GPL"); #define EFIVARS_VERSION "0.03 2001-Apr-20" @@ -276,21 +277,20 @@ efivar_write(struct file *file, const char *buffer, if (!capable(CAP_SYS_ADMIN)) return -EACCES; - spin_lock(&efivars_lock); MOD_INC_USE_COUNT; var_data = kmalloc(size, GFP_KERNEL); if (!var_data) { MOD_DEC_USE_COUNT; - spin_unlock(&efivars_lock); return -ENOMEM; } if (copy_from_user(var_data, buffer, size)) { MOD_DEC_USE_COUNT; - spin_unlock(&efivars_lock); + kfree(var_data); return -EFAULT; } + spin_lock(&efivars_lock); /* Since the data ptr we've currently got is probably for a different variable find the right variable. diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 7380e13fadfd..07099adb1ea0 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -4,7 +4,7 @@ * Kernel entry points. * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang + * David Mosberger-Tang * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond * Copyright (C) 1999 Asit Mallick @@ -15,7 +15,7 @@ * kernel stack. This allows us to handle interrupts without changing * to physical mode. * - * Jonathan Nickin + * Jonathan Nicklin * Patrick O'Rourke * 11/07/2000 / @@ -55,7 +55,7 @@ ENTRY(ia64_execve) mov out1=in1 // argv mov out2=in2 // envp add out3=16,sp // regs - br.call.sptk.few rp=sys_execve + br.call.sptk.many rp=sys_execve .ret0: cmp4.ge p6,p7=r8,r0 mov ar.pfs=loc1 // restore ar.pfs sxt4 r8=r8 // return 64-bit result @@ -64,7 +64,7 @@ ENTRY(ia64_execve) (p6) cmp.ne pKern,pUser=r0,r0 // a successful execve() lands us in user-mode... mov rp=loc0 (p6) mov ar.pfs=r0 // clear ar.pfs on success -(p7) br.ret.sptk.few rp +(p7) br.ret.sptk.many rp /* * In theory, we'd have to zap this state only to prevent leaking of @@ -85,7 +85,7 @@ ENTRY(ia64_execve) ldf.fill f26=[sp]; ldf.fill f27=[sp]; mov f28=f0 ldf.fill f29=[sp]; ldf.fill f30=[sp]; mov f31=f0 mov ar.lc=0 - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_execve) GLOBAL_ENTRY(sys_clone2) @@ -99,7 +99,7 @@ GLOBAL_ENTRY(sys_clone2) mov out3=in2 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags - br.call.sptk.few rp=do_fork + br.call.sptk.many rp=do_fork .ret1: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 @@ -118,7 +118,7 @@ GLOBAL_ENTRY(sys_clone) mov out3=0 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags - br.call.sptk.few rp=do_fork + br.call.sptk.many rp=do_fork .ret2: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 @@ -140,23 +140,23 @@ GLOBAL_ENTRY(ia64_switch_to) dep r20=0,in0,61,3 // physical address of "current" ;; st8 [r22]=sp // save kernel stack pointer of old task - shr.u r26=r20,KERNEL_PG_SHIFT - mov r16=KERNEL_PG_NUM + shr.u r26=r20,IA64_GRANULE_SHIFT + shr.u r17=r20,KERNEL_TR_PAGE_SHIFT ;; - cmp.ne p6,p7=r26,r16 // check >= 64M && < 128M + cmp.ne p6,p7=KERNEL_TR_PAGE_NUM,r17 adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; /* - * If we've already mapped this task's page, we can skip doing it - * again. + * If we've already mapped this task's page, we can skip doing it again. */ (p6) cmp.eq p7,p6=r26,r27 -(p6) br.cond.dpnt.few .map +(p6) br.cond.dpnt .map ;; -.done: ld8 sp=[r21] // load kernel stack pointer of new task +.done: (p6) ssm psr.ic // if we we had to map, renable the psr.ic bit FIRST!!! ;; (p6) srlz.d + ld8 sp=[r21] // load kernel stack pointer of new task mov IA64_KR(CURRENT)=r20 // update "current" application register mov r8=r13 // return pointer to previously running task mov r13=in0 // set "current" pointer @@ -167,7 +167,7 @@ GLOBAL_ENTRY(ia64_switch_to) #ifdef CONFIG_SMP sync.i // ensure "fc"s done by this CPU are visible on other CPUs #endif - br.ret.sptk.few rp // boogie on out in new context + br.ret.sptk.many rp // boogie on out in new context .map: rsm psr.i | psr.ic @@ -175,7 +175,7 @@ GLOBAL_ENTRY(ia64_switch_to) ;; srlz.d or r23=r25,r20 // construct PA | page properties - mov r25=KERNEL_PG_SHIFT<<2 + mov r25=IA64_GRANULE_SHIFT<<2 ;; mov cr.itir=r25 mov cr.ifa=in0 // VA of next task... @@ -184,7 +184,7 @@ GLOBAL_ENTRY(ia64_switch_to) mov IA64_KR(CURRENT_STACK)=r26 // remember last page we mapped... ;; itr.d dtr[r25]=r23 // wire in new mapping... - br.cond.sptk.many .done + br.cond.sptk .done END(ia64_switch_to) /* @@ -212,24 +212,18 @@ GLOBAL_ENTRY(save_switch_stack) .save @priunat,r17 mov r17=ar.unat // preserve caller's .body -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) adds r3=80,sp ;; lfetch.fault.excl.nt1 [r3],128 -#endif mov ar.rsc=0 // put RSE in mode: enforced lazy, little endian, pl 0 -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) adds r2=16+128,sp ;; lfetch.fault.excl.nt1 [r2],128 lfetch.fault.excl.nt1 [r3],128 -#endif adds r14=SW(R4)+16,sp -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) ;; lfetch.fault.excl [r2] lfetch.fault.excl [r3] -#endif adds r15=SW(R5)+16,sp ;; mov r18=ar.fpsr // preserve fpsr @@ -309,7 +303,7 @@ GLOBAL_ENTRY(save_switch_stack) st8 [r2]=r20 // save ar.bspstore st8 [r3]=r21 // save predicate registers mov ar.rsc=3 // put RSE back into eager mode, pl 0 - br.cond.sptk.few b7 + br.cond.sptk.many b7 END(save_switch_stack) /* @@ -321,11 +315,9 @@ END(save_switch_stack) ENTRY(load_switch_stack) .prologue .altrp b7 - .body -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + .body lfetch.fault.nt1 [sp] -#endif adds r2=SW(AR_BSPSTORE)+16,sp adds r3=SW(AR_UNAT)+16,sp mov ar.rsc=0 // put RSE into enforced lazy mode @@ -426,7 +418,7 @@ GLOBAL_ENTRY(__ia64_syscall) ;; (p6) st4 [r2]=r8 (p6) mov r8=-1 - br.ret.sptk.few rp + br.ret.sptk.many rp END(__ia64_syscall) /* @@ -441,11 +433,11 @@ GLOBAL_ENTRY(invoke_syscall_trace) .body mov loc2=b6 ;; - br.call.sptk.few rp=syscall_trace + br.call.sptk.many rp=syscall_trace .ret3: mov rp=loc0 mov ar.pfs=loc1 mov b6=loc2 - br.ret.sptk.few rp + br.ret.sptk.many rp END(invoke_syscall_trace) /* @@ -462,21 +454,21 @@ END(invoke_syscall_trace) GLOBAL_ENTRY(ia64_trace_syscall) PT_REGS_UNWIND_INFO(0) - br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args -.ret6: br.call.sptk.few rp=b6 // do the syscall + br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args +.ret6: br.call.sptk.many rp=b6 // do the syscall strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 mov r10=0 -(p6) br.cond.sptk.few strace_error // syscall failed -> +(p6) br.cond.sptk strace_error // syscall failed -> ;; // avoid RAW on r10 strace_save_retval: .mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 .mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ia64_strace_leave_kernel: - br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value -.rety: br.cond.sptk.many ia64_leave_kernel + br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value +.rety: br.cond.sptk ia64_leave_kernel strace_error: ld8 r3=[r2] // load pt_regs.r8 @@ -487,7 +479,7 @@ strace_error: ;; (p6) mov r10=-1 (p6) mov r8=r9 - br.cond.sptk.few strace_save_retval + br.cond.sptk strace_save_retval END(ia64_trace_syscall) GLOBAL_ENTRY(ia64_ret_from_clone) @@ -497,7 +489,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) * Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the * address of the previously executing task. */ - br.call.sptk.few rp=invoke_schedule_tail + br.call.sptk.many rp=ia64_invoke_schedule_tail .ret8: adds r2=IA64_TASK_PTRACE_OFFSET,r13 ;; @@ -505,7 +497,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) ;; mov r8=0 tbit.nz p6,p0=r2,PT_TRACESYS_BIT -(p6) br strace_check_retval +(p6) br.cond.spnt strace_check_retval ;; // added stop bits to prevent r8 dependency END(ia64_ret_from_clone) // fall through @@ -519,7 +511,7 @@ GLOBAL_ENTRY(ia64_ret_from_syscall) (p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit .mem.offset 8,0 (p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit -(p7) br.cond.spnt.few handle_syscall_error // handle potential syscall failure +(p7) br.cond.spnt handle_syscall_error // handle potential syscall failure END(ia64_ret_from_syscall) // fall through GLOBAL_ENTRY(ia64_leave_kernel) @@ -527,22 +519,22 @@ GLOBAL_ENTRY(ia64_leave_kernel) lfetch.fault [sp] movl r14=.restart ;; - MOVBR(.ret.sptk,rp,r14,.restart) + mov.ret.sptk rp=r14,.restart .restart: adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13 adds r18=IA64_TASK_SIGPENDING_OFFSET,r13 #ifdef CONFIG_PERFMON - adds r19=IA64_TASK_PFM_NOTIFY_OFFSET,r13 + adds r19=IA64_TASK_PFM_MUST_BLOCK_OFFSET,r13 #endif ;; #ifdef CONFIG_PERFMON - ld8 r19=[r19] // load current->task.pfm_notify +(pUser) ld8 r19=[r19] // load current->thread.pfm_must_block #endif - ld8 r17=[r17] // load current->need_resched - ld4 r18=[r18] // load current->sigpending +(pUser) ld8 r17=[r17] // load current->need_resched +(pUser) ld4 r18=[r18] // load current->sigpending ;; #ifdef CONFIG_PERFMON - cmp.ne p9,p0=r19,r0 // current->task.pfm_notify != 0? +(pUser) cmp.ne.unc p9,p0=r19,r0 // current->thread.pfm_must_block != 0? #endif (pUser) cmp.ne.unc p7,p0=r17,r0 // current->need_resched != 0? (pUser) cmp.ne.unc p8,p0=r18,r0 // current->sigpending != 0? @@ -550,7 +542,7 @@ GLOBAL_ENTRY(ia64_leave_kernel) adds r2=PT(R8)+16,r12 adds r3=PT(R9)+16,r12 #ifdef CONFIG_PERFMON -(p9) br.call.spnt.many b7=pfm_overflow_notify +(p9) br.call.spnt.many b7=pfm_block_on_overflow #endif #if __GNUC__ < 3 (p7) br.call.spnt.many b7=invoke_schedule @@ -650,13 +642,13 @@ GLOBAL_ENTRY(ia64_leave_kernel) movl r17=PERCPU_ADDR+IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET ;; ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 -(pKern) br.cond.dpnt.few skip_rbs_switch +(pKern) br.cond.dpnt skip_rbs_switch /* * Restore user backing store. * * NOTE: alloc, loadrs, and cover can't be predicated. */ -(pNonSys) br.cond.dpnt.few dont_preserve_current_frame +(pNonSys) br.cond.dpnt dont_preserve_current_frame cover // add current frame into dirty partition ;; mov r19=ar.bsp // get new backing store pointer @@ -687,7 +679,7 @@ dont_preserve_current_frame: shladd in0=loc1,3,r17 mov in1=0 ;; - .align 32 +// .align 32 // gas-2.11.90 is unable to generate a stop bit after .align rse_clear_invalid: // cycle 0 { .mii @@ -706,7 +698,7 @@ rse_clear_invalid: }{ .mib mov loc3=0 mov loc4=0 -(pRecurse) br.call.sptk.few b6=rse_clear_invalid +(pRecurse) br.call.sptk.many b6=rse_clear_invalid }{ .mfi // cycle 2 mov loc5=0 @@ -715,7 +707,7 @@ rse_clear_invalid: }{ .mib mov loc6=0 mov loc7=0 -(pReturn) br.ret.sptk.few b6 +(pReturn) br.ret.sptk.many b6 } # undef pRecurse # undef pReturn @@ -761,24 +753,24 @@ ENTRY(handle_syscall_error) ;; .mem.offset 0,0; st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit .mem.offset 8,0; st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit - br.cond.sptk.many ia64_leave_kernel + br.cond.sptk ia64_leave_kernel END(handle_syscall_error) /* * Invoke schedule_tail(task) while preserving in0-in7, which may be needed * in case a system call gets restarted. */ -ENTRY(invoke_schedule_tail) +GLOBAL_ENTRY(ia64_invoke_schedule_tail) .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,1,0 mov loc0=rp mov out0=r8 // Address of previous task ;; - br.call.sptk.few rp=schedule_tail + br.call.sptk.many rp=schedule_tail .ret11: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp -END(invoke_schedule_tail) +END(ia64_invoke_schedule_tail) #if __GNUC__ < 3 @@ -797,7 +789,7 @@ ENTRY(invoke_schedule) mov loc0=rp ;; .body - br.call.sptk.few rp=schedule + br.call.sptk.many rp=schedule .ret14: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp @@ -824,7 +816,7 @@ ENTRY(handle_signal_delivery) .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) st8 [sp]=r9,-16 // allocate space for ar.unat and save it .body - br.call.sptk.few rp=ia64_do_signal + br.call.sptk.many rp=ia64_do_signal .ret15: .restore sp adds sp=16,sp // pop scratch stack space ;; @@ -849,7 +841,7 @@ GLOBAL_ENTRY(sys_rt_sigsuspend) .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) st8 [sp]=r9,-16 // allocate space for ar.unat and save it .body - br.call.sptk.few rp=ia64_rt_sigsuspend + br.call.sptk.many rp=ia64_rt_sigsuspend .ret17: .restore sp adds sp=16,sp // pop scratch stack space ;; @@ -871,15 +863,15 @@ ENTRY(sys_rt_sigreturn) cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall... ;; adds out0=16,sp // out0 = &sigscratch - br.call.sptk.few rp=ia64_rt_sigreturn + br.call.sptk.many rp=ia64_rt_sigreturn .ret19: .restore sp 0 adds sp=16,sp ;; ld8 r9=[sp] // load new ar.unat - MOVBR(.sptk,b7,r8,ia64_leave_kernel) + mov.sptk b7=r8,ia64_leave_kernel ;; mov ar.unat=r9 - br b7 + br.many b7 END(sys_rt_sigreturn) GLOBAL_ENTRY(ia64_prepare_handle_unaligned) @@ -890,7 +882,7 @@ GLOBAL_ENTRY(ia64_prepare_handle_unaligned) mov r16=r0 .prologue DO_SAVE_SWITCH_STACK - br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt + br.call.sptk.many rp=ia64_handle_unaligned // stack frame setup in ivt .ret21: .body DO_LOAD_SWITCH_STACK br.cond.sptk.many rp // goes to ia64_leave_kernel @@ -920,14 +912,14 @@ GLOBAL_ENTRY(unw_init_running) adds out0=16,sp // &info mov out1=r13 // current adds out2=16+EXTRA_FRAME_SIZE,sp // &switch_stack - br.call.sptk.few rp=unw_init_frame_info + br.call.sptk.many rp=unw_init_frame_info 1: adds out0=16,sp // &info mov b6=loc2 mov loc2=gp // save gp across indirect function call ;; ld8 gp=[in0] mov out1=in1 // arg - br.call.sptk.few rp=b6 // invoke the callback function + br.call.sptk.many rp=b6 // invoke the callback function 1: mov gp=loc2 // restore gp // For now, we don't allow changing registers from within @@ -1026,7 +1018,7 @@ sys_call_table: data8 sys_setpriority data8 sys_statfs data8 sys_fstatfs - data8 ia64_ni_syscall // 1105 + data8 sys_gettid // 1105 data8 sys_semget data8 sys_semop data8 sys_semctl @@ -1137,7 +1129,7 @@ sys_call_table: data8 sys_clone2 data8 sys_getdents64 data8 sys_getunwind // 1215 - data8 ia64_ni_syscall + data8 sys_readahead data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall diff --git a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h index 34051263d75e..fb80a0461569 100644 --- a/arch/ia64/kernel/entry.h +++ b/arch/ia64/kernel/entry.h @@ -1,12 +1,5 @@ #include -/* XXX fixme */ -#if defined(CONFIG_ITANIUM_B1_SPECIFIC) -# define MOVBR(type,br,gr,lbl) mov br=gr -#else -# define MOVBR(type,br,gr,lbl) mov##type br=gr,lbl -#endif - /* * Preserved registers that are shared between code in ivt.S and entry.S. Be * careful not to step on these! @@ -62,7 +55,7 @@ ;; \ .fframe IA64_SWITCH_STACK_SIZE; \ adds sp=-IA64_SWITCH_STACK_SIZE,sp; \ - MOVBR(.ret.sptk,b7,r28,1f); \ + mov.ret.sptk b7=r28,1f; \ SWITCH_STACK_SAVES(0); \ br.cond.sptk.many save_switch_stack; \ 1: @@ -71,7 +64,7 @@ movl r28=1f; \ ;; \ invala; \ - MOVBR(.ret.sptk,b7,r28,1f); \ + mov.ret.sptk b7=r28,1f; \ br.cond.sptk.many load_switch_stack; \ 1: .restore sp; \ adds sp=IA64_SWITCH_STACK_SIZE,sp diff --git a/arch/ia64/kernel/fw-emu.c b/arch/ia64/kernel/fw-emu.c index 78ee7766db2f..0d47db90a962 100644 --- a/arch/ia64/kernel/fw-emu.c +++ b/arch/ia64/kernel/fw-emu.c @@ -174,6 +174,43 @@ asm ( " ;;\n" " mov ar.lc=r9\n" " mov r8=r0\n" +" ;;\n" +"1: cmp.eq p6,p7=15,r28 /* PAL_PERF_MON_INFO */\n" +"(p7) br.cond.sptk.few 1f\n" +" mov r8=0 /* status = 0 */\n" +" movl r9 =0x12082004 /* generic=4 width=32 retired=8 cycles=18 */\n" +" mov r10=0 /* reserved */\n" +" mov r11=0 /* reserved */\n" +" mov r16=0xffff /* implemented PMC */\n" +" mov r17=0xffff /* implemented PMD */\n" +" add r18=8,r29 /* second index */\n" +" ;;\n" +" st8 [r29]=r16,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r0,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r17,16 /* store implemented PMD */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" mov r16=0xf0 /* cycles count capable PMC */\n" +" ;;\n" +" st8 [r29]=r0,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" mov r17=0x10 /* retired bundles capable PMC */\n" +" ;;\n" +" st8 [r29]=r16,16 /* store cycles capable */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r0,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r17,16 /* store retired bundle capable */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r0,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" "1: br.cond.sptk.few rp\n" "stacked:\n" " br.ret.sptk.few rp\n" @@ -416,11 +453,6 @@ sys_fw_init (const char *args, int arglen) strcpy(sal_systab->product_id, "SDV"); #endif -#ifdef CONFIG_IA64_SGI_SN1_SIM - strcpy(sal_systab->oem_id, "SGI"); - strcpy(sal_systab->product_id, "SN1"); -#endif - /* fill in an entry point: */ sal_ed->type = SAL_DESC_ENTRY_POINT; sal_ed->pal_proc = __pa(pal_desc[0]); diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S index 05942e22977d..774c1b9bf0b3 100644 --- a/arch/ia64/kernel/gate.S +++ b/arch/ia64/kernel/gate.S @@ -3,7 +3,7 @@ * region. For now, it contains the signal trampoline code only. * * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2001 David Mosberger-Tang + * David Mosberger-Tang */ #include @@ -18,7 +18,6 @@ # define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET) # define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET) # define ARG2_OFF (16 + IA64_SIGFRAME_ARG2_OFFSET) -# define RBS_BASE_OFF (16 + IA64_SIGFRAME_RBS_BASE_OFFSET) # define SIGHANDLER_OFF (16 + IA64_SIGFRAME_HANDLER_OFFSET) # define SIGCONTEXT_OFF (16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET) @@ -32,6 +31,8 @@ # define PR_OFF IA64_SIGCONTEXT_PR_OFFSET # define RP_OFF IA64_SIGCONTEXT_B0_OFFSET # define SP_OFF IA64_SIGCONTEXT_R12_OFFSET +# define RBS_BASE_OFF IA64_SIGCONTEXT_RBS_BASE_OFFSET +# define LOADRS_OFF IA64_SIGCONTEXT_LOADRS_OFFSET # define base0 r2 # define base1 r3 /* @@ -73,34 +74,37 @@ GLOBAL_ENTRY(ia64_sigtramp) .vframesp SP_OFF+SIGCONTEXT_OFF .body - .prologue + .label_state 1 + adds base0=SIGHANDLER_OFF,sp - adds base1=RBS_BASE_OFF,sp + adds base1=RBS_BASE_OFF+SIGCONTEXT_OFF,sp br.call.sptk.many rp=1f 1: ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF) // get pointer to signal handler's plabel - ld8 r15=[base1],(ARG1_OFF-RBS_BASE_OFF) // get address of new RBS base (or NULL) + ld8 r15=[base1] // get address of new RBS base (or NULL) cover // push args in interrupted frame onto backing store ;; + cmp.ne p8,p0=r15,r0 // do we need to switch the rbs? + mov.m r9=ar.bsp // fetch ar.bsp + .spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF +(p8) br.cond.spnt setup_rbs // yup -> (clobbers r14, r15, and r16) +back_from_setup_rbs: + .save ar.pfs, r8 alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8 ld8 out0=[base0],16 // load arg0 (signum) + adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1 ;; ld8 out1=[base1] // load arg1 (siginfop) ld8 r10=[r17],8 // get signal handler entry point ;; ld8 out2=[base0] // load arg2 (sigcontextp) ld8 gp=[r17] // get signal handler's global pointer - cmp.ne p8,p0=r15,r0 // do we need to switch the rbs? - mov.m r17=ar.bsp // fetch ar.bsp - .spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF -(p8) br.cond.spnt.few setup_rbs // yup -> (clobbers r14 and r16) -back_from_setup_rbs: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp ;; .spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF - st8 [base0]=r17,(CFM_OFF-BSP_OFF) // save sc_ar_bsp + st8 [base0]=r9,(CFM_OFF-BSP_OFF) // save sc_ar_bsp dep r8=0,r8,38,26 // clear EC0, CPL0 and reserved bits adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp ;; @@ -123,7 +127,7 @@ back_from_setup_rbs: ;; stf.spill [base0]=f14,32 stf.spill [base1]=f15,32 - br.call.sptk.few rp=b6 // call the signal handler + br.call.sptk.many rp=b6 // call the signal handler .ret0: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp ;; ld8 r15=[base0],(CFM_OFF-BSP_OFF) // fetch sc_ar_bsp and advance to CFM_OFF @@ -131,7 +135,7 @@ back_from_setup_rbs: ;; ld8 r8=[base0] // restore (perhaps modified) CFM0, EC0, and CPL0 cmp.ne p8,p0=r14,r15 // do we need to restore the rbs? -(p8) br.cond.spnt.few restore_rbs // yup -> (clobbers r14 and r16) +(p8) br.cond.spnt restore_rbs // yup -> (clobbers r14 and r16) ;; back_from_restore_rbs: adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp @@ -154,30 +158,52 @@ back_from_restore_rbs: mov r15=__NR_rt_sigreturn break __BREAK_SYSCALL + .body + .copy_state 1 setup_rbs: - flushrs // must be first in insn mov ar.rsc=0 // put RSE into enforced lazy mode - adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp ;; - mov r14=ar.rnat // get rnat as updated by flushrs - mov ar.bspstore=r15 // set new register backing store area + .save ar.rnat, r16 + mov r16=ar.rnat // save RNaT before switching backing store area + adds r14=(RNAT_OFF+SIGCONTEXT_OFF),sp + + mov ar.bspstore=r15 // switch over to new register backing store area ;; .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF - st8 [r16]=r14 // save sc_ar_rnat + st8 [r14]=r16 // save sc_ar_rnat + adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp + + mov.m r16=ar.bsp // sc_loadrs <- (new bsp - new bspstore) << 16 + ;; + invala + sub r15=r16,r15 + ;; + shl r15=r15,16 + ;; + st8 [r14]=r15 // save sc_loadrs mov ar.rsc=0xf // set RSE into eager mode, pl 3 - invala // invalidate ALAT - br.cond.sptk.many back_from_setup_rbs + br.cond.sptk back_from_setup_rbs + .prologue + .copy_state 1 + .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF + .body restore_rbs: - flushrs - mov ar.rsc=0 // put RSE into enforced lazy mode + alloc r2=ar.pfs,0,0,0,0 // alloc null frame + adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp + ;; + ld8 r14=[r16] adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp ;; + mov ar.rsc=r14 // put RSE into enforced lazy mode ld8 r14=[r16] // get new rnat - mov ar.bspstore=r15 // set old register backing store area ;; - mov ar.rnat=r14 // establish new rnat + loadrs // restore dirty partition + ;; + mov ar.bspstore=r15 // switch back to old register backing store area + ;; + mov ar.rnat=r14 // restore RNaT mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) // invala not necessary as that will happen when returning to user-mode - br.cond.sptk.many back_from_restore_rbs + br.cond.sptk back_from_restore_rbs END(ia64_sigtramp) diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 590a59f7922f..148078b735bf 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -6,8 +6,8 @@ * entry point. * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang - * Copyright (C) 2001 Stephane Eranian + * David Mosberger-Tang + * Stephane Eranian * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond * Copyright (C) 1999 Intel Corp. @@ -63,17 +63,17 @@ start_ap: * that maps the kernel's text and data: */ rsm psr.i | psr.ic - mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (KERNEL_PG_SHIFT << 2)) + mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (IA64_GRANULE_SHIFT << 2)) ;; srlz.i - mov r18=KERNEL_PG_SHIFT<<2 - movl r17=PAGE_OFFSET + KERNEL_PG_NUM*KERNEL_PG_SIZE + mov r18=KERNEL_TR_PAGE_SHIFT<<2 + movl r17=KERNEL_START ;; mov rr[r17]=r16 mov cr.itir=r18 mov cr.ifa=r17 mov r16=IA64_TR_KERNEL - movl r18=(KERNEL_PG_NUM*KERNEL_PG_SIZE | PAGE_KERNEL) + movl r18=((1 << KERNEL_TR_PAGE_SHIFT) | PAGE_KERNEL) ;; srlz.i ;; @@ -86,7 +86,8 @@ start_ap: /* * Switch into virtual mode: */ - movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN) + movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN \ + |IA64_PSR_DI) ;; mov cr.ipsr=r16 movl r17=1f @@ -111,7 +112,7 @@ start_ap: ;; #ifdef CONFIG_IA64_EARLY_PRINTK - mov r3=(6<<8) | (KERNEL_PG_SHIFT<<2) + mov r3=(6<<8) | (IA64_GRANULE_SHIFT<<2) movl r2=6<<61 ;; mov rr[r2]=r3 @@ -144,6 +145,7 @@ start_ap: cmp4.ne isAP,isBP=r3,r0 ;; // RAW on r2 extr r3=r2,0,61 // r3 == phys addr of task struct + mov r16=KERNEL_TR_PAGE_NUM ;; // load the "current" pointer (r13) and ar.k6 with the current task @@ -151,7 +153,7 @@ start_ap: mov IA64_KR(CURRENT)=r3 // Physical address // initialize k4 to a safe value (64-128MB is mapped by TR_KERNEL) - mov IA64_KR(CURRENT_STACK)=1 + mov IA64_KR(CURRENT_STACK)=r16 /* * Reserve space at the top of the stack for "struct pt_regs". Kernel threads * don't store interesting values in that structure, but the space still needs @@ -183,31 +185,31 @@ alive_msg: alloc r2=ar.pfs,0,0,2,0 movl out0=alive_msg ;; - br.call.sptk.few rp=early_printk + br.call.sptk.many rp=early_printk 1: // force new bundle #endif /* CONFIG_IA64_EARLY_PRINTK */ #ifdef CONFIG_SMP -(isAP) br.call.sptk.few rp=start_secondary +(isAP) br.call.sptk.many rp=start_secondary .ret0: -(isAP) br.cond.sptk.few self +(isAP) br.cond.sptk self #endif // This is executed by the bootstrap processor (bsp) only: #ifdef CONFIG_IA64_FW_EMU // initialize PAL & SAL emulator: - br.call.sptk.few rp=sys_fw_init + br.call.sptk.many rp=sys_fw_init .ret1: #endif - br.call.sptk.few rp=start_kernel + br.call.sptk.many rp=start_kernel .ret2: addl r3=@ltoff(halt_msg),gp ;; alloc r2=ar.pfs,8,0,2,0 ;; ld8 out0=[r3] - br.call.sptk.few b0=console_print -self: br.sptk.few self // endless loop + br.call.sptk.many b0=console_print +self: br.sptk.many self // endless loop END(_start) GLOBAL_ENTRY(ia64_save_debug_regs) @@ -218,7 +220,7 @@ GLOBAL_ENTRY(ia64_save_debug_regs) add r19=IA64_NUM_DBG_REGS*8,in0 ;; 1: mov r16=dbr[r18] -#if defined(CONFIG_ITANIUM_C0_SPECIFIC) +#ifdef CONFIG_ITANIUM ;; srlz.d #endif @@ -227,17 +229,15 @@ GLOBAL_ENTRY(ia64_save_debug_regs) ;; st8.nta [in0]=r16,8 st8.nta [r19]=r17,8 - br.cloop.sptk.few 1b + br.cloop.sptk.many 1b ;; mov ar.lc=r20 // restore ar.lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_save_debug_regs) GLOBAL_ENTRY(ia64_load_debug_regs) alloc r16=ar.pfs,1,0,0,0 -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) lfetch.nta [in0] -#endif mov r20=ar.lc // preserve ar.lc add r19=IA64_NUM_DBG_REGS*8,in0 mov ar.lc=IA64_NUM_DBG_REGS-1 @@ -248,15 +248,15 @@ GLOBAL_ENTRY(ia64_load_debug_regs) add r18=1,r18 ;; mov dbr[r18]=r16 -#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) || defined(CONFIG_ITANIUM_C0_SPECIFIC) +#ifdef CONFIG_ITANIUM ;; - srlz.d + srlz.d // Errata 132 (NoFix status) #endif mov ibr[r18]=r17 - br.cloop.sptk.few 1b + br.cloop.sptk.many 1b ;; mov ar.lc=r20 // restore ar.lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_load_debug_regs) GLOBAL_ENTRY(__ia64_save_fpu) @@ -406,7 +406,7 @@ GLOBAL_ENTRY(__ia64_save_fpu) ;; stf.spill.nta [in0]=f126,32 stf.spill.nta [ r3]=f127,32 - br.ret.sptk.few rp + br.ret.sptk.many rp END(__ia64_save_fpu) GLOBAL_ENTRY(__ia64_load_fpu) @@ -556,7 +556,7 @@ GLOBAL_ENTRY(__ia64_load_fpu) ;; ldf.fill.nta f126=[in0],32 ldf.fill.nta f127=[ r3],32 - br.ret.sptk.few rp + br.ret.sptk.many rp END(__ia64_load_fpu) GLOBAL_ENTRY(__ia64_init_fpu) @@ -690,7 +690,7 @@ GLOBAL_ENTRY(__ia64_init_fpu) ;; ldf.fill f126=[sp] mov f127=f0 - br.ret.sptk.few rp + br.ret.sptk.many rp END(__ia64_init_fpu) /* @@ -738,7 +738,7 @@ GLOBAL_ENTRY(ia64_switch_mode) rfi // must be last insn in group ;; 1: mov rp=r14 - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_switch_mode) #ifdef CONFIG_IA64_BRL_EMU @@ -752,7 +752,7 @@ END(ia64_switch_mode) alloc r16=ar.pfs,1,0,0,0; \ mov reg=r32; \ ;; \ - br.ret.sptk rp; \ + br.ret.sptk.many rp; \ END(ia64_set_##reg) SET_REG(b1); @@ -816,12 +816,11 @@ GLOBAL_ENTRY(ia64_spinlock_contention) ;; cmp.ne p15,p0=tmp,r0 mov tmp=ar.itc -(p15) br.cond.sptk.few .retry // lock is still busy +(p15) br.cond.sptk .retry // lock is still busy ;; // try acquiring lock (we know ar.ccv is still zero!): mov tmp=1 ;; - IA64_SEMFIX_INSN cmpxchg4.acq tmp=[r31],tmp,ar.ccv ;; cmp.eq p15,p0=tmp,r0 diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 0c94d0b1c1cc..329125a1113f 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -69,6 +69,8 @@ EXPORT_SYMBOL(last_cli_ip); #include +EXPORT_SYMBOL(flush_tlb_range); + #ifdef CONFIG_SMP EXPORT_SYMBOL(smp_flush_tlb_all); @@ -145,4 +147,3 @@ EXPORT_SYMBOL(efi); #include extern struct proc_dir_entry *efi_dir; EXPORT_SYMBOL(efi_dir); - diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 13d7067d4a85..266526fac8bb 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -325,7 +326,7 @@ struct hw_interrupt_type irq_type_iosapic_edge = { set_affinity: iosapic_set_affinity }; -static unsigned int +unsigned int iosapic_version (char *addr) { /* @@ -341,6 +342,113 @@ iosapic_version (char *addr) return readl(IOSAPIC_WINDOW + addr); } +/* + * ACPI can describe IOSAPIC interrupts via static tables and namespace + * methods. This provides an interface to register those interrupts and + * program the IOSAPIC RTE. + */ +int +iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long + edge_triggered, u32 base_irq, char *iosapic_address) +{ + irq_desc_t *idesc; + struct hw_interrupt_type *irq_type; + int vector; + + vector = iosapic_irq_to_vector(global_vector); + if (vector < 0) + vector = ia64_alloc_irq(); + + /* fill in information from this vector's IOSAPIC */ + iosapic_irq[vector].addr = iosapic_address; + iosapic_irq[vector].base_irq = base_irq; + iosapic_irq[vector].pin = global_vector - iosapic_irq[vector].base_irq; + iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; + iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + + if (edge_triggered) { + iosapic_irq[vector].trigger = IOSAPIC_EDGE; + irq_type = &irq_type_iosapic_edge; + } else { + iosapic_irq[vector].trigger = IOSAPIC_LEVEL; + irq_type = &irq_type_iosapic_level; + } + + idesc = irq_desc(vector); + if (idesc->handler != irq_type) { + if (idesc->handler != &no_irq_type) + printk("iosapic_register_irq(): changing vector 0x%02x from" + "%s to %s\n", vector, idesc->handler->typename, irq_type->typename); + idesc->handler = irq_type; + } + + printk("IOSAPIC %x(%s,%s) -> Vector %x\n", global_vector, + (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector); + + /* program the IOSAPIC routing table */ + set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + return vector; +} + +/* + * ACPI calls this when it finds an entry for a platform interrupt. + * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). + */ +int +iosapic_register_platform_irq (u32 int_type, u32 global_vector, u32 iosapic_vector, + u16 eid, u16 id, unsigned long polarity, + unsigned long edge_triggered, u32 base_irq, char *iosapic_address) +{ + struct hw_interrupt_type *irq_type; + irq_desc_t *idesc; + int vector; + + switch (int_type) { + case ACPI20_ENTRY_PIS_CPEI: + vector = IA64_PCE_VECTOR; + iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + break; + case ACPI20_ENTRY_PIS_INIT: + vector = ia64_alloc_irq(); + iosapic_irq[vector].dmode = IOSAPIC_INIT; + break; + default: + printk("iosapic_register_platform_irq(): invalid int type\n"); + return -1; + } + + /* fill in information from this vector's IOSAPIC */ + iosapic_irq[vector].addr = iosapic_address; + iosapic_irq[vector].base_irq = base_irq; + iosapic_irq[vector].pin = global_vector - iosapic_irq[vector].base_irq; + iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; + + if (edge_triggered) { + iosapic_irq[vector].trigger = IOSAPIC_EDGE; + irq_type = &irq_type_iosapic_edge; + } else { + iosapic_irq[vector].trigger = IOSAPIC_LEVEL; + irq_type = &irq_type_iosapic_level; + } + + idesc = irq_desc(vector); + if (idesc->handler != irq_type) { + if (idesc->handler != &no_irq_type) + printk("iosapic_register_platform_irq(): changing vector 0x%02x from" + "%s to %s\n", vector, idesc->handler->typename, irq_type->typename); + idesc->handler = irq_type; + } + + printk("PLATFORM int %x: IOSAPIC %x(%s,%s) -> Vector %x CPU %.02u:%.02u\n", + int_type, global_vector, (polarity ? "high" : "low"), + (edge_triggered ? "edge" : "level"), vector, eid, id); + + /* program the IOSAPIC routing table */ + set_rte(vector, ((id << 8) | eid) & 0xffff); + return vector; +} + + /* * ACPI calls this when it finds an entry for a legacy ISA interrupt. Note that the * irq_base and IOSAPIC address must be set in iosapic_init(). @@ -436,7 +544,7 @@ iosapic_init (unsigned long phys_addr, unsigned int base_irq, int pcat_compat) /* the interrupt route is for another controller... */ continue; - if (irq < 16) + if (pcat_compat && (irq < 16)) vector = isa_irq_to_vector(irq); else { vector = iosapic_irq_to_vector(irq); @@ -515,6 +623,23 @@ iosapic_pci_fixup (int phase) printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n", dev->bus->number, PCI_SLOT(dev->devfn), pin, vector); dev->irq = vector; + +#ifdef CONFIG_SMP + /* + * For platforms that do not support interrupt redirect + * via the XTP interface, we can round-robin the PCI + * device interrupts to the processors + */ + if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) { + static int cpu_index = 0; + + set_rte(vector, cpu_physical_id(cpu_index) & 0xffff); + + cpu_index++; + if (cpu_index >= smp_num_cpus) + cpu_index = 0; + } +#endif } } /* diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index c0a9f341be91..32f1decef189 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -121,7 +122,10 @@ struct hw_interrupt_type no_irq_type = { end_none }; -volatile unsigned long irq_err_count; +atomic_t irq_err_count; +#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG) +atomic_t irq_mis_count; +#endif /* * Generic, controller-independent functions: @@ -164,14 +168,17 @@ int get_irq_list(char *buf) p += sprintf(p, "%10u ", nmi_count(cpu_logical_map(j))); p += sprintf(p, "\n"); -#if defined(CONFIG_SMP) && defined(__i386__) +#if defined(CONFIG_SMP) && defined(CONFIG_X86) p += sprintf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]); p += sprintf(p, "\n"); #endif - p += sprintf(p, "ERR: %10lu\n", irq_err_count); + p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); +#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG) + p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); +#endif return p - buf; } @@ -183,7 +190,7 @@ int get_irq_list(char *buf) #ifdef CONFIG_SMP unsigned int global_irq_holder = NO_PROC_ID; -volatile unsigned long global_irq_lock; /* long for set_bit --RR */ +unsigned volatile long global_irq_lock; /* pedantic: long for set_bit --RR */ extern void show_stack(unsigned long* esp); @@ -201,14 +208,14 @@ static void show(char * str) printk(" %d",bh_count(i)); printk(" ]\nStack dumps:"); -#if defined(__ia64__) +#if defined(CONFIG_IA64) /* * We can't unwind the stack of another CPU without access to * the registers of that CPU. And sending an IPI when we're * in a potentially wedged state doesn't sound like a smart * idea. */ -#elif defined(__i386__) +#elif defined(CONFIG_X86) for(i=0;i< smp_num_cpus;i++) { unsigned long esp; if(i==cpu) @@ -261,7 +268,7 @@ static void show(char * str) /* * We have to allow irqs to arrive between __sti and __cli */ -# ifdef __ia64__ +# ifdef CONFIG_IA64 # define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop 0") # else # define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") @@ -331,6 +338,9 @@ static inline void get_irqlock(void) /* Uhhuh.. Somebody else got it. Wait.. */ do { do { +#ifdef CONFIG_X86 + rep_nop(); +#endif } while (test_bit(0,&global_irq_lock)); } while (test_and_set_bit(0,&global_irq_lock)); } @@ -364,7 +374,7 @@ void __global_cli(void) { unsigned int flags; -#ifdef __ia64__ +#ifdef CONFIG_IA64 __save_flags(flags); if (flags & IA64_PSR_I) { __cli(); @@ -403,7 +413,7 @@ unsigned long __global_save_flags(void) int cpu = smp_processor_id(); __save_flags(flags); -#ifdef __ia64__ +#ifdef CONFIG_IA64 local_enabled = (flags & IA64_PSR_I) != 0; #else local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; @@ -476,13 +486,19 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * return status; } -/* - * Generic enable/disable code: this just calls - * down into the PIC-specific version for the actual - * hardware disable after having gotten the irq - * controller lock. +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. */ -void inline disable_irq_nosync(unsigned int irq) + +inline void disable_irq_nosync(unsigned int irq) { irq_desc_t *desc = irq_desc(irq); unsigned long flags; @@ -495,10 +511,19 @@ void inline disable_irq_nosync(unsigned int irq) spin_unlock_irqrestore(&desc->lock, flags); } -/* - * Synchronous version of the above, making sure the IRQ is - * no longer running on any other IRQ.. +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. */ + void disable_irq(unsigned int irq) { disable_irq_nosync(irq); @@ -512,6 +537,17 @@ void disable_irq(unsigned int irq) #endif } +/** + * enable_irq - enable handling of an irq + * @irq: Interrupt to enable + * + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. + * + * This function may be called from IRQ context. + */ + void enable_irq(unsigned int irq) { irq_desc_t *desc = irq_desc(irq); @@ -533,7 +569,8 @@ void enable_irq(unsigned int irq) desc->depth--; break; case 0: - printk("enable_irq() unbalanced from %p\n", (void *) __builtin_return_address(0)); + printk("enable_irq(%u) unbalanced from %p\n", + irq, (void *) __builtin_return_address(0)); } spin_unlock_irqrestore(&desc->lock, flags); } @@ -626,11 +663,41 @@ unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs) desc->handler->end(irq); spin_unlock(&desc->lock); } - if (local_softirq_pending()) - do_softirq(); return 1; } +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, @@ -676,6 +743,24 @@ int request_irq(unsigned int irq, return retval; } +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function may be called from interrupt context. + * + * Bugs: Attempting to free an irq in a handler for the same irq hangs + * the machine. + */ + void free_irq(unsigned int irq, void *dev_id) { irq_desc_t *desc; @@ -726,6 +811,17 @@ void free_irq(unsigned int irq, void *dev_id) * with "IRQ_WAITING" cleared and the interrupt * disabled. */ + +static DECLARE_MUTEX(probe_sem); + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ + unsigned long probe_irq_on(void) { unsigned int i; @@ -733,6 +829,7 @@ unsigned long probe_irq_on(void) unsigned long val; unsigned long delay; + down(&probe_sem); /* * something may have generated an irq long ago and we want to * flush such a longstanding irq before considering it as spurious. @@ -799,10 +896,19 @@ unsigned long probe_irq_on(void) return val; } -/* - * Return a mask of triggered interrupts (this - * can handle only legacy ISA interrupts). +/** + * probe_irq_mask - scan a bitmap of interrupt lines + * @val: mask of interrupts to consider + * + * Scan the ISA bus interrupt lines and return a bitmap of + * active interrupts. The interrupt probe logic state is then + * returned to its previous value. + * + * Note: we need to scan all the irq's even though we will + * only return ISA irq numbers - just so that we reset them + * all to a known state. */ + unsigned int probe_irq_mask(unsigned long val) { int i; @@ -825,14 +931,29 @@ unsigned int probe_irq_mask(unsigned long val) } spin_unlock_irq(&desc->lock); } + up(&probe_sem); return mask & val; } -/* - * Return the one interrupt that triggered (this can - * handle any interrupt source) +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldnt happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. */ + int probe_irq_off(unsigned long val) { int i, irq_found, nr_irqs; @@ -857,6 +978,7 @@ int probe_irq_off(unsigned long val) } spin_unlock_irq(&desc->lock); } + up(&probe_sem); if (nr_irqs > 1) irq_found = -irq_found; @@ -911,7 +1033,7 @@ int setup_irq(unsigned int irq, struct irqaction * new) if (!shared) { desc->depth = 0; - desc->status &= ~IRQ_DISABLED; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); desc->handler->startup(irq); } spin_unlock_irqrestore(&desc->lock,flags); @@ -922,20 +1044,9 @@ int setup_irq(unsigned int irq, struct irqaction * new) static struct proc_dir_entry * root_irq_dir; static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; - -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; #define HEX_DIGITS 8 -static int irq_affinity_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - if (count < HEX_DIGITS+1) - return -EINVAL; - return sprintf (page, "%08lx\n", irq_affinity[(long)data]); -} - static unsigned int parse_hex_value (const char *buffer, unsigned long count, unsigned long *ret) { @@ -973,6 +1084,20 @@ out: return 0; } +#if CONFIG_SMP + +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", irq_affinity[(long)data]); +} + static int irq_affinity_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { @@ -984,7 +1109,6 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, err = parse_hex_value(buffer, count, &new_value); -#if CONFIG_SMP /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least @@ -992,7 +1116,6 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, */ if (!(new_value & cpu_online_map)) return -EINVAL; -#endif irq_affinity[irq] = new_value; irq_desc(irq)->handler->set_affinity(irq, new_value); @@ -1000,6 +1123,8 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, return full_count; } +#endif /* CONFIG_SMP */ + static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -1027,7 +1152,6 @@ static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, static void register_irq_proc (unsigned int irq) { - struct proc_dir_entry *entry; char name [MAX_NAMELEN]; if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type)) @@ -1039,15 +1163,22 @@ static void register_irq_proc (unsigned int irq) /* create /proc/irq/1234 */ irq_dir[irq] = proc_mkdir(name, root_irq_dir); - /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); - - entry->nlink = 1; - entry->data = (void *)(long)irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; +#if CONFIG_SMP + { + struct proc_dir_entry *entry; + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } - smp_affinity_entry[irq] = entry; + smp_affinity_entry[irq] = entry; + } +#endif } unsigned long prof_cpu_mask = -1; @@ -1063,6 +1194,9 @@ void init_irq_proc (void) /* create /proc/irq/prof_cpu_mask */ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + if (!entry) + return; + entry->nlink = 1; entry->data = (void *)&prof_cpu_mask; entry->read_proc = prof_cpu_mask_read_proc; diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 89e48dca23ac..fe2ef585b493 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -1,9 +1,9 @@ /* * linux/arch/ia64/kernel/irq.c * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998, 1999 Stephane Eranian - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Stephane Eranian + * David Mosberger-Tang * * 6/10/99: Updated to bring in sync with x86 version to facilitate * support for SMP and different interrupt controllers. @@ -131,6 +131,13 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) ia64_eoi(); vector = ia64_get_ivr(); } + /* + * This must be done *after* the ia64_eoi(). For example, the keyboard softirq + * handler needs to be able to wait for further keyboard interrupts, which can't + * come through until ia64_eoi() has been done. + */ + if (local_softirq_pending()) + do_softirq(); } #ifdef CONFIG_SMP diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index 393079fd68a3..957cd803ad5d 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -2,8 +2,8 @@ * arch/ia64/kernel/ivt.S * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998, 1999 Stephane Eranian - * Copyright (C) 1998-2001 David Mosberger + * Stephane Eranian + * David Mosberger * * 00/08/23 Asit Mallick TLB handling for SMP * 00/12/20 David Mosberger-Tang DTLB/ITLB handler now uses virtual PT. @@ -157,7 +157,7 @@ ENTRY(vhpt_miss) ;; (p10) itc.i r18 // insert the instruction TLB entry (p11) itc.d r18 // insert the data TLB entry -(p6) br.spnt.many page_fault // handle bad address/page not present (page fault) +(p6) br.cond.spnt.many page_fault // handle bad address/page not present (page fault) mov cr.ifa=r22 /* @@ -213,7 +213,7 @@ itlb_fault: ;; mov b0=r29 tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.cond.spnt.many page_fault +(p6) br.cond.spnt page_fault ;; itc.i r18 ;; @@ -251,7 +251,7 @@ dtlb_fault: ;; mov b0=r29 tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.cond.spnt.many page_fault +(p6) br.cond.spnt page_fault ;; itc.d r18 ;; @@ -286,7 +286,7 @@ ENTRY(alt_itlb_miss) ;; (p8) mov cr.iha=r17 (p8) mov r29=b0 // save b0 -(p8) br.cond.dptk.many itlb_fault +(p8) br.cond.dptk itlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl shr.u r18=r16,57 // move address bit 61 to bit 4 @@ -297,7 +297,7 @@ ENTRY(alt_itlb_miss) dep r19=r17,r19,0,12 // insert PTE control bits into r19 ;; or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 -(p8) br.cond.spnt.many page_fault +(p8) br.cond.spnt page_fault ;; itc.i r19 // insert the TLB entry mov pr=r31,-1 @@ -324,7 +324,7 @@ ENTRY(alt_dtlb_miss) ;; (p8) mov cr.iha=r17 (p8) mov r29=b0 // save b0 -(p8) br.cond.dptk.many dtlb_fault +(p8) br.cond.dptk dtlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? @@ -333,7 +333,7 @@ ENTRY(alt_dtlb_miss) ;; andcm r18=0x10,r18 // bit 4=~address-bit(61) cmp.ne p8,p0=r0,r23 -(p8) br.cond.spnt.many page_fault +(p8) br.cond.spnt page_fault dep r21=-1,r21,IA64_PSR_ED_BIT,1 dep r19=r17,r19,0,12 // insert PTE control bits into r19 @@ -429,7 +429,7 @@ ENTRY(nested_dtlb_miss) ;; (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry -(p6) br.cond.spnt.many page_fault +(p6) br.cond.spnt page_fault mov b0=r30 br.sptk.many b0 // return to continuation point END(nested_dtlb_miss) @@ -534,15 +534,6 @@ ENTRY(iaccess_bit) ;; 1: ld8 r18=[r17] ;; -# if defined(CONFIG_IA32_SUPPORT) && defined(CONFIG_ITANIUM_B0_SPECIFIC) - /* - * Erratum 85 (Access bit fault could be reported before page not present fault) - * If the PTE is indicates the page is not present, then just turn this into a - * page fault. - */ - tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.sptk page_fault // page wasn't present -# endif mov ar.ccv=r18 // set compare value for cmpxchg or r25=_PAGE_A,r18 // set the accessed bit ;; @@ -564,15 +555,6 @@ ENTRY(iaccess_bit) ;; 1: ld8 r18=[r17] ;; -# if defined(CONFIG_IA32_SUPPORT) && defined(CONFIG_ITANIUM_B0_SPECIFIC) - /* - * Erratum 85 (Access bit fault could be reported before page not present fault) - * If the PTE is indicates the page is not present, then just turn this into a - * page fault. - */ - tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.sptk page_fault // page wasn't present -# endif or r18=_PAGE_A,r18 // set the accessed bit mov b0=r29 // restore b0 ;; @@ -640,7 +622,7 @@ ENTRY(break_fault) mov r31=pr // prepare to save predicates ;; cmp.eq p0,p7=r16,r17 // is this a system call? (p7 <- false, if so) -(p7) br.cond.spnt.many non_syscall +(p7) br.cond.spnt non_syscall SAVE_MIN // uses r31; defines r2: @@ -656,7 +638,7 @@ ENTRY(break_fault) adds r3=8,r2 // set up second base pointer for SAVE_REST ;; SAVE_REST - br.call.sptk rp=demine_args // clear NaT bits in (potential) syscall args + br.call.sptk.many rp=demine_args // clear NaT bits in (potential) syscall args mov r3=255 adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 @@ -698,7 +680,7 @@ ENTRY(break_fault) st8 [r16]=r18 // store new value for cr.isr (p8) br.call.sptk.many b6=b6 // ignore this return addr - br.cond.sptk.many ia64_trace_syscall + br.cond.sptk ia64_trace_syscall // NOT REACHED END(break_fault) @@ -811,8 +793,8 @@ ENTRY(dispatch_illegal_op_fault) mov b6=r8 ;; cmp.ne p6,p0=0,r8 -(p6) br.call.dpnt b6=b6 // call returns to ia64_leave_kernel - br.sptk ia64_leave_kernel +(p6) br.call.dpnt.many b6=b6 // call returns to ia64_leave_kernel + br.sptk.many ia64_leave_kernel END(dispatch_illegal_op_fault) .align 1024 @@ -855,30 +837,30 @@ ENTRY(dispatch_to_ia32_handler) adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp ;; cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 - st8 [r15]=r8 // save orignal EAX in r1 (IA32 procs don't use the GP) + st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) ;; alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ;; - ld4 r8=[r14],8 // r8 == EAX (syscall number) - mov r15=222 // sys_vfork - last implemented system call + ld4 r8=[r14],8 // r8 == eax (syscall number) + mov r15=230 // number of entries in ia32 system call table ;; - cmp.leu.unc p6,p7=r8,r15 - ld4 out1=[r14],8 // r9 == ecx + cmp.ltu.unc p6,p7=r8,r15 + ld4 out1=[r14],8 // r9 == ecx ;; - ld4 out2=[r14],8 // r10 == edx + ld4 out2=[r14],8 // r10 == edx ;; - ld4 out0=[r14] // r11 == ebx + ld4 out0=[r14] // r11 == ebx adds r14=(IA64_PT_REGS_R8_OFFSET-(8*3)) + 16,sp ;; - ld4 out5=[r14],8 // r13 == ebp + ld4 out5=[r14],8 // r13 == ebp ;; - ld4 out3=[r14],8 // r14 == esi + ld4 out3=[r14],8 // r14 == esi adds r2=IA64_TASK_PTRACE_OFFSET,r13 // r2 = ¤t->ptrace ;; - ld4 out4=[r14] // R15 == edi + ld4 out4=[r14] // r15 == edi movl r16=ia32_syscall_table ;; -(p6) shladd r16=r8,3,r16 // Force ni_syscall if not valid syscall number +(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number ld8 r2=[r2] // r2 = current->ptrace ;; ld8 r16=[r16] @@ -889,12 +871,12 @@ ENTRY(dispatch_to_ia32_handler) ;; mov rp=r15 (p8) br.call.sptk.many b6=b6 - br.cond.sptk.many ia32_trace_syscall + br.cond.sptk ia32_trace_syscall non_ia32_syscall: alloc r15=ar.pfs,0,0,2,0 - mov out0=r14 // interrupt # - add out1=16,sp // pointer to pt_regs + mov out0=r14 // interrupt # + add out1=16,sp // pointer to pt_regs ;; // avoid WAW on CFM br.call.sptk.many rp=ia32_bad_interrupt .ret1: movl r15=ia64_leave_kernel @@ -1085,7 +1067,7 @@ ENTRY(general_exception) mov r31=pr ;; cmp4.eq p6,p0=0,r16 -(p6) br.sptk dispatch_illegal_op_fault +(p6) br.sptk.many dispatch_illegal_op_fault ;; mov r19=24 // fault number br.sptk.many dispatch_to_fault_handler diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 19e445ff44dc..f090da7b9ff0 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -3,12 +3,20 @@ * Purpose: Generic MCA handling layer * * Updated for latest kernel + * Copyright (C) 2001 Intel + * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com) + * * Copyright (C) 2000 Intel * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * + * 01/01/03 F. Lewis Added setup of CMCI and CPEI IRQs, logging of corrected + * platform errors, completed code for logging of + * corrected & uncorrected machine check errors, and + * updated for conformance with Nov. 2000 revision of the + * SAL 3.0 spec. * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, * added min save state dump, added INIT handler. */ @@ -16,6 +24,7 @@ #include #include #include +#include #include #include @@ -27,8 +36,10 @@ #include #include -#include +#include +#include +#undef MCA_PRT_XTRA_DATA typedef struct ia64_fptr { unsigned long fp; @@ -38,22 +49,67 @@ typedef struct ia64_fptr { ia64_mc_info_t ia64_mc_info; ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; -u64 ia64_mca_proc_state_dump[256]; +u64 ia64_mca_proc_state_dump[512]; u64 ia64_mca_stack[1024]; u64 ia64_mca_stackframe[32]; u64 ia64_mca_bspstore[1024]; u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16))); -static void ia64_mca_cmc_vector_setup(int enable, - int_vector_t cmc_vector); static void ia64_mca_wakeup_ipi_wait(void); static void ia64_mca_wakeup(int cpu); static void ia64_mca_wakeup_all(void); -static void ia64_log_init(int,int); -static void ia64_log_get(int,int, prfunc_t); -static void ia64_log_clear(int,int,int, prfunc_t); +static void ia64_log_init(int); extern void ia64_monarch_init_handler (void); extern void ia64_slave_init_handler (void); +extern struct hw_interrupt_type irq_type_iosapic_level; + +static struct irqaction cmci_irqaction = { + handler: ia64_mca_cmc_int_handler, + flags: SA_INTERRUPT, + name: "cmc_hndlr" +}; + +static struct irqaction mca_rdzv_irqaction = { + handler: ia64_mca_rendez_int_handler, + flags: SA_INTERRUPT, + name: "mca_rdzv" +}; + +static struct irqaction mca_wkup_irqaction = { + handler: ia64_mca_wakeup_int_handler, + flags: SA_INTERRUPT, + name: "mca_wkup" +}; + +static struct irqaction mca_cpe_irqaction = { + handler: ia64_mca_cpe_int_handler, + flags: SA_INTERRUPT, + name: "cpe_hndlr" +}; + +/* + * ia64_mca_log_sal_error_record + * + * This function retrieves a specified error record type from SAL, sends it to + * the system log, and notifies SALs to clear the record from its non-volatile + * memory. + * + * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) + * Outputs : None + */ +void +ia64_mca_log_sal_error_record(int sal_info_type) +{ + /* Get the MCA error record */ + if (!ia64_log_get(sal_info_type, (prfunc_t)printk)) + return; // no record retrieved + + /* Log the error record */ + ia64_log_print(sal_info_type, (prfunc_t)printk); + + /* Clear the CMC SAL logs now that they have been logged */ + ia64_sal_clear_state_info(sal_info_type); +} /* * hack for now, add platform dependent handlers @@ -67,10 +123,14 @@ mca_handler_platform (void) } void -cmci_handler_platform (int cmc_irq, void *arg, struct pt_regs *ptregs) +ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) { + IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq); + /* Get the CMC error record and log it */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); } + /* * This routine will be used to deal with platform specific handling * of the init, i.e. drop into the kernel debugger on server machine, @@ -81,17 +141,72 @@ void init_handler_platform (struct pt_regs *regs) { /* if a kernel debugger is available call it here else just dump the registers */ + show_regs(regs); /* dump the state info */ + while (1); /* hang city if no debugger */ } +/* + * ia64_mca_init_platform + * + * External entry for platform specific MCA initialization. + * + * Inputs + * None + * + * Outputs + * None + */ void -log_print_platform ( void *cur_buff_ptr, prfunc_t prfunc) +ia64_mca_init_platform (void) { + } +/* + * ia64_mca_check_errors + * + * External entry to check for error records which may have been posted by SAL + * for a prior failure which resulted in a machine shutdown before an the + * error could be logged. This function must be called after the filesystem + * is initialized. + * + * Inputs : None + * + * Outputs : None + */ void -ia64_mca_init_platform (void) +ia64_mca_check_errors (void) { + /* + * If there is an MCA error record pending, get it and log it. + */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); +} + +/* + * ia64_mca_register_cpev + * + * Register the corrected platform error vector with SAL. + * + * Inputs + * cpev Corrected Platform Error Vector number + * + * Outputs + * None + */ +static void +ia64_mca_register_cpev (int cpev) +{ + /* Register the CPE interrupt vector with SAL */ + if (ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0)) { + printk("ia64_mca_platform_init: failed to register Corrected " + "Platform Error interrupt vector with SAL.\n"); + return; + } + + IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error " + "vector %#x setup and enabled\n", cpev); } #endif /* PLATFORM_MCA_HANDLERS */ @@ -140,30 +255,36 @@ ia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs) && !ia64_pmss_dump_bank0)) printk("\n"); } - /* hang city for now, until we include debugger or copy to ptregs to show: */ - while (1); } /* * ia64_mca_cmc_vector_setup - * Setup the correctable machine check vector register in the processor + * + * Setup the corrected machine check vector register in the processor and + * unmask interrupt. This function is invoked on a per-processor basis. + * * Inputs - * Enable (1 - enable cmc interrupt , 0 - disable) - * CMC handler entry point (if enabled) + * None * * Outputs * None */ -static void -ia64_mca_cmc_vector_setup(int enable, - int_vector_t cmc_vector) +void +ia64_mca_cmc_vector_setup (void) { cmcv_reg_t cmcv; cmcv.cmcv_regval = 0; - cmcv.cmcv_mask = enable; - cmcv.cmcv_vector = cmc_vector; + cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ + cmcv.cmcv_vector = IA64_CMC_VECTOR; ia64_set_cmcv(cmcv.cmcv_regval); + + IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected " + "machine check vector %#x setup and enabled.\n", + smp_processor_id(), IA64_CMC_VECTOR); + + IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n", + smp_processor_id(), ia64_get_cmcv()); } @@ -174,26 +295,58 @@ sal_log_processor_info_t slpi_buf; void mca_test(void) { - slpi_buf.slpi_valid.slpi_psi = 1; - slpi_buf.slpi_valid.slpi_cache_check = 1; - slpi_buf.slpi_valid.slpi_tlb_check = 1; - slpi_buf.slpi_valid.slpi_bus_check = 1; - slpi_buf.slpi_valid.slpi_minstate = 1; - slpi_buf.slpi_valid.slpi_bank1_gr = 1; - slpi_buf.slpi_valid.slpi_br = 1; - slpi_buf.slpi_valid.slpi_cr = 1; - slpi_buf.slpi_valid.slpi_ar = 1; - slpi_buf.slpi_valid.slpi_rr = 1; - slpi_buf.slpi_valid.slpi_fr = 1; + slpi_buf.valid.psi_static_struct = 1; + slpi_buf.valid.num_cache_check = 1; + slpi_buf.valid.num_tlb_check = 1; + slpi_buf.valid.num_bus_check = 1; + slpi_buf.valid.processor_static_info.minstate = 1; + slpi_buf.valid.processor_static_info.br = 1; + slpi_buf.valid.processor_static_info.cr = 1; + slpi_buf.valid.processor_static_info.ar = 1; + slpi_buf.valid.processor_static_info.rr = 1; + slpi_buf.valid.processor_static_info.fr = 1; ia64_os_mca_dispatch(); } #endif /* #if defined(MCA_TEST) */ + +/* + * verify_guid + * + * Compares a test guid to a target guid and returns result. + * + * Inputs + * test_guid * (ptr to guid to be verified) + * target_guid * (ptr to standard guid to be verified against) + * + * Outputs + * 0 (test verifies against target) + * non-zero (test guid does not verify) + */ +static int +verify_guid (efi_guid_t *test, efi_guid_t *target) +{ + int rc; + + if ((rc = memcmp((void *)test, (void *)target, sizeof(efi_guid_t)))) { + IA64_MCA_DEBUG("ia64_mca_print: invalid guid = " + "{ %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " + "%#02x, %#02x, %#02x, %#02x, } } \n ", + test->data1, test->data2, test->data3, test->data4[0], + test->data4[1], test->data4[2], test->data4[3], + test->data4[4], test->data4[5], test->data4[6], + test->data4[7]); + } + + return rc; +} + /* * ia64_mca_init - * Do all the mca specific initialization on a per-processor basis. + * + * Do all the system level mca specific initialization. * * 1. Register spinloop and wakeup request interrupt vectors * @@ -201,77 +354,80 @@ mca_test(void) * * 3. Register OS_INIT handler entry point * - * 4. Initialize CMCV register to enable/disable CMC interrupt on the - * processor and hook a handler in the platform-specific ia64_mca_init. + * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS. * - * 5. Initialize MCA/CMC/INIT related log buffers maintained by the OS. + * Note that this initialization is done very early before some kernel + * services are available. * - * Inputs - * None - * Outputs - * None + * Inputs : None + * + * Outputs : None */ void __init ia64_mca_init(void) { ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; + ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; int i; + s64 rc; - IA64_MCA_DEBUG("ia64_mca_init : begin\n"); + IA64_MCA_DEBUG("ia64_mca_init: begin\n"); /* Clear the Rendez checkin flag for all cpus */ - for(i = 0 ; i < IA64_MAXCPUS; i++) + for(i = 0 ; i < NR_CPUS; i++) ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - /* NOTE : The actual irqs for the rendez, wakeup and - * cmc interrupts are requested in the platform-specific - * mca initialization code. - */ /* * Register the rendezvous spinloop and wakeup mechanism with SAL */ /* Register the rendezvous interrupt vector with SAL */ - if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, - SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_RENDEZ_VECTOR, - IA64_MCA_RENDEZ_TIMEOUT, - 0)) + if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_RENDEZ_VECTOR, + IA64_MCA_RENDEZ_TIMEOUT, + 0))) + { + printk("ia64_mca_init: Failed to register rendezvous interrupt " + "with SAL. rc = %ld\n", rc); return; + } /* Register the wakeup interrupt vector with SAL */ - if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, - SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_WAKEUP_VECTOR, - 0, - 0)) + if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_WAKEUP_VECTOR, + 0, 0))) + { + printk("ia64_mca_init: Failed to register wakeup interrupt with SAL. rc = %ld\n", + rc); return; + } - IA64_MCA_DEBUG("ia64_mca_init : registered mca rendezvous spinloop and wakeup mech.\n"); - /* - * Setup the correctable machine check vector - */ - ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, IA64_CMC_VECTOR); - - IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n"); + IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n"); - ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); + ia64_mc_info.imi_mca_handler = __pa(mca_hldlr_ptr->fp); /* * XXX - disable SAL checksum by setting size to 0; should be * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); */ ia64_mc_info.imi_mca_handler_size = 0; - /* Register the os mca handler with SAL */ - if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, - ia64_mc_info.imi_mca_handler, - __pa(ia64_get_gp()), - ia64_mc_info.imi_mca_handler_size, - 0,0,0)) + /* Register the os mca handler with SAL */ + if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, + ia64_mc_info.imi_mca_handler, + mca_hldlr_ptr->gp, + ia64_mc_info.imi_mca_handler_size, + 0, 0, 0))) + { + printk("ia64_mca_init: Failed to register os mca handler with SAL. rc = %ld\n", + rc); return; + } - IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n"); + IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n", + ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp); /* * XXX - disable SAL checksum by setting size to 0, should be @@ -282,53 +438,87 @@ ia64_mca_init(void) ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = 0; - IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler); + IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n", + ia64_mc_info.imi_monarch_init_handler); /* Register the os init handler with SAL */ - if (ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, - ia64_mc_info.imi_monarch_init_handler, - __pa(ia64_get_gp()), - ia64_mc_info.imi_monarch_init_handler_size, - ia64_mc_info.imi_slave_init_handler, - __pa(ia64_get_gp()), - ia64_mc_info.imi_slave_init_handler_size)) - - + if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, + ia64_mc_info.imi_monarch_init_handler, + __pa(ia64_get_gp()), + ia64_mc_info.imi_monarch_init_handler_size, + ia64_mc_info.imi_slave_init_handler, + __pa(ia64_get_gp()), + ia64_mc_info.imi_slave_init_handler_size))) + { + printk("ia64_mca_init: Failed to register m/s init handlers with SAL. rc = %ld\n", + rc); return; + } - IA64_MCA_DEBUG("ia64_mca_init : registered os init handler with SAL\n"); + IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n"); + + /* + * Configure the CMCI vector and handler. Interrupts for CMC are + * per-processor, so AP CMC interrupts are setup in smp_callin() (smp.c). + */ + register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); + ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */ + + /* Setup the MCA rendezvous interrupt vector */ + register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction); + + /* Setup the MCA wakeup interrupt vector */ + register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); + + /* Setup the CPE interrupt vector */ + { + irq_desc_t *desc; + unsigned int irq; + int cpev = acpi_request_vector(ACPI20_ENTRY_PIS_CPEI); + + if (cpev >= 0) { + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == cpev) { + desc = irq_desc(irq); + desc->status |= IRQ_PER_CPU; + desc->handler = &irq_type_iosapic_level; + setup_irq(irq, &mca_cpe_irqaction); + } + ia64_mca_register_cpev(cpev); + } else + printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n"); + } /* Initialize the areas set aside by the OS to buffer the * platform/processor error states for MCA/INIT/CMC * handling. */ - ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM); - ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM); - ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); - - ia64_mca_init_platform(); - - IA64_MCA_DEBUG("ia64_mca_init : platform-specific mca handling setup done\n"); + ia64_log_init(SAL_INFO_TYPE_MCA); + ia64_log_init(SAL_INFO_TYPE_INIT); + ia64_log_init(SAL_INFO_TYPE_CMC); + ia64_log_init(SAL_INFO_TYPE_CPE); #if defined(MCA_TEST) mca_test(); #endif /* #if defined(MCA_TEST) */ printk("Mca related initialization done\n"); + +#if 0 // Too early in initialization -- error log is lost + /* Do post-failure MCA error logging */ + ia64_mca_check_errors(); +#endif // Too early in initialization -- error log is lost } /* * ia64_mca_wakeup_ipi_wait + * * Wait for the inter-cpu interrupt to be sent by the * monarch processor once it is done with handling the * MCA. - * Inputs - * None - * Outputs - * None + * + * Inputs : None + * Outputs : None */ void ia64_mca_wakeup_ipi_wait(void) @@ -339,16 +529,16 @@ ia64_mca_wakeup_ipi_wait(void) do { switch(irr_num) { - case 0: + case 0: irr = ia64_get_irr0(); break; - case 1: + case 1: irr = ia64_get_irr1(); break; - case 2: + case 2: irr = ia64_get_irr2(); break; - case 3: + case 3: irr = ia64_get_irr3(); break; } @@ -357,26 +547,28 @@ ia64_mca_wakeup_ipi_wait(void) /* * ia64_mca_wakeup + * * Send an inter-cpu interrupt to wake-up a particular cpu * and mark that cpu to be out of rendez. - * Inputs - * cpuid - * Outputs - * None + * + * Inputs : cpuid + * Outputs : None */ void ia64_mca_wakeup(int cpu) { platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; + } + /* * ia64_mca_wakeup_all + * * Wakeup all the cpus which have rendez'ed previously. - * Inputs - * None - * Outputs - * None + * + * Inputs : None + * Outputs : None */ void ia64_mca_wakeup_all(void) @@ -389,15 +581,16 @@ ia64_mca_wakeup_all(void) ia64_mca_wakeup(cpu); } + /* * ia64_mca_rendez_interrupt_handler + * * This is handler used to put slave processors into spinloop * while the monarch processor does the mca handling and later * wake each slave up once the monarch is done. - * Inputs - * None - * Outputs - * None + * + * Inputs : None + * Outputs : None */ void ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) @@ -423,23 +616,22 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) /* Enable all interrupts */ restore_flags(flags); - - } /* * ia64_mca_wakeup_int_handler + * * The interrupt handler for processing the inter-cpu interrupt to the * slave cpu which was spinning in the rendez loop. * Since this spinning is done by turning off the interrupts and * polling on the wakeup-interrupt bit in the IRR, there is * nothing useful to be done in the handler. - * Inputs - * wakeup_irq (Wakeup-interrupt bit) + * + * Inputs : wakeup_irq (Wakeup-interrupt bit) * arg (Interrupt handler specific argument) * ptregs (Exception frame at the time of the interrupt) - * Outputs + * Outputs : None * */ void @@ -450,16 +642,16 @@ ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) /* * ia64_return_to_sal_check + * * This is function called before going back from the OS_MCA handler * to the OS_MCA dispatch code which finally takes the control back * to the SAL. * The main purpose of this routine is to setup the OS_MCA to SAL * return state which can be used by the OS_MCA dispatch code * just before going back to SAL. - * Inputs - * None - * Outputs - * None + * + * Inputs : None + * Outputs : None */ void @@ -474,11 +666,13 @@ ia64_return_to_sal_check(void) ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; - /* For now ignore the MCA */ - ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; + /* Cold Boot for uncorrectable MCA */ + ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; } + /* * ia64_mca_ucmc_handler + * * This is uncorrectable machine check handler called from OS_MCA * dispatch code which is in turn called from SAL_CHECK(). * This is the place where the core of OS MCA handling is done. @@ -487,93 +681,92 @@ ia64_return_to_sal_check(void) * monarch processor. Once the monarch is done with MCA handling * further MCA logging is enabled by clearing logs. * Monarch also has the duty of sending wakeup-IPIs to pull the - * slave processors out of rendez. spinloop. - * Inputs - * None - * Outputs - * None + * slave processors out of rendezvous spinloop. + * + * Inputs : None + * Outputs : None */ void ia64_mca_ucmc_handler(void) { +#if 0 /* stubbed out @FVL */ + /* + * Attempting to log a DBE error Causes "reserved register/field panic" + * in printk. + */ - /* Get the MCA processor log */ - ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - /* Get the MCA platform log */ - ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); - - ia64_log_print(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + /* Get the MCA error record and log it */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); +#endif /* stubbed out @FVL */ /* - * Do some error handling - Platform-specific mca handler is called at this point + * Do Platform-specific mca error handling if required. */ - mca_handler_platform() ; - /* Clear the SAL MCA logs */ - ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, 1, printk); - ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, 1, printk); - - /* Wakeup all the processors which are spinning in the rendezvous - * loop. + /* + * Wakeup all the processors which are spinning in the rendezvous + * loop. */ ia64_mca_wakeup_all(); + + /* Return to SAL */ ia64_return_to_sal_check(); } /* * ia64_mca_cmc_int_handler - * This is correctable machine check interrupt handler. + * + * This is corrected machine check interrupt handler. * Right now the logs are extracted and displayed in a well-defined * format. + * * Inputs - * None + * interrupt number + * client data arg ptr + * saved registers ptr + * * Outputs * None */ void ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) { - /* Get the CMC processor log */ - ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - /* Get the CMC platform log */ - ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); - + IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n", + cmc_irq, smp_processor_id()); - ia64_log_print(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - cmci_handler_platform(cmc_irq, arg, ptregs); - - /* Clear the CMC SAL logs now that they have been saved in the OS buffer */ - ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC); + /* Get the CMC error record and log it */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC); } /* * IA64_MCA log support */ #define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */ -#define IA64_MAX_LOG_TYPES 3 /* MCA, CMC, INIT */ -#define IA64_MAX_LOG_SUBTYPES 2 /* Processor, Platform */ +#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */ -typedef struct ia64_state_log_s { +typedef struct ia64_state_log_s +{ spinlock_t isl_lock; int isl_index; - ia64_psilog_t isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ + ia64_err_rec_t isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ } ia64_state_log_t; -static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES]; - -#define IA64_LOG_LOCK_INIT(it, sit) spin_lock_init(&ia64_state_log[it][sit].isl_lock) -#define IA64_LOG_LOCK(it, sit) spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s) -#define IA64_LOG_UNLOCK(it, sit) spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\ - s) -#define IA64_LOG_NEXT_INDEX(it, sit) ia64_state_log[it][sit].isl_index -#define IA64_LOG_CURR_INDEX(it, sit) 1 - ia64_state_log[it][sit].isl_index -#define IA64_LOG_INDEX_INC(it, sit) \ - ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index -#define IA64_LOG_INDEX_DEC(it, sit) \ - ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index -#define IA64_LOG_NEXT_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)])) -#define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)])) +static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; + +/* Note: Some of these macros assume IA64_MAX_LOGS is always 2. Should be */ +/* fixed. @FVL */ +#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) +#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) +#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) +#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index +#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index +#define IA64_LOG_INDEX_INC(it) \ + ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index +#define IA64_LOG_INDEX_DEC(it) \ + ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index +#define IA64_LOG_NEXT_BUFFER(it) (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) +#define IA64_LOG_CURR_BUFFER(it) (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) /* * C portion of the OS INIT handler @@ -584,123 +777,217 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES * * Returns: * 0 if SAL must warm boot the System - * 1 if SAL must retrun to interrupted context using PAL_MC_RESUME + * 1 if SAL must return to interrupted context using PAL_MC_RESUME * */ - void ia64_init_handler (struct pt_regs *regs) { sal_log_processor_info_t *proc_ptr; - ia64_psilog_t *plog_ptr; + ia64_err_rec_t *plog_ptr; printk("Entered OS INIT handler\n"); /* Get the INIT processor log */ - ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - /* Get the INIT platform log */ - ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); + if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk)) + return; // no record retrieved #ifdef IA64_DUMP_ALL_PROC_INFO - ia64_log_print(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + ia64_log_print(SAL_INFO_TYPE_INIT, (prfunc_t)printk); #endif /* * get pointer to min state save area * */ - plog_ptr=(ia64_psilog_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT, - SAL_SUB_INFO_TYPE_PROCESSOR); - proc_ptr = &plog_ptr->devlog.proclog; + plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT); + proc_ptr = &plog_ptr->proc_err; - ia64_process_min_state_save(&proc_ptr->slpi_min_state_area,regs); - - init_handler_platform(regs); /* call platform specific routines */ + ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area, + regs); /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT); + + init_handler_platform(regs); /* call platform specific routines */ } +/* + * ia64_log_prt_guid + * + * Print a formatted GUID. + * + * Inputs : p_guid (ptr to the GUID) + * prfunc (print function) + * Outputs : None + * + */ +void +ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc) +{ + printk("GUID = { %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " + "%#02x, %#02x, %#02x, %#02x, } } \n ", p_guid->data1, + p_guid->data2, p_guid->data3, p_guid->data4[0], p_guid->data4[1], + p_guid->data4[2], p_guid->data4[3], p_guid->data4[4], + p_guid->data4[5], p_guid->data4[6], p_guid->data4[7]); +} + +static void +ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc) +{ + int i, j; + + if (!p) + return; + + for (i = 0; i < n_ch;) { + prfunc("%p ", (void *)p); + for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) { + prfunc("%02x ", *p); + } + prfunc("\n"); + } +} + +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + +static void +ia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc) +{ + prfunc("SAL RECORD HEADER: Record buffer = %p, header size = %ld\n", + (void *)rh, sizeof(sal_log_record_header_t)); + ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t), + (prfunc_t)prfunc); + prfunc("Total record length = %d\n", rh->len); + ia64_log_prt_guid(&rh->platform_guid, prfunc); + prfunc("End of SAL RECORD HEADER\n"); +} + +static void +ia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc) +{ + prfunc("SAL SECTION HEADER: Record buffer = %p, header size = %ld\n", + (void *)sh, sizeof(sal_log_section_hdr_t)); + ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t), + (prfunc_t)prfunc); + prfunc("Length of section & header = %d\n", sh->len); + ia64_log_prt_guid(&sh->guid, prfunc); + prfunc("End of SAL SECTION HEADER\n"); +} +#endif // MCA_PRT_XTRA_DATA for test only @FVL + /* * ia64_log_init * Reset the OS ia64 log buffer - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) - * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) * Outputs : None */ void -ia64_log_init(int sal_info_type, int sal_sub_info_type) +ia64_log_init(int sal_info_type) { - IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type); - IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0; - memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, - sizeof(ia64_psilog_t) * IA64_MAX_LOGS); + IA64_LOG_LOCK_INIT(sal_info_type); + IA64_LOG_NEXT_INDEX(sal_info_type) = 0; + memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, + sizeof(ia64_err_rec_t) * IA64_MAX_LOGS); } /* * ia64_log_get + * * Get the current MCA log from SAL and copy it into the OS log buffer. - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) - * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * Outputs : None + * + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * prfunc (fn ptr of log output function) + * Outputs : size (total record length) * */ -void -ia64_log_get(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) +u64 +ia64_log_get(int sal_info_type, prfunc_t prfunc) { - sal_log_header_t *log_buffer; - int s,total_len=0; - - IA64_LOG_LOCK(sal_info_type, sal_sub_info_type); + sal_log_record_header_t *log_buffer; + u64 total_len = 0; + int s; + IA64_LOG_LOCK(sal_info_type); /* Get the process state information */ - log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type); - - if (!(total_len=ia64_sal_get_state_info(sal_info_type,(u64 *)log_buffer))) - prfunc("ia64_mca_log_get : Getting processor log failed\n"); - - IA64_MCA_DEBUG("ia64_log_get: retrieved %d bytes of error information\n",total_len); - - IA64_LOG_INDEX_INC(sal_info_type, sal_sub_info_type); - - IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); - + log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); + + total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); + + if (total_len) { + IA64_LOG_INDEX_INC(sal_info_type); + IA64_LOG_UNLOCK(sal_info_type); + IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. " + "Record length = %ld\n", sal_info_type, total_len); + return total_len; + } else { + IA64_LOG_UNLOCK(sal_info_type); + prfunc("ia64_log_get: Failed to retrieve SAL error record type %d\n", + sal_info_type); + return 0; + } } /* - * ia64_log_clear - * Clear the current MCA log from SAL and dpending on the clear_os_buffer flags - * clear the OS log buffer also - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) - * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * clear_os_buffer + * ia64_log_prt_oem_data + * + * Print OEM specific data if included. + * + * Inputs : header_len (length passed in section header) + * sect_len (default length of section type) + * p_data (ptr to data) * prfunc (print function) * Outputs : None * */ void -ia64_log_clear(int sal_info_type, int sal_sub_info_type, int clear_os_buffer, prfunc_t prfunc) +ia64_log_prt_oem_data (int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) { - if (ia64_sal_clear_state_info(sal_info_type)) - prfunc("ia64_mca_log_get : Clearing processor log failed\n"); - - if (clear_os_buffer) { - sal_log_header_t *log_buffer; - int s; - - IA64_LOG_LOCK(sal_info_type, sal_sub_info_type); - - /* Get the process state information */ - log_buffer = IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type); + int oem_data_len, i; - memset(log_buffer, 0, sizeof(ia64_psilog_t)); - - IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type); - - IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); + if ((oem_data_len = header_len - sect_len) > 0) { + prfunc(" OEM Specific Data:"); + for (i = 0; i < oem_data_len; i++, p_data++) + prfunc(" %02x", *p_data); } + prfunc("\n"); +} +/* + * ia64_log_rec_header_print + * + * Log info from the SAL error record header. + * + * Inputs : lh * (ptr to SAL log error record header) + * prfunc (fn ptr of log output function to use) + * Outputs : None + */ +void +ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc) +{ + char str_buf[32]; + + sprintf(str_buf, "%2d.%02d", + (lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf), + (lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf)); + prfunc("+Err Record ID: %d SAL Rev: %s\n", lh->id, str_buf); + sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d", + (lh->timestamp.slh_month >> 4) * 10 + + (lh->timestamp.slh_month & 0xf), + (lh->timestamp.slh_day >> 4) * 10 + + (lh->timestamp.slh_day & 0xf), + (lh->timestamp.slh_century >> 4) * 1000 + + (lh->timestamp.slh_century & 0xf) * 100 + + (lh->timestamp.slh_year >> 4) * 10 + + (lh->timestamp.slh_year & 0xf), + (lh->timestamp.slh_hour >> 4) * 10 + + (lh->timestamp.slh_hour & 0xf), + (lh->timestamp.slh_minute >> 4) * 10 + + (lh->timestamp.slh_minute & 0xf), + (lh->timestamp.slh_second >> 4) * 10 + + (lh->timestamp.slh_second & 0xf)); + prfunc("+Time: %s Severity %d\n", str_buf, lh->severity); } /* @@ -729,6 +1016,33 @@ ia64_log_processor_regs_print(u64 *regs, prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]); } +/* + * ia64_log_processor_fp_regs_print + * Print the contents of the saved floating page register(s) in the format + * [] + * + * Inputs: ia64_fpreg (Register save buffer) + * reg_num (# of registers) + * reg_class (application/banked/control/bank1_general) + * reg_prefix (ar/br/cr/b1_gr) + * Outputs: None + * + */ +void +ia64_log_processor_fp_regs_print (struct ia64_fpreg *regs, + int reg_num, + char *reg_class, + char *reg_prefix, + prfunc_t prfunc) +{ + int i; + + prfunc("+%s Registers\n", reg_class); + for (i = 0; i < reg_num; i++) + prfunc("+ %s[%d] 0x%lx%016lx\n", reg_prefix, i, regs[i].u.bits[1], + regs[i].u.bits[0]); +} + static char *pal_mesi_state[] = { "Invalid", "Shared", @@ -754,69 +1068,91 @@ static char *pal_cache_op[] = { /* * ia64_log_cache_check_info_print * Display the machine check information related to cache error(s). - * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * Inputs: i (Multiple errors are logged, i - index of logged error) + * cc_info * (Ptr to cache check info logged by the PAL and later * captured by the SAL) - * target_addr (Address which caused the cache error) - * Outputs : None + * prfunc (fn ptr of print function to be used for output) + * Outputs: None */ void -ia64_log_cache_check_info_print(int i, - pal_cache_check_info_t info, - u64 target_addr, - prfunc_t prfunc) +ia64_log_cache_check_info_print (int i, + sal_log_mod_error_info_t *cache_check_info, + prfunc_t prfunc) { + pal_cache_check_info_t *info; + u64 target_addr; + + if (!cache_check_info->valid.check_info) { + IA64_MCA_DEBUG("ia64_mca_log_print: invalid cache_check_info[%d]\n",i); + return; /* If check info data not valid, skip it */ + } + + info = (pal_cache_check_info_t *)&cache_check_info->check_info; + target_addr = cache_check_info->target_identifier; + prfunc("+ Cache check info[%d]\n+", i); - prfunc(" Level: L%d",info.level); - if (info.mv) - prfunc(" ,Mesi: %s",pal_mesi_state[info.mesi]); - prfunc(" ,Index: %d,", info.index); - if (info.ic) - prfunc(" ,Cache: Instruction"); - if (info.dc) - prfunc(" ,Cache: Data"); - if (info.tl) - prfunc(" ,Line: Tag"); - if (info.dl) - prfunc(" ,Line: Data"); - prfunc(" ,Operation: %s,", pal_cache_op[info.op]); - if (info.wv) - prfunc(" ,Way: %d,", info.way); - if (info.tv) - prfunc(" ,Target Addr: 0x%lx", target_addr); - if (info.mc) - prfunc(" ,MC: Corrected"); + prfunc(" Level: L%d,",info->level); + if (info->mv) + prfunc(" Mesi: %s,",pal_mesi_state[info->mesi]); + prfunc(" Index: %d,", info->index); + if (info->ic) + prfunc(" Cache: Instruction,"); + if (info->dc) + prfunc(" Cache: Data,"); + if (info->tl) + prfunc(" Line: Tag,"); + if (info->dl) + prfunc(" Line: Data,"); + prfunc(" Operation: %s,", pal_cache_op[info->op]); + if (info->wv) + prfunc(" Way: %d,", info->way); + if (cache_check_info->valid.target_identifier) + /* Hope target address is saved in target_identifier */ + if (info->tv) + prfunc(" Target Addr: 0x%lx,", target_addr); + if (info->mc) + prfunc(" MC: Corrected"); prfunc("\n"); } /* * ia64_log_tlb_check_info_print * Display the machine check information related to tlb error(s). - * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * Inputs: i (Multiple errors are logged, i - index of logged error) + * tlb_info * (Ptr to machine check info logged by the PAL and later * captured by the SAL) - * Outputs : None + * prfunc (fn ptr of print function to be used for output) + * Outputs: None */ - void -ia64_log_tlb_check_info_print(int i, - pal_tlb_check_info_t info, - prfunc_t prfunc) +ia64_log_tlb_check_info_print (int i, + sal_log_mod_error_info_t *tlb_check_info, + prfunc_t prfunc) + { + pal_tlb_check_info_t *info; + + if (!tlb_check_info->valid.check_info) { + IA64_MCA_DEBUG("ia64_mca_log_print: invalid tlb_check_info[%d]\n", i); + return; /* If check info data not valid, skip it */ + } + + info = (pal_tlb_check_info_t *)&tlb_check_info->check_info; + prfunc("+ TLB Check Info [%d]\n+", i); - if (info.itc) + if (info->itc) prfunc(" Failure: Instruction Translation Cache"); - if (info.dtc) + if (info->dtc) prfunc(" Failure: Data Translation Cache"); - if (info.itr) { + if (info->itr) { prfunc(" Failure: Instruction Translation Register"); - prfunc(" ,Slot: %d", info.tr_slot); + prfunc(" ,Slot: %d", info->tr_slot); } - if (info.dtr) { + if (info->dtr) { prfunc(" Failure: Data Translation Register"); - prfunc(" ,Slot: %d", info.tr_slot); + prfunc(" ,Slot: %d", info->tr_slot); } - if (info.mc) + if (info->mc) prfunc(" ,MC: Corrected"); prfunc("\n"); } @@ -824,159 +1160,721 @@ ia64_log_tlb_check_info_print(int i, /* * ia64_log_bus_check_info_print * Display the machine check information related to bus error(s). - * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * Inputs: i (Multiple errors are logged, i - index of logged error) + * bus_info * (Ptr to machine check info logged by the PAL and later * captured by the SAL) - * req_addr (Address of the requestor of the transaction) - * resp_addr (Address of the responder of the transaction) - * target_addr (Address where the data was to be delivered to or - * obtained from) - * Outputs : None + * prfunc (fn ptr of print function to be used for output) + * Outputs: None */ void -ia64_log_bus_check_info_print(int i, - pal_bus_check_info_t info, - u64 req_addr, - u64 resp_addr, - u64 targ_addr, - prfunc_t prfunc) +ia64_log_bus_check_info_print (int i, + sal_log_mod_error_info_t *bus_check_info, + prfunc_t prfunc) { + pal_bus_check_info_t *info; + u64 req_addr; /* Address of the requestor of the transaction */ + u64 resp_addr; /* Address of the responder of the transaction */ + u64 targ_addr; /* Address where the data was to be delivered to */ + /* or obtained from */ + + if (!bus_check_info->valid.check_info) { + IA64_MCA_DEBUG("ia64_mca_log_print: invalid bus_check_info[%d]\n", i); + return; /* If check info data not valid, skip it */ + } + + info = (pal_bus_check_info_t *)&bus_check_info->check_info; + req_addr = bus_check_info->requestor_identifier; + resp_addr = bus_check_info->responder_identifier; + targ_addr = bus_check_info->target_identifier; + prfunc("+ BUS Check Info [%d]\n+", i); - prfunc(" Status Info: %d", info.bsi); - prfunc(" ,Severity: %d", info.sev); - prfunc(" ,Transaction Type: %d", info.type); - prfunc(" ,Transaction Size: %d", info.size); - if (info.cc) + prfunc(" Status Info: %d", info->bsi); + prfunc(" ,Severity: %d", info->sev); + prfunc(" ,Transaction Type: %d", info->type); + prfunc(" ,Transaction Size: %d", info->size); + if (info->cc) prfunc(" ,Cache-cache-transfer"); - if (info.ib) + if (info->ib) prfunc(" ,Error: Internal"); - if (info.eb) + if (info->eb) prfunc(" ,Error: External"); - if (info.mc) + if (info->mc) prfunc(" ,MC: Corrected"); - if (info.tv) + if (info->tv) prfunc(" ,Target Address: 0x%lx", targ_addr); - if (info.rq) + if (info->rq) prfunc(" ,Requestor Address: 0x%lx", req_addr); - if (info.tv) + if (info->tv) prfunc(" ,Responder Address: 0x%lx", resp_addr); prfunc("\n"); } +/* + * ia64_log_mem_dev_err_info_print + * + * Format and log the platform memory device error record section data. + * + * Inputs: mem_dev_err_info * (Ptr to memory device error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_mem_dev_err_info_print (sal_log_mem_dev_err_info_t *mdei, + prfunc_t prfunc) +{ + prfunc("+ Mem Error Detail: "); + + if (mdei->valid.error_status) + prfunc(" Error Status: %#lx,", mdei->error_status); + if (mdei->valid.physical_addr) + prfunc(" Physical Address: %#lx,", mdei->physical_addr); + if (mdei->valid.addr_mask) + prfunc(" Address Mask: %#lx,", mdei->addr_mask); + if (mdei->valid.node) + prfunc(" Node: %d,", mdei->node); + if (mdei->valid.card) + prfunc(" Card: %d,", mdei->card); + if (mdei->valid.module) + prfunc(" Module: %d,", mdei->module); + if (mdei->valid.bank) + prfunc(" Bank: %d,", mdei->bank); + if (mdei->valid.device) + prfunc(" Device: %d,", mdei->device); + if (mdei->valid.row) + prfunc(" Row: %d,", mdei->row); + if (mdei->valid.column) + prfunc(" Column: %d,", mdei->column); + if (mdei->valid.bit_position) + prfunc(" Bit Position: %d,", mdei->bit_position); + if (mdei->valid.target_id) + prfunc(" ,Target Address: %#lx,", mdei->target_id); + if (mdei->valid.requestor_id) + prfunc(" ,Requestor Address: %#lx,", mdei->requestor_id); + if (mdei->valid.responder_id) + prfunc(" ,Responder Address: %#lx,", mdei->responder_id); + if (mdei->valid.bus_spec_data) + prfunc(" Bus Specific Data: %#lx,", mdei->bus_spec_data); + prfunc("\n"); + + if (mdei->valid.oem_id) { + u8 *p_data = &(mdei->oem_id[0]); + int i; + + prfunc(" OEM Memory Controller ID:"); + for (i = 0; i < 16; i++, p_data++) + prfunc(" %02x", *p_data); + prfunc("\n"); + } + + if (mdei->valid.oem_data) { + ia64_log_prt_oem_data((int)mdei->header.len, + (int)sizeof(sal_log_mem_dev_err_info_t) - 1, + &(mdei->oem_data[0]), prfunc); + } +} + +/* + * ia64_log_sel_dev_err_info_print + * + * Format and log the platform SEL device error record section data. + * + * Inputs: sel_dev_err_info * (Ptr to the SEL device error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_sel_dev_err_info_print (sal_log_sel_dev_err_info_t *sdei, + prfunc_t prfunc) +{ + int i; + + prfunc("+ SEL Device Error Detail: "); + + if (sdei->valid.record_id) + prfunc(" Record ID: %#x", sdei->record_id); + if (sdei->valid.record_type) + prfunc(" Record Type: %#x", sdei->record_type); + prfunc(" Time Stamp: "); + for (i = 0; i < 4; i++) + prfunc("%1d", sdei->timestamp[i]); + if (sdei->valid.generator_id) + prfunc(" Generator ID: %#x", sdei->generator_id); + if (sdei->valid.evm_rev) + prfunc(" Message Format Version: %#x", sdei->evm_rev); + if (sdei->valid.sensor_type) + prfunc(" Sensor Type: %#x", sdei->sensor_type); + if (sdei->valid.sensor_num) + prfunc(" Sensor Number: %#x", sdei->sensor_num); + if (sdei->valid.event_dir) + prfunc(" Event Direction Type: %#x", sdei->event_dir); + if (sdei->valid.event_data1) + prfunc(" Data1: %#x", sdei->event_data1); + if (sdei->valid.event_data2) + prfunc(" Data2: %#x", sdei->event_data2); + if (sdei->valid.event_data3) + prfunc(" Data3: %#x", sdei->event_data3); + prfunc("\n"); + +} + +/* + * ia64_log_pci_bus_err_info_print + * + * Format and log the platform PCI bus error record section data. + * + * Inputs: pci_bus_err_info * (Ptr to the PCI bus error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_pci_bus_err_info_print (sal_log_pci_bus_err_info_t *pbei, + prfunc_t prfunc) +{ + prfunc("+ PCI Bus Error Detail: "); + + if (pbei->valid.err_status) + prfunc(" Error Status: %#lx", pbei->err_status); + if (pbei->valid.err_type) + prfunc(" Error Type: %#x", pbei->err_type); + if (pbei->valid.bus_id) + prfunc(" Bus ID: %#x", pbei->bus_id); + if (pbei->valid.bus_address) + prfunc(" Bus Address: %#lx", pbei->bus_address); + if (pbei->valid.bus_data) + prfunc(" Bus Data: %#lx", pbei->bus_data); + if (pbei->valid.bus_cmd) + prfunc(" Bus Command: %#lx", pbei->bus_cmd); + if (pbei->valid.requestor_id) + prfunc(" Requestor ID: %#lx", pbei->requestor_id); + if (pbei->valid.responder_id) + prfunc(" Responder ID: %#lx", pbei->responder_id); + if (pbei->valid.target_id) + prfunc(" Target ID: %#lx", pbei->target_id); + if (pbei->valid.oem_data) + prfunc("\n"); + + if (pbei->valid.oem_data) { + ia64_log_prt_oem_data((int)pbei->header.len, + (int)sizeof(sal_log_pci_bus_err_info_t) - 1, + &(pbei->oem_data[0]), prfunc); + } +} + +/* + * ia64_log_smbios_dev_err_info_print + * + * Format and log the platform SMBIOS device error record section data. + * + * Inputs: smbios_dev_err_info * (Ptr to the SMBIOS device error record + * section returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_smbios_dev_err_info_print (sal_log_smbios_dev_err_info_t *sdei, + prfunc_t prfunc) +{ + u8 i; + + prfunc("+ SMBIOS Device Error Detail: "); + + if (sdei->valid.event_type) + prfunc(" Event Type: %#x", sdei->event_type); + if (sdei->valid.time_stamp) { + prfunc(" Time Stamp: "); + for (i = 0; i < 6; i++) + prfunc("%d", sdei->time_stamp[i]); + } + if ((sdei->valid.data) && (sdei->valid.length)) { + prfunc(" Data: "); + for (i = 0; i < sdei->length; i++) + prfunc(" %02x", sdei->data[i]); + } + prfunc("\n"); +} + +/* + * ia64_log_pci_comp_err_info_print + * + * Format and log the platform PCI component error record section data. + * + * Inputs: pci_comp_err_info * (Ptr to the PCI component error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_pci_comp_err_info_print(sal_log_pci_comp_err_info_t *pcei, + prfunc_t prfunc) +{ + u32 n_mem_regs, n_io_regs; + u64 i, n_pci_data; + u64 *p_reg_data; + u8 *p_oem_data; + + prfunc("+ PCI Component Error Detail: "); + + if (pcei->valid.err_status) + prfunc(" Error Status: %#lx\n", pcei->err_status); + if (pcei->valid.comp_info) + prfunc(" Component Info: Vendor Id = %#x, Device Id = %#x," + " Class Code = %#x, Seg/Bus/Dev/Func = %d/%d/%d/%d\n", + pcei->comp_info.vendor_id, pcei->comp_info.device_id, + pcei->comp_info.class_code, pcei->comp_info.seg_num, + pcei->comp_info.bus_num, pcei->comp_info.dev_num, + pcei->comp_info.func_num); + + n_mem_regs = (pcei->valid.num_mem_regs) ? pcei->num_mem_regs : 0; + n_io_regs = (pcei->valid.num_io_regs) ? pcei->num_io_regs : 0; + p_reg_data = &(pcei->reg_data_pairs[0]); + p_oem_data = (u8 *)p_reg_data + + (n_mem_regs + n_io_regs) * 2 * sizeof(u64); + n_pci_data = p_oem_data - (u8 *)pcei; + + if (n_pci_data > pcei->header.len) { + prfunc(" Invalid PCI Component Error Record format: length = %ld, " + " Size PCI Data = %d, Num Mem-Map/IO-Map Regs = %ld/%ld\n", + pcei->header.len, n_pci_data, n_mem_regs, n_io_regs); + return; + } + + if (n_mem_regs) { + prfunc(" Memory Mapped Registers\n Address \tValue\n"); + for (i = 0; i < pcei->num_mem_regs; i++) { + prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]); + p_reg_data += 2; + } + } + if (n_io_regs) { + prfunc(" I/O Mapped Registers\n Address \tValue\n"); + for (i = 0; i < pcei->num_io_regs; i++) { + prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]); + p_reg_data += 2; + } + } + if (pcei->valid.oem_data) { + ia64_log_prt_oem_data((int)pcei->header.len, n_pci_data, + p_oem_data, prfunc); + prfunc("\n"); + } +} + +/* + * ia64_log_plat_specific_err_info_print + * + * Format and log the platform specifie error record section data. + * + * Inputs: sel_dev_err_info * (Ptr to the platform specific error record + * section returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_plat_specific_err_info_print (sal_log_plat_specific_err_info_t *psei, + prfunc_t prfunc) +{ + prfunc("+ Platform Specific Error Detail: "); + + if (psei->valid.err_status) + prfunc(" Error Status: %#lx", psei->err_status); + if (psei->valid.guid) { + prfunc(" GUID: "); + ia64_log_prt_guid(&psei->guid, prfunc); + } + if (psei->valid.oem_data) { + ia64_log_prt_oem_data((int)psei->header.len, + (int)sizeof(sal_log_plat_specific_err_info_t) - 1, + &(psei->oem_data[0]), prfunc); + } + prfunc("\n"); +} + +/* + * ia64_log_host_ctlr_err_info_print + * + * Format and log the platform host controller error record section data. + * + * Inputs: host_ctlr_err_info * (Ptr to the host controller error record + * section returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_host_ctlr_err_info_print (sal_log_host_ctlr_err_info_t *hcei, + prfunc_t prfunc) +{ + prfunc("+ Host Controller Error Detail: "); + + if (hcei->valid.err_status) + prfunc(" Error Status: %#lx", hcei->err_status); + if (hcei->valid.requestor_id) + prfunc(" Requestor ID: %#lx", hcei->requestor_id); + if (hcei->valid.responder_id) + prfunc(" Responder ID: %#lx", hcei->responder_id); + if (hcei->valid.target_id) + prfunc(" Target ID: %#lx", hcei->target_id); + if (hcei->valid.bus_spec_data) + prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data); + if (hcei->valid.oem_data) { + ia64_log_prt_oem_data((int)hcei->header.len, + (int)sizeof(sal_log_host_ctlr_err_info_t) - 1, + &(hcei->oem_data[0]), prfunc); + } + prfunc("\n"); +} + +/* + * ia64_log_plat_bus_err_info_print + * + * Format and log the platform bus error record section data. + * + * Inputs: plat_bus_err_info * (Ptr to the platform bus error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_plat_bus_err_info_print (sal_log_plat_bus_err_info_t *pbei, + prfunc_t prfunc) +{ + prfunc("+ Platform Bus Error Detail: "); + + if (pbei->valid.err_status) + prfunc(" Error Status: %#lx", pbei->err_status); + if (pbei->valid.requestor_id) + prfunc(" Requestor ID: %#lx", pbei->requestor_id); + if (pbei->valid.responder_id) + prfunc(" Responder ID: %#lx", pbei->responder_id); + if (pbei->valid.target_id) + prfunc(" Target ID: %#lx", pbei->target_id); + if (pbei->valid.bus_spec_data) + prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data); + if (pbei->valid.oem_data) { + ia64_log_prt_oem_data((int)pbei->header.len, + (int)sizeof(sal_log_plat_bus_err_info_t) - 1, + &(pbei->oem_data[0]), prfunc); + } + prfunc("\n"); +} + +/* + * ia64_log_proc_dev_err_info_print + * + * Display the processor device error record. + * + * Inputs: sal_log_processor_info_t * (Ptr to processor device error record + * section body). + * prfunc (fn ptr of print function to be used + * for output). + * Outputs: None + */ +void +ia64_log_proc_dev_err_info_print (sal_log_processor_info_t *slpi, + prfunc_t prfunc) +{ +#ifdef MCA_PRT_XTRA_DATA + size_t d_len = slpi->header.len - sizeof(sal_log_section_hdr_t); +#endif + sal_processor_static_info_t *spsi; + int i; + sal_log_mod_error_info_t *p_data; + + prfunc("+Processor Device Error Info Section\n"); + +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + { + char *p_data = (char *)&slpi->valid; + + prfunc("SAL_PROC_DEV_ERR SECTION DATA: Data buffer = %p, " + "Data size = %ld\n", (void *)p_data, d_len); + ia64_log_hexdump(p_data, d_len, prfunc); + prfunc("End of SAL_PROC_DEV_ERR SECTION DATA\n"); + } +#endif // MCA_PRT_XTRA_DATA for test only @FVL + + if (slpi->valid.proc_error_map) + prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map); + + if (slpi->valid.proc_state_param) + prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter); + + if (slpi->valid.proc_cr_lid) + prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid); + + /* + * Note: March 2001 SAL spec states that if the number of elements in any + * of the MOD_ERROR_INFO_STRUCT arrays is zero, the entire array is + * absent. Also, current implementations only allocate space for number of + * elements used. So we walk the data pointer from here on. + */ + p_data = &slpi->cache_check_info[0]; + + /* Print the cache check information if any*/ + for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++) + ia64_log_cache_check_info_print(i, p_data, prfunc); + + /* Print the tlb check information if any*/ + for (i = 0 ; i < slpi->valid.num_tlb_check; i++, p_data++) + ia64_log_tlb_check_info_print(i, p_data, prfunc); + + /* Print the bus check information if any*/ + for (i = 0 ; i < slpi->valid.num_bus_check; i++, p_data++) + ia64_log_bus_check_info_print(i, p_data, prfunc); + + /* Print the reg file check information if any*/ + for (i = 0 ; i < slpi->valid.num_reg_file_check; i++, p_data++) + ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t), + prfunc); /* Just hex dump for now */ + + /* Print the ms check information if any*/ + for (i = 0 ; i < slpi->valid.num_ms_check; i++, p_data++) + ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t), + prfunc); /* Just hex dump for now */ + + /* Print CPUID registers if any*/ + if (slpi->valid.cpuid_info) { + u64 *p = (u64 *)p_data; + + prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]); + p_data++; + } + + /* Print processor static info if any */ + if (slpi->valid.psi_static_struct) { + spsi = (sal_processor_static_info_t *)p_data; + + /* Print branch register contents if valid */ + if (spsi->valid.br) + ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br", + prfunc); + + /* Print control register contents if valid */ + if (spsi->valid.cr) + ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr", + prfunc); + + /* Print application register contents if valid */ + if (spsi->valid.ar) + ia64_log_processor_regs_print(spsi->ar, 128, "Application", + "ar", prfunc); + + /* Print region register contents if valid */ + if (spsi->valid.rr) + ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr", + prfunc); + + /* Print floating-point register contents if valid */ + if (spsi->valid.fr) + ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr", + prfunc); + } +} + /* * ia64_log_processor_info_print + * * Display the processor-specific information logged by PAL as a part * of MCA or INIT or CMC. - * Inputs : lh (Pointer of the sal log header which specifies the format - * of SAL state info as specified by the SAL spec). + * + * Inputs : lh (Pointer of the sal log header which specifies the + * format of SAL state info as specified by the SAL spec). + * prfunc (fn ptr of print function to be used for output). * Outputs : None */ void -ia64_log_processor_info_print(sal_log_header_t *lh, prfunc_t prfunc) +ia64_log_processor_info_print(sal_log_record_header_t *lh, prfunc_t prfunc) { - sal_log_processor_info_t *slpi; - int i; + sal_log_section_hdr_t *slsh; + int n_sects; + int ercd_pos; if (!lh) return; - if (lh->slh_log_type != SAL_SUB_INFO_TYPE_PROCESSOR) +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + ia64_log_prt_record_header(lh, prfunc); +#endif // MCA_PRT_XTRA_DATA for test only @FVL + + if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) { + IA64_MCA_DEBUG("ia64_mca_log_print: " + "truncated SAL CMC error record. len = %d\n", + lh->len); return; + } + + /* Print record header info */ + ia64_log_rec_header_print(lh, prfunc); - slpi = (sal_log_processor_info_t *)((char *)lh+sizeof(sal_log_header_t)); /* point to proc info */ + for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) { + /* point to next section header */ + slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos); + +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + ia64_log_prt_section_header(slsh, prfunc); +#endif // MCA_PRT_XTRA_DATA for test only @FVL + + if (verify_guid((void *)&slsh->guid, (void *)&(SAL_PROC_DEV_ERR_SECT_GUID))) { + IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); + continue; + } - if (!slpi) { - prfunc("No Processor Error Log found\n"); + /* + * Now process processor device error record section + */ + ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, + printk); + } + + IA64_MCA_DEBUG("ia64_mca_log_print: " + "found %d sections in SAL CMC error record. len = %d\n", + n_sects, lh->len); + if (!n_sects) { + prfunc("No Processor Device Error Info Section found\n"); return; } +} - /* Print branch register contents if valid */ - if (slpi->slpi_valid.slpi_br) - ia64_log_processor_regs_print(slpi->slpi_br, 8, "Branch", "br", prfunc); +/* + * ia64_log_platform_info_print + * + * Format and Log the SAL Platform Error Record. + * + * Inputs : lh (Pointer to the sal error record header with format + * specified by the SAL spec). + * prfunc (fn ptr of log output function to use) + * Outputs : None + */ +void +ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc) +{ + sal_log_section_hdr_t *slsh; + int n_sects; + int ercd_pos; - /* Print control register contents if valid */ - if (slpi->slpi_valid.slpi_cr) - ia64_log_processor_regs_print(slpi->slpi_cr, 128, "Control", "cr", prfunc); + if (!lh) + return; - /* Print application register contents if valid */ - if (slpi->slpi_valid.slpi_ar) - ia64_log_processor_regs_print(slpi->slpi_br, 128, "Application", "ar", prfunc); +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + ia64_log_prt_record_header(lh, prfunc); +#endif // MCA_PRT_XTRA_DATA for test only @FVL - /* Print region register contents if valid */ - if (slpi->slpi_valid.slpi_rr) - ia64_log_processor_regs_print(slpi->slpi_rr, 8, "Region", "rr", prfunc); + if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) { + IA64_MCA_DEBUG("ia64_mca_log_print: " + "truncated SAL error record. len = %d\n", + lh->len); + return; + } - /* Print floating-point register contents if valid */ - if (slpi->slpi_valid.slpi_fr) - ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", - prfunc); + /* Print record header info */ + ia64_log_rec_header_print(lh, prfunc); - /* Print the cache check information if any*/ - for (i = 0 ; i < MAX_CACHE_ERRORS; i++) - ia64_log_cache_check_info_print(i, - slpi->slpi_cache_check_info[i].slpi_cache_check, - slpi->slpi_cache_check_info[i].slpi_target_address, - prfunc); - /* Print the tlb check information if any*/ - for (i = 0 ; i < MAX_TLB_ERRORS; i++) - ia64_log_tlb_check_info_print(i,slpi->slpi_tlb_check_info[i], prfunc); + for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) { + /* point to next section header */ + slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos); - /* Print the bus check information if any*/ - for (i = 0 ; i < MAX_BUS_ERRORS; i++) - ia64_log_bus_check_info_print(i, - slpi->slpi_bus_check_info[i].slpi_bus_check, - slpi->slpi_bus_check_info[i].slpi_requestor_addr, - slpi->slpi_bus_check_info[i].slpi_responder_addr, - slpi->slpi_bus_check_info[i].slpi_target_addr, - prfunc); +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + ia64_log_prt_section_header(slsh, prfunc); + if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) != 0) { + size_t d_len = slsh->len - sizeof(sal_log_section_hdr_t); + char *p_data = (char *)&((sal_log_mem_dev_err_info_t *)slsh)->valid; + + prfunc("Start of Platform Err Data Section: Data buffer = %p, " + "Data size = %ld\n", (void *)p_data, d_len); + ia64_log_hexdump(p_data, d_len, prfunc); + prfunc("End of Platform Err Data Section\n"); + } +#endif // MCA_PRT_XTRA_DATA for test only @FVL + + /* + * Now process CPE error record section + */ + if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) == 0) { + ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) { + prfunc("+Platform Memory Device Error Info Section\n"); + ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) == 0) { + prfunc("+Platform SEL Device Error Info Section\n"); + ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) == 0) { + prfunc("+Platform PCI Bus Error Info Section\n"); + ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) == 0) { + prfunc("+Platform SMBIOS Device Error Info Section\n"); + ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) == 0) { + prfunc("+Platform PCI Component Error Info Section\n"); + ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) { + prfunc("+Platform Specific Error Info Section\n"); + ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *) + slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) == 0) { + prfunc("+Platform Host Controller Error Info Section\n"); + ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) == 0) { + prfunc("+Platform Bus Error Info Section\n"); + ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh, + prfunc); + } else { + IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); + continue; + } + } + + IA64_MCA_DEBUG("ia64_mca_log_print: found %d sections in SAL error record. len = %d\n", + n_sects, lh->len); + if (!n_sects) { + prfunc("No Platform Error Info Sections found\n"); + return; + } } /* * ia64_log_print - * Display the contents of the OS error log information - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) - * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) + * + * Displays the contents of the OS error log information + * + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * prfunc (fn ptr of log output function to use) * Outputs : None */ void -ia64_log_print(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) +ia64_log_print(int sal_info_type, prfunc_t prfunc) { - char *info_type, *sub_info_type; - switch(sal_info_type) { - case SAL_INFO_TYPE_MCA: - info_type = "MCA"; - break; - case SAL_INFO_TYPE_INIT: - info_type = "INIT"; - break; - case SAL_INFO_TYPE_CMC: - info_type = "CMC"; + case SAL_INFO_TYPE_MCA: + prfunc("+BEGIN HARDWARE ERROR STATE AT MCA\n"); + ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); + prfunc("+END HARDWARE ERROR STATE AT MCA\n"); break; - default: - info_type = "UNKNOWN"; + case SAL_INFO_TYPE_INIT: + prfunc("+MCA INIT ERROR LOG (UNIMPLEMENTED)\n"); break; - } - - switch(sal_sub_info_type) { - case SAL_SUB_INFO_TYPE_PROCESSOR: - sub_info_type = "PROCESSOR"; + case SAL_INFO_TYPE_CMC: + prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n"); + ia64_log_processor_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); + prfunc("+END HARDWARE ERROR STATE AT CMC\n"); break; - case SAL_SUB_INFO_TYPE_PLATFORM: - sub_info_type = "PLATFORM"; + case SAL_INFO_TYPE_CPE: + prfunc("+BEGIN HARDWARE ERROR STATE AT CPE\n"); + ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); + prfunc("+END HARDWARE ERROR STATE AT CPE\n"); break; - default: - sub_info_type = "UNKNOWN"; + default: + prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n"); break; } - - prfunc("+BEGIN HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type); - if (sal_sub_info_type == SAL_SUB_INFO_TYPE_PROCESSOR) - ia64_log_processor_info_print( - IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type), - prfunc); - else - log_print_platform(IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type),prfunc); - prfunc("+END HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type); } diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index 45e0ffa47726..18a10311e58c 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -9,6 +9,7 @@ // #include +#include #include #include #include @@ -23,7 +24,7 @@ #include "minstate.h" /* - * SAL_TO_OS_MCA_HANDOFF_STATE + * SAL_TO_OS_MCA_HANDOFF_STATE (SAL 3.0 spec) * 1. GR1 = OS GP * 2. GR8 = PAL_PROC physical address * 3. GR9 = SAL_PROC physical address @@ -33,6 +34,7 @@ */ #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ movl _tmp=ia64_sal_to_os_handoff_state;; \ + DATA_VA_TO_PA(_tmp);; \ st8 [_tmp]=r1,0x08;; \ st8 [_tmp]=r8,0x08;; \ st8 [_tmp]=r9,0x08;; \ @@ -41,47 +43,29 @@ st8 [_tmp]=r12,0x08;; /* - * OS_MCA_TO_SAL_HANDOFF_STATE - * 1. GR8 = OS_MCA status - * 2. GR9 = SAL GP (physical) - * 3. GR22 = New min state save area pointer + * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) + * 1. GR8 = OS_MCA return status + * 2. GR9 = SAL GP (physical) + * 3. GR10 = 0/1 returning same/new context + * 4. GR22 = New min state save area pointer + * returns ptr to SAL rtn save loc in _tmp */ -#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ - movl _tmp=ia64_os_to_sal_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ - ld8 r8=[_tmp],0x08;; \ - ld8 r9=[_tmp],0x08;; \ - ld8 r22=[_tmp],0x08;; - -/* - * BRANCH - * Jump to the instruction referenced by - * "to_label". - * Branch is taken only if the predicate - * register "p" is true. - * "ip" is the address of the instruction - * located at "from_label". - * "temp" is a scratch register like r2 - * "adjust" needed for HP compiler. - * A screwup somewhere with constant arithmetic. - */ -#define BRANCH(to_label, temp, p, adjust) \ -100: (p) mov temp=ip; \ - ;; \ - (p) adds temp=to_label-100b,temp;\ - ;; \ - (p) adds temp=adjust,temp; \ - ;; \ - (p) mov b1=temp ; \ - (p) br b1 +#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ + movl _tmp=ia64_os_to_sal_handoff_state;; \ + DATA_VA_TO_PA(_tmp);; \ + ld8 r8=[_tmp],0x08;; \ + ld8 r9=[_tmp],0x08;; \ + ld8 r10=[_tmp],0x08;; \ + ld8 r22=[_tmp],0x08;; \ + movl _tmp=ia64_sal_to_os_handoff_state;; \ + DATA_VA_TO_PA(_tmp);; \ + add _tmp=0x28,_tmp;; // point to SAL rtn save location .global ia64_os_mca_dispatch .global ia64_os_mca_dispatch_end .global ia64_sal_to_os_handoff_state .global ia64_os_to_sal_handoff_state - .global ia64_os_mca_ucmc_handler .global ia64_mca_proc_state_dump - .global ia64_mca_proc_state_restore .global ia64_mca_stack .global ia64_mca_stackframe .global ia64_mca_bspstore @@ -100,7 +84,7 @@ ia64_os_mca_dispatch: #endif /* #if defined(MCA_TEST) */ // Save the SAL to OS MCA handoff state as defined - // by SAL SPEC 2.5 + // by SAL SPEC 3.0 // NOTE : The order in which the state gets saved // is dependent on the way the C-structure // for ia64_mca_sal_to_os_state_t has been @@ -110,15 +94,20 @@ ia64_os_mca_dispatch: // LOG PROCESSOR STATE INFO FROM HERE ON.. ;; begin_os_mca_dump: - BRANCH(ia64_os_mca_proc_state_dump, r2, p0, 0x0) - ;; + br ia64_os_mca_proc_state_dump;; + ia64_os_mca_done_dump: // Setup new stack frame for OS_MCA handling - movl r2=ia64_mca_bspstore // local bspstore area location in r2 - movl r3=ia64_mca_stackframe // save stack frame to memory in r3 + movl r2=ia64_mca_bspstore;; // local bspstore area location in r2 + DATA_VA_TO_PA(r2);; + movl r3=ia64_mca_stackframe;; // save stack frame to memory in r3 + DATA_VA_TO_PA(r3);; rse_switch_context(r6,r3,r2);; // RSC management in this new context movl r12=ia64_mca_stack;; + mov r2=8*1024;; // stack size must be same as c array + add r12=r2,r12;; // stack base @ bottom of array + DATA_VA_TO_PA(r12);; // Enter virtual mode from physical mode VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4) @@ -127,7 +116,7 @@ ia64_os_mca_virtual_begin: // call our handler movl r2=ia64_mca_ucmc_handler;; mov b6=r2;; - br.call.sptk.few b0=b6 + br.call.sptk.many b0=b6;; .ret0: // Revert back to physical mode before going back to SAL PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4) @@ -135,9 +124,9 @@ ia64_os_mca_virtual_end: #if defined(MCA_TEST) // Pretend that we are in interrupt context - mov r2=psr - dep r2=0, r2, PSR_IC, 2; - mov psr.l = r2 + mov r2=psr;; + dep r2=0, r2, PSR_IC, 2;; + mov psr.l = r2;; #endif /* #if defined(MCA_TEST) */ // restore the original stack frame here @@ -152,15 +141,14 @@ ia64_os_mca_virtual_end: mov r8=gp ;; begin_os_mca_restore: - BRANCH(ia64_os_mca_proc_state_restore, r2, p0, 0x0) - ;; + br ia64_os_mca_proc_state_restore;; ia64_os_mca_done_restore: ;; // branch back to SALE_CHECK OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2) ld8 r3=[r2];; - mov b0=r3 // SAL_CHECK return address + mov b0=r3;; // SAL_CHECK return address br b0 ;; ia64_os_mca_dispatch_end: @@ -178,8 +166,10 @@ ia64_os_mca_dispatch_end: //-- ia64_os_mca_proc_state_dump: -// Get and save GR0-31 from Proc. Min. State Save Area to SAL PSI +// Save bank 1 GRs 16-31 which will be used by c-language code when we switch +// to virtual addressing mode. movl r2=ia64_mca_proc_state_dump;; // Os state dump area + DATA_VA_TO_PA(r2) // convert to to physical address // save ar.NaT mov r5=ar.unat // ar.unat @@ -250,16 +240,16 @@ cSaveCRs: // if PSR.ic=0, reading interruption registers causes an illegal operation fault mov r3=psr;; tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p6) st8 [r2]=r0,9*8+160 // increment by 168 byte inc. +(p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc. begin_skip_intr_regs: - BRANCH(SkipIntrRegs, r9, p6, 0x0) - ;; +(p6) br SkipIntrRegs;; + add r4=8,r2 // duplicate r2 in r4 add r6=2*8,r2 // duplicate r2 in r6 mov r3=cr16 // cr.ipsr mov r5=cr17 // cr.isr - mov r7=r0;; // cr.ida => cr18 + mov r7=r0;; // cr.ida => cr18 (reserved) st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; @@ -394,8 +384,7 @@ cStRR: br.cloop.sptk.few cStRR ;; end_os_mca_dump: - BRANCH(ia64_os_mca_done_dump, r2, p0, -0x10) - ;; + br ia64_os_mca_done_dump;; //EndStub////////////////////////////////////////////////////////////////////// @@ -484,11 +473,10 @@ restore_CRs: // if PSR.ic=1, reading interruption registers causes an illegal operation fault mov r3=psr;; tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p6) st8 [r2]=r0,9*8+160 // increment by 160 byte inc. +(p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc. begin_rskip_intr_regs: - BRANCH(rSkipIntrRegs, r9, p6, 0x0) - ;; +(p6) br rSkipIntrRegs;; add r4=8,r2 // duplicate r2 in r4 add r6=2*8,r2;; // duplicate r2 in r4 @@ -498,7 +486,7 @@ begin_rskip_intr_regs: ld8 r7=[r6],3*8;; mov cr16=r3 // cr.ipsr mov cr17=r5 // cr.isr is read only -// mov cr18=r7;; // cr.ida +// mov cr18=r7;; // cr.ida (reserved - don't restore) ld8 r3=[r2],3*8 ld8 r5=[r4],3*8 @@ -629,8 +617,8 @@ cStRRr: mov ar.lc=r5 ;; end_os_mca_restore: - BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20) - ;; + br ia64_os_mca_done_restore;; + //EndStub////////////////////////////////////////////////////////////////////// // ok, the issue here is that we need to save state information so @@ -660,12 +648,7 @@ end_os_mca_restore: // 6. GR12 = Return address to location within SAL_INIT procedure - .text - .align 16 -.global ia64_monarch_init_handler -.proc ia64_monarch_init_handler -ia64_monarch_init_handler: - +GLOBAL_ENTRY(ia64_monarch_init_handler) #if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND) // // work around SAL bug that sends all processors to monarch entry @@ -741,13 +724,12 @@ IVirtual_Switch: adds out0=16,sp // out0 = pointer to pt_regs ;; - br.call.sptk.few rp=ia64_init_handler + br.call.sptk.many rp=ia64_init_handler .ret1: return_from_init: br.sptk return_from_init - - .endp +END(ia64_monarch_init_handler) // // SAL to OS entry point for INIT on the slave processor @@ -755,14 +737,6 @@ return_from_init: // as a part of ia64_mca_init. // - .text - .align 16 -.global ia64_slave_init_handler -.proc ia64_slave_init_handler -ia64_slave_init_handler: - - -slave_init_spin_me: - br.sptk slave_init_spin_me - ;; - .endp +GLOBAL_ENTRY(ia64_slave_init_handler) +1: br.sptk 1b +END(ia64_slave_init_handler) diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S index f0f5458ef0c3..aaaa0352b91f 100644 --- a/arch/ia64/kernel/pal.S +++ b/arch/ia64/kernel/pal.S @@ -4,8 +4,9 @@ * * Copyright (C) 1999 Don Dugger * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999-2000 David Mosberger - * Copyright (C) 2000 Stephane Eranian + * Copyright (C) 1999-2001 Hewlett-Packard Co + * David Mosberger + * Stephane Eranian * * 05/22/2000 eranian Added support for stacked register calls * 05/24/2000 eranian Added support for physical mode static calls @@ -31,7 +32,7 @@ GLOBAL_ENTRY(ia64_pal_handler_init) movl r2=pal_entry_point ;; st8 [r2]=in0 - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_pal_handler_init) /* @@ -41,7 +42,7 @@ END(ia64_pal_handler_init) */ GLOBAL_ENTRY(ia64_pal_default_handler) mov r8=-1 - br.cond.sptk.few rp + br.cond.sptk.many rp END(ia64_pal_default_handler) /* @@ -79,13 +80,13 @@ GLOBAL_ENTRY(ia64_pal_call_static) ;; (p6) srlz.i mov rp = r8 - br.cond.sptk.few b7 + br.cond.sptk.many b7 1: mov psr.l = loc3 mov ar.pfs = loc1 mov rp = loc0 ;; srlz.d // seralize restoration of psr.l - br.ret.sptk.few b0 + br.ret.sptk.many b0 END(ia64_pal_call_static) /* @@ -120,7 +121,7 @@ GLOBAL_ENTRY(ia64_pal_call_stacked) mov rp = loc0 ;; srlz.d // serialize restoration of psr.l - br.ret.sptk.few b0 + br.ret.sptk.many b0 END(ia64_pal_call_stacked) /* @@ -173,13 +174,13 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) or loc3=loc3,r17 // add in psr the bits to set ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.few rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode .ret1: mov rp = r8 // install return address (physical) - br.cond.sptk.few b7 + br.cond.sptk.many b7 1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode // return to virtual mode .ret2: mov psr.l = loc3 // restore init PSR @@ -188,7 +189,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) ;; mov ar.rsc=loc4 // restore RSE configuration srlz.d // seralize restoration of psr.l - br.ret.sptk.few b0 + br.ret.sptk.many b0 END(ia64_pal_call_phys_static) /* @@ -227,13 +228,13 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) mov b7 = loc2 // install target to branch reg ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.few rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode .ret6: br.call.sptk.many rp=b7 // now make the call .ret7: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode // return to virtual mode .ret8: mov psr.l = loc3 // restore init PSR mov ar.pfs = loc1 @@ -241,6 +242,6 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) ;; mov ar.rsc=loc4 // restore RSE configuration srlz.d // seralize restoration of psr.l - br.ret.sptk.few b0 + br.ret.sptk.many b0 END(ia64_pal_call_phys_stacked) diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c index 3185ab8a8bce..cd877205455b 100644 --- a/arch/ia64/kernel/palinfo.c +++ b/arch/ia64/kernel/palinfo.c @@ -6,12 +6,13 @@ * Intel IA-64 Architecture Software Developer's Manual v1.0. * * - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 Stephane Eranian + * Copyright (C) 2000-2001 Hewlett-Packard Co + * Stephane Eranian * * 05/26/2000 S.Eranian initial release * 08/21/2000 S.Eranian updated to July 2000 PAL specs * 02/05/2001 S.Eranian fixed module support + * 10/23/2001 S.Eranian updated pal_perf_mon_info bug fixes */ #include #include @@ -32,8 +33,9 @@ MODULE_AUTHOR("Stephane Eranian "); MODULE_DESCRIPTION("/proc interface to IA-64 PAL"); +MODULE_LICENSE("GPL"); -#define PALINFO_VERSION "0.4" +#define PALINFO_VERSION "0.5" #ifdef CONFIG_SMP #define cpu_is_online(i) (cpu_online_map & (1UL << i)) @@ -606,15 +608,6 @@ perfmon_info(char *page) if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0; -#ifdef IA64_PAL_PERF_MON_INFO_BUG - /* - * This bug has been fixed in PAL 2.2.9 and higher - */ - pm_buffer[5]=0x3; - pm_info.pal_perf_mon_info_s.cycles = 0x12; - pm_info.pal_perf_mon_info_s.retired = 0x08; -#endif - p += sprintf(p, "PMC/PMD pairs : %d\n" \ "Counter width : %d bits\n" \ "Cycle event number : %d\n" \ @@ -637,6 +630,14 @@ perfmon_info(char *page) p += sprintf(p, "\nRetired bundles count capable : "); +#ifdef CONFIG_ITANIUM + /* + * PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES + * which is wrong, both PMC4 and PMD5 support it. + */ + if (pm_buffer[12] == 0x10) pm_buffer[12]=0x30; +#endif + p = bitregister_process(p, pm_buffer+12, 256); p += sprintf(p, "\n"); diff --git a/arch/ia64/kernel/pci.c b/arch/ia64/kernel/pci.c index 091086975fa8..1448db834883 100644 --- a/arch/ia64/kernel/pci.c +++ b/arch/ia64/kernel/pci.c @@ -38,6 +38,10 @@ #define DBG(x...) #endif +#ifdef CONFIG_IA64_MCA +extern void ia64_mca_check_errors( void ); +#endif + /* * This interrupt-safe spinlock protects all accesses to PCI * configuration space. @@ -122,6 +126,10 @@ pcibios_init (void) # define PCI_BUSES_TO_SCAN 255 int i; +#ifdef CONFIG_IA64_MCA + ia64_mca_check_errors(); /* For post-failure MCA error logging */ +#endif + platform_pci_fixup(0); /* phase 0 initialization (before PCI bus has been scanned) */ printk("PCI: Probing PCI hardware\n"); @@ -195,3 +203,39 @@ pcibios_setup (char *str) { return NULL; } + +int +pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + /* + * I/O space cannot be accessed via normal processor loads and stores on this + * platform. + */ + if (mmap_state == pci_mmap_io) + /* + * XXX we could relax this for I/O spaces for which ACPI indicates that + * the space is 1-to-1 mapped. But at the moment, we don't support + * multiple PCI address spaces and the legacy I/O space is not 1-to-1 + * mapped, so this is moot. + */ + return -EINVAL; + + /* + * Leave vm_pgoff as-is, the PCI space address is the physical address on this + * platform. + */ + vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO); + + if (write_combine) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 488f63591daf..272d4a16416d 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -38,7 +38,7 @@ #ifdef CONFIG_PERFMON -#define PFM_VERSION "0.2" +#define PFM_VERSION "0.3" #define PFM_SMPL_HDR_VERSION 1 #define PMU_FIRST_COUNTER 4 /* first generic counter */ @@ -52,6 +52,7 @@ #define PFM_DISABLE 0xa6 /* freeze only */ #define PFM_RESTART 0xcf #define PFM_CREATE_CONTEXT 0xa7 +#define PFM_DESTROY_CONTEXT 0xa8 /* * Those 2 are just meant for debugging. I considered using sysctl() for * that but it is a little bit too pervasive. This solution is at least @@ -60,6 +61,8 @@ #define PFM_DEBUG_ON 0xe0 #define PFM_DEBUG_OFF 0xe1 +#define PFM_DEBUG_BASE PFM_DEBUG_ON + /* * perfmon API flags @@ -68,7 +71,8 @@ #define PFM_FL_INHERIT_ONCE 0x01 /* clone pfm_context only once across fork() */ #define PFM_FL_INHERIT_ALL 0x02 /* always clone pfm_context across fork() */ #define PFM_FL_SMPL_OVFL_NOBLOCK 0x04 /* do not block on sampling buffer overflow */ -#define PFM_FL_SYSTEMWIDE 0x08 /* create a systemwide context */ +#define PFM_FL_SYSTEM_WIDE 0x08 /* create a system wide context */ +#define PFM_FL_EXCL_INTR 0x10 /* exclude interrupt from system wide monitoring */ /* * PMC API flags @@ -87,7 +91,7 @@ #endif #define PMC_IS_IMPL(i) (i < pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1)))) -#define PMD_IS_IMPL(i) (i < pmu_conf.num_pmds && pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) +#define PMD_IS_IMPL(i) (i < pmu_conf.num_pmds && pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) #define PMD_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) #define PMC_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) @@ -197,7 +201,8 @@ typedef struct { unsigned int noblock:1; /* block/don't block on overflow with notification */ unsigned int system:1; /* do system wide monitoring */ unsigned int frozen:1; /* pmu must be kept frozen on ctxsw in */ - unsigned int reserved:27; + unsigned int exclintr:1;/* exlcude interrupts from system wide monitoring */ + unsigned int reserved:26; } pfm_context_flags_t; typedef struct pfm_context { @@ -207,26 +212,33 @@ typedef struct pfm_context { unsigned long ctx_iear_counter; /* which PMD holds I-EAR */ unsigned long ctx_btb_counter; /* which PMD holds BTB */ - pid_t ctx_notify_pid; /* who to notify on overflow */ - int ctx_notify_sig; /* XXX: SIGPROF or other */ - pfm_context_flags_t ctx_flags; /* block/noblock */ - pid_t ctx_creator; /* pid of creator (debug) */ - unsigned long ctx_ovfl_regs; /* which registers just overflowed (notification) */ - unsigned long ctx_smpl_regs; /* which registers to record on overflow */ + spinlock_t ctx_notify_lock; + pfm_context_flags_t ctx_flags; /* block/noblock */ + int ctx_notify_sig; /* XXX: SIGPROF or other */ + struct task_struct *ctx_notify_task; /* who to notify on overflow */ + struct task_struct *ctx_creator; /* pid of creator (debug) */ + + unsigned long ctx_ovfl_regs; /* which registers just overflowed (notification) */ + unsigned long ctx_smpl_regs; /* which registers to record on overflow */ - struct semaphore ctx_restart_sem; /* use for blocking notification mode */ + struct semaphore ctx_restart_sem; /* use for blocking notification mode */ + + unsigned long ctx_used_pmds[4]; /* bitmask of used PMD (speedup ctxsw) */ + unsigned long ctx_used_pmcs[4]; /* bitmask of used PMC (speedup ctxsw) */ pfm_counter_t ctx_pmds[IA64_NUM_PMD_COUNTERS]; /* XXX: size should be dynamic */ + } pfm_context_t; +#define CTX_USED_PMD(ctx,n) (ctx)->ctx_used_pmds[(n)>>6] |= 1<< ((n) % 64) +#define CTX_USED_PMC(ctx,n) (ctx)->ctx_used_pmcs[(n)>>6] |= 1<< ((n) % 64) + #define ctx_fl_inherit ctx_flags.inherit #define ctx_fl_noblock ctx_flags.noblock #define ctx_fl_system ctx_flags.system #define ctx_fl_frozen ctx_flags.frozen +#define ctx_fl_exclintr ctx_flags.exclintr -#define CTX_IS_DEAR(c,n) ((c)->ctx_dear_counter == (n)) -#define CTX_IS_IEAR(c,n) ((c)->ctx_iear_counter == (n)) -#define CTX_IS_BTB(c,n) ((c)->ctx_btb_counter == (n)) #define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_noblock == 1) #define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) #define CTX_HAS_SMPL(c) ((c)->ctx_smpl_buf != NULL) @@ -234,17 +246,15 @@ typedef struct pfm_context { static pmu_config_t pmu_conf; /* for debug only */ -static unsigned long pfm_debug=0; /* 0= nodebug, >0= debug output on */ +static int pfm_debug=0; /* 0= nodebug, >0= debug output on */ + #define DBprintk(a) \ do { \ - if (pfm_debug >0) { printk(__FUNCTION__" "); printk a; } \ + if (pfm_debug >0) { printk(__FUNCTION__" %d: ", __LINE__); printk a; } \ } while (0); -static void perfmon_softint(unsigned long ignored); static void ia64_reset_pmu(void); -DECLARE_TASKLET(pfm_tasklet, perfmon_softint, 0); - /* * structure used to pass information between the interrupt handler * and the tasklet. @@ -256,25 +266,41 @@ typedef struct { unsigned long bitvect; /* which counters have overflowed */ } notification_info_t; -#define notification_is_invalid(i) (i->to_pid < 2) -/* will need to be cache line padded */ -static notification_info_t notify_info[NR_CPUS]; +typedef struct { + unsigned long pfs_proc_sessions; + unsigned long pfs_sys_session; /* can only be 0/1 */ + unsigned long pfs_dfl_dcr; /* XXX: hack */ + unsigned int pfs_pp; +} pfm_session_t; -/* - * We force cache line alignment to avoid false sharing - * given that we have one entry per CPU. - */ -static struct { +struct { struct task_struct *owner; } ____cacheline_aligned pmu_owners[NR_CPUS]; -/* helper macros */ + + +/* + * helper macros + */ #define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0); #define PMU_OWNER() pmu_owners[smp_processor_id()].owner +#ifdef CONFIG_SMP +#define PFM_CAN_DO_LAZY() (smp_num_cpus==1 && pfs_info.pfs_sys_session==0) +#else +#define PFM_CAN_DO_LAZY() (pfs_info.pfs_sys_session==0) +#endif + +static void pfm_lazy_save_regs (struct task_struct *ta); + /* for debug only */ static struct proc_dir_entry *perfmon_dir; +/* + * XXX: hack to indicate that a system wide monitoring session is active + */ +static pfm_session_t pfs_info; + /* * finds the number of PM(C|D) registers given * the bitvector returned by PAL @@ -339,8 +365,7 @@ uvirt_to_kva(pgd_t *pgd, unsigned long adr) static inline unsigned long kvirt_to_pa(unsigned long adr) { - __u64 pa; - __asm__ __volatile__ ("tpa %0 = %1" : "=r"(pa) : "r"(adr) : "memory"); + __u64 pa = ia64_tpa(adr); DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa)); return pa; } @@ -568,25 +593,44 @@ no_buffer_desc: static int pfx_is_sane(pfreq_context_t *pfx) { + int ctx_flags; + /* valid signal */ - if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return 0; + //if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return -EINVAL; + if (pfx->notify_sig !=0 && pfx->notify_sig != SIGPROF) return -EINVAL; /* cannot send to process 1, 0 means do not notify */ - if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return 0; + if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return -EINVAL; + + ctx_flags = pfx->flags; + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) { + printk("perfmon: system wide monitoring on SMP not yet supported\n"); + return -EINVAL; + } +#endif + if ((ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) == 0) { + printk("perfmon: system wide monitoring cannot use blocking notification mode\n"); + return -EINVAL; + } + } /* probably more to add here */ - return 1; + return 0; } static int -pfm_context_create(struct task_struct *task, int flags, perfmon_req_t *req) +pfm_context_create(int flags, perfmon_req_t *req) { pfm_context_t *ctx; + struct task_struct *task = NULL; perfmon_req_t tmp; void *uaddr = NULL; - int ret = -EFAULT; + int ret; int ctx_flags; + pid_t pid; /* to go away */ if (flags) { @@ -595,48 +639,156 @@ pfm_context_create(struct task_struct *task, int flags, perfmon_req_t *req) if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + ret = pfx_is_sane(&tmp.pfr_ctx); + if (ret < 0) return ret; + ctx_flags = tmp.pfr_ctx.flags; - /* not yet supported */ - if (ctx_flags & PFM_FL_SYSTEMWIDE) return -EINVAL; + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { + /* + * XXX: This is not AT ALL SMP safe + */ + if (pfs_info.pfs_proc_sessions > 0) return -EBUSY; + if (pfs_info.pfs_sys_session > 0) return -EBUSY; + + pfs_info.pfs_sys_session = 1; - if (!pfx_is_sane(&tmp.pfr_ctx)) return -EINVAL; + } else if (pfs_info.pfs_sys_session >0) { + /* no per-process monitoring while there is a system wide session */ + return -EBUSY; + } else + pfs_info.pfs_proc_sessions++; ctx = pfm_context_alloc(); - if (!ctx) return -ENOMEM; + if (!ctx) goto error; + + /* record the creator (debug only) */ + ctx->ctx_creator = current; + + pid = tmp.pfr_ctx.notify_pid; + + spin_lock_init(&ctx->ctx_notify_lock); + + if (pid == current->pid) { + ctx->ctx_notify_task = task = current; + current->thread.pfm_context = ctx; + + atomic_set(¤t->thread.pfm_notifiers_check, 1); + + } else if (pid!=0) { + read_lock(&tasklist_lock); + + task = find_task_by_pid(pid); + if (task) { + /* + * record who to notify + */ + ctx->ctx_notify_task = task; + + /* + * make visible + * must be done inside critical section + * + * if the initialization does not go through it is still + * okay because child will do the scan for nothing which + * won't hurt. + */ + current->thread.pfm_context = ctx; + + /* + * will cause task to check on exit for monitored + * processes that would notify it. see release_thread() + * Note: the scan MUST be done in release thread, once the + * task has been detached from the tasklist otherwise you are + * exposed to race conditions. + */ + atomic_add(1, &task->thread.pfm_notifiers_check); + } + read_unlock(&tasklist_lock); + } - /* record who the creator is (for debug) */ - ctx->ctx_creator = task->pid; + /* + * notification process does not exist + */ + if (pid != 0 && task == NULL) { + ret = -EINVAL; + goto buffer_error; + } - ctx->ctx_notify_pid = tmp.pfr_ctx.notify_pid; ctx->ctx_notify_sig = SIGPROF; /* siginfo imposes a fixed signal */ if (tmp.pfr_ctx.smpl_entries) { DBprintk((" sampling entries=%ld\n",tmp.pfr_ctx.smpl_entries)); - if ((ret=pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, tmp.pfr_ctx.smpl_entries, &uaddr)) ) goto buffer_error; + + ret = pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, + tmp.pfr_ctx.smpl_entries, &uaddr); + if (ret<0) goto buffer_error; + tmp.pfr_ctx.smpl_vaddr = uaddr; } /* initialization of context's flags */ - ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; - ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0; - ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEMWIDE) ? 1: 0; - ctx->ctx_fl_frozen = 0; + ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; + ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; + ctx->ctx_fl_exclintr = (ctx_flags & PFM_FL_EXCL_INTR) ? 1: 0; + ctx->ctx_fl_frozen = 0; + + /* + * Keep track of the pmds we want to sample + * XXX: may be we don't need to save/restore the DEAR/IEAR pmds + * but we do need the BTB for sure. This is because of a hardware + * buffer of 1 only for non-BTB pmds. + */ + ctx->ctx_used_pmds[0] = tmp.pfr_ctx.smpl_regs; + ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */ sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */ - if (copy_to_user(req, &tmp, sizeof(tmp))) goto buffer_error; - DBprintk((" context=%p, pid=%d notify_sig %d notify_pid=%d\n",(void *)ctx, task->pid, ctx->ctx_notify_sig, ctx->ctx_notify_pid)); - DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system)); + if (copy_to_user(req, &tmp, sizeof(tmp))) { + ret = -EFAULT; + goto buffer_error; + } + + DBprintk((" context=%p, pid=%d notify_sig %d notify_task=%p\n",(void *)ctx, current->pid, ctx->ctx_notify_sig, ctx->ctx_notify_task)); + DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, current->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system)); - /* link with task */ - task->thread.pfm_context = ctx; + /* + * when no notification is required, we can make this visible at the last moment + */ + if (pid == 0) current->thread.pfm_context = ctx; + + /* + * by default, we always include interrupts for system wide + * DCR.pp is set by default to zero by kernel in cpu_init() + */ + if (ctx->ctx_fl_system) { + if (ctx->ctx_fl_exclintr == 0) { + unsigned long dcr = ia64_get_dcr(); + + ia64_set_dcr(dcr|IA64_DCR_PP); + /* + * keep track of the kernel default value + */ + pfs_info.pfs_dfl_dcr = dcr; + + DBprintk((" dcr.pp is set\n")); + } + } return 0; buffer_error: - vfree(ctx); - + pfm_context_free(ctx); +error: + /* + * undo session reservation + */ + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { + pfs_info.pfs_sys_session = 0; + } else { + pfs_info.pfs_proc_sessions--; + } return ret; } @@ -656,8 +808,20 @@ pfm_reset_regs(pfm_context_t *ctx) /* upper part is ignored on rval */ ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); + + /* + * we must reset BTB index (clears pmd16.full to make + * sure we do not report the same branches twice. + * The non-blocking case in handled in update_counters() + */ + if (cnum == ctx->ctx_btb_counter) { + DBprintk(("reseting PMD16\n")); + ia64_set_pmd(16, 0); + } } } + /* just in case ! */ + ctx->ctx_ovfl_regs = 0; } static int @@ -695,20 +859,23 @@ pfm_write_pmcs(struct task_struct *ta, perfmon_req_t *req, int count) } else if (PMC_IS_BTB(&tmp.pfr_reg.reg_value)) { ctx->ctx_btb_counter = cnum; } - +#if 0 if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY) ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY; +#endif } - + /* keep track of what we use */ + CTX_USED_PMC(ctx, cnum); ia64_set_pmc(cnum, tmp.pfr_reg.reg_value); - DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags)); + + DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x used_pmcs=0%lx\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags, ctx->ctx_used_pmcs[0])); } /* * we have to set this here event hough we haven't necessarily started monitoring * because we may be context switched out */ - th->flags |= IA64_THREAD_PM_VALID; + if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; return 0; } @@ -741,25 +908,32 @@ pfm_write_pmds(struct task_struct *ta, perfmon_req_t *req, int count) ctx->ctx_pmds[k].val = tmp.pfr_reg.reg_value & ~pmu_conf.perf_ovfl_val; ctx->ctx_pmds[k].smpl_rval = tmp.pfr_reg.reg_smpl_reset; ctx->ctx_pmds[k].ovfl_rval = tmp.pfr_reg.reg_ovfl_reset; + + if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY) + ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY; } + /* keep track of what we use */ + CTX_USED_PMD(ctx, cnum); /* writes to unimplemented part is ignored, so this is safe */ ia64_set_pmd(cnum, tmp.pfr_reg.reg_value); /* to go away */ ia64_srlz_d(); - DBprintk((" setting PMD[%ld]: pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx\n", + DBprintk((" setting PMD[%ld]: ovfl_notify=%d pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx used_pmds=0%lx\n", cnum, + PMD_OVFL_NOTIFY(ctx, cnum - PMU_FIRST_COUNTER), ctx->ctx_pmds[k].val, ctx->ctx_pmds[k].ovfl_rval, ctx->ctx_pmds[k].smpl_rval, - ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val)); + ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val, + ctx->ctx_used_pmds[0])); } /* * we have to set this here event hough we haven't necessarily started monitoring * because we may be context switched out */ - th->flags |= IA64_THREAD_PM_VALID; + if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; return 0; } @@ -783,6 +957,8 @@ pfm_read_pmds(struct task_struct *ta, perfmon_req_t *req, int count) /* XXX: ctx locking may be required here */ for (i = 0; i < count; i++, req++) { + unsigned long reg_val = ~0, ctx_val = ~0; + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL; @@ -791,23 +967,25 @@ pfm_read_pmds(struct task_struct *ta, perfmon_req_t *req, int count) if (ta == current){ val = ia64_get_pmd(tmp.pfr_reg.reg_num); } else { - val = th->pmd[tmp.pfr_reg.reg_num]; + val = reg_val = th->pmd[tmp.pfr_reg.reg_num]; } val &= pmu_conf.perf_ovfl_val; /* * lower part of .val may not be zero, so we must be an addition because of * residual count (see update_counters). */ - val += ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val; + val += ctx_val = ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val; } else { /* for now */ if (ta != current) return -EINVAL; + ia64_srlz_d(); val = ia64_get_pmd(tmp.pfr_reg.reg_num); } tmp.pfr_reg.reg_value = val; - DBprintk((" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg.reg_num, val)); + DBprintk((" reading PMD[%ld]=0x%lx reg=0x%lx ctx_val=0x%lx pmc=0x%lx\n", + tmp.pfr_reg.reg_num, val, reg_val, ctx_val, ia64_get_pmc(tmp.pfr_reg.reg_num))); if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; } @@ -822,7 +1000,7 @@ pfm_do_restart(struct task_struct *task) void *sem = &ctx->ctx_restart_sem; if (task == current) { - DBprintk((" restartig self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); + DBprintk((" restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); pfm_reset_regs(ctx); @@ -871,6 +1049,23 @@ pfm_do_restart(struct task_struct *task) return 0; } +/* + * system-wide mode: propagate activation/desactivation throughout the tasklist + * + * XXX: does not work for SMP, of course + */ +static void +pfm_process_tasklist(int cmd) +{ + struct task_struct *p; + struct pt_regs *regs; + + for_each_task(p) { + regs = (struct pt_regs *)((unsigned long)p + IA64_STK_OFFSET); + regs--; + ia64_psr(regs)->pp = cmd; + } +} static int do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs) @@ -881,19 +1076,26 @@ do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, memset(&tmp, 0, sizeof(tmp)); + if (ctx == NULL && cmd != PFM_CREATE_CONTEXT && cmd < PFM_DEBUG_BASE) { + DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid)); + return -EINVAL; + } + switch (cmd) { case PFM_CREATE_CONTEXT: /* a context has already been defined */ if (ctx) return -EBUSY; - /* may be a temporary limitation */ + /* + * cannot directly create a context in another process + */ if (task != current) return -EINVAL; if (req == NULL || count != 1) return -EINVAL; if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - return pfm_context_create(task, flags, req); + return pfm_context_create(flags, req); case PFM_WRITE_PMCS: /* we don't quite support this right now */ @@ -901,10 +1103,6 @@ do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - if (!ctx) { - DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid)); - return -EINVAL; - } return pfm_write_pmcs(task, req, count); case PFM_WRITE_PMDS: @@ -913,45 +1111,41 @@ do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - if (!ctx) { - DBprintk((" PFM_WRITE_PMDS: no context for task %d\n", task->pid)); - return -EINVAL; - } return pfm_write_pmds(task, req, count); case PFM_START: /* we don't quite support this right now */ if (task != current) return -EINVAL; - if (!ctx) { - DBprintk((" PFM_START: no context for task %d\n", task->pid)); - return -EINVAL; - } + if (PMU_OWNER() && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER()); SET_PMU_OWNER(current); /* will start monitoring right after rfi */ ia64_psr(regs)->up = 1; + ia64_psr(regs)->pp = 1; + + if (ctx->ctx_fl_system) { + pfm_process_tasklist(1); + pfs_info.pfs_pp = 1; + } /* * mark the state as valid. * this will trigger save/restore at context switch */ - th->flags |= IA64_THREAD_PM_VALID; + if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; ia64_set_pmc(0, 0); ia64_srlz_d(); - break; + break; case PFM_ENABLE: /* we don't quite support this right now */ if (task != current) return -EINVAL; - if (!ctx) { - DBprintk((" PFM_ENABLE: no context for task %d\n", task->pid)); - return -EINVAL; - } + if (PMU_OWNER() && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER()); /* reset all registers to stable quiet state */ ia64_reset_pmu(); @@ -969,7 +1163,7 @@ do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, * mark the state as valid. * this will trigger save/restore at context switch */ - th->flags |= IA64_THREAD_PM_VALID; + if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; /* simply unfreeze */ ia64_set_pmc(0, 0); @@ -983,54 +1177,41 @@ do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, /* simply freeze */ ia64_set_pmc(0, 1); ia64_srlz_d(); + /* + * XXX: cannot really toggle IA64_THREAD_PM_VALID + * but context is still considered valid, so any + * read request would return something valid. Same + * thing when this task terminates (pfm_flush_regs()). + */ break; case PFM_READ_PMDS: if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - if (!ctx) { - DBprintk((" PFM_READ_PMDS: no context for task %d\n", task->pid)); - return -EINVAL; - } return pfm_read_pmds(task, req, count); case PFM_STOP: /* we don't quite support this right now */ if (task != current) return -EINVAL; - ia64_set_pmc(0, 1); - ia64_srlz_d(); - + /* simply stop monitors, not PMU */ ia64_psr(regs)->up = 0; + ia64_psr(regs)->pp = 0; - th->flags &= ~IA64_THREAD_PM_VALID; - - SET_PMU_OWNER(NULL); - - /* we probably will need some more cleanup here */ - break; - - case PFM_DEBUG_ON: - printk(" debugging on\n"); - pfm_debug = 1; - break; + if (ctx->ctx_fl_system) { + pfm_process_tasklist(0); + pfs_info.pfs_pp = 0; + } - case PFM_DEBUG_OFF: - printk(" debugging off\n"); - pfm_debug = 0; break; case PFM_RESTART: /* temporary, will most likely end up as a PFM_ENABLE */ - if ((th->flags & IA64_THREAD_PM_VALID) == 0) { + if ((th->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system==0) { printk(" PFM_RESTART not monitoring\n"); return -EINVAL; } - if (!ctx) { - printk(" PFM_RESTART no ctx for %d\n", task->pid); - return -EINVAL; - } if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_fl_frozen==0) { printk("task %d without pmu_frozen set\n", task->pid); return -EINVAL; @@ -1038,6 +1219,37 @@ do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, return pfm_do_restart(task); /* we only look at first entry */ + case PFM_DESTROY_CONTEXT: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + /* first stop monitors */ + ia64_psr(regs)->up = 0; + ia64_psr(regs)->pp = 0; + + /* then freeze PMU */ + ia64_set_pmc(0, 1); + ia64_srlz_d(); + + /* don't save/restore on context switch */ + if (ctx->ctx_fl_system ==0) task->thread.flags &= ~IA64_THREAD_PM_VALID; + + SET_PMU_OWNER(NULL); + + /* now free context and related state */ + pfm_context_exit(task); + break; + + case PFM_DEBUG_ON: + printk("perfmon debugging on\n"); + pfm_debug = 1; + break; + + case PFM_DEBUG_OFF: + printk("perfmon debugging off\n"); + pfm_debug = 0; + break; + default: DBprintk((" UNknown command 0x%x\n", cmd)); return -EINVAL; @@ -1074,11 +1286,8 @@ sys_perfmonctl (int pid, int cmd, int flags, perfmon_req_t *req, int count, long /* XXX: pid interface is going away in favor of pfm context */ if (pid != current->pid) { read_lock(&tasklist_lock); - { - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - } + + child = find_task_by_pid(pid); if (!child) goto abort_call; @@ -1101,93 +1310,44 @@ abort_call: return ret; } - -/* - * This function is invoked on the exit path of the kernel. Therefore it must make sure - * it does does modify the caller's input registers (in0-in7) in case of entry by system call - * which can be restarted. That's why it's declared as a system call and all 8 possible args - * are declared even though not used. - */ #if __GNUC__ >= 3 void asmlinkage -pfm_overflow_notify(void) +pfm_block_on_overflow(void) #else void asmlinkage -pfm_overflow_notify(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) +pfm_block_on_overflow(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) #endif { - struct task_struct *task; struct thread_struct *th = ¤t->thread; pfm_context_t *ctx = current->thread.pfm_context; - struct siginfo si; int ret; - /* - * do some sanity checks first - */ - if (!ctx) { - printk("perfmon: process %d has no PFM context\n", current->pid); - return; - } - if (ctx->ctx_notify_pid < 2) { - printk("perfmon: process %d invalid notify_pid=%d\n", current->pid, ctx->ctx_notify_pid); - return; - } - - DBprintk((" current=%d ctx=%p bv=0%lx\n", current->pid, (void *)ctx, ctx->ctx_ovfl_regs)); /* * NO matter what notify_pid is, * we clear overflow, won't notify again */ - th->pfm_pend_notify = 0; + th->pfm_must_block = 0; /* - * When measuring in kernel mode and non-blocking fashion, it is possible to - * get an overflow while executing this code. Therefore the state of pend_notify - * and ovfl_regs can be altered. The important point is not to loose any notification. - * It is fine to get called for nothing. To make sure we do collect as much state as - * possible, update_counters() always uses |= to add bit to the ovfl_regs field. - * - * In certain cases, it is possible to come here, with ovfl_regs == 0; - * - * XXX: pend_notify and ovfl_regs could be merged maybe ! + * do some sanity checks first */ - if (ctx->ctx_ovfl_regs == 0) { - printk("perfmon: spurious overflow notification from pid %d\n", current->pid); + if (!ctx) { + printk("perfmon: process %d has no PFM context\n", current->pid); return; } - read_lock(&tasklist_lock); - - task = find_task_by_pid(ctx->ctx_notify_pid); - - if (task) { - si.si_signo = ctx->ctx_notify_sig; - si.si_errno = 0; - si.si_code = PROF_OVFL; /* goes to user */ - si.si_addr = NULL; - si.si_pid = current->pid; /* who is sending */ - si.si_pfm_ovfl = ctx->ctx_ovfl_regs; - - DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task)); - - /* must be done with tasklist_lock locked */ - ret = send_sig_info(ctx->ctx_notify_sig, &si, task); - if (ret != 0) { - DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_pid, ret)); - task = NULL; /* will cause return */ - } - } else { - printk("perfmon: notify_pid %d not found\n", ctx->ctx_notify_pid); + if (ctx->ctx_notify_task == 0) { + printk("perfmon: process %d has no task to notify\n", current->pid); + return; } - read_unlock(&tasklist_lock); + DBprintk((" current=%d task=%d\n", current->pid, ctx->ctx_notify_task->pid)); - /* now that we have released the lock handle error condition */ - if (!task || CTX_OVFL_NOBLOCK(ctx)) { - /* we clear all pending overflow bits in noblock mode */ - ctx->ctx_ovfl_regs = 0; + /* should not happen */ + if (CTX_OVFL_NOBLOCK(ctx)) { + printk("perfmon: process %d non-blocking ctx should not be here\n", current->pid); return; } + DBprintk((" CPU%d %d before sleep\n", smp_processor_id(), current->pid)); /* @@ -1211,9 +1371,6 @@ pfm_overflow_notify(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, pfm_reset_regs(ctx); - /* now we can clear this mask */ - ctx->ctx_ovfl_regs = 0; - /* * Unlock sampling buffer and reset index atomically * XXX: not really needed when blocking @@ -1232,84 +1389,14 @@ pfm_overflow_notify(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, } } -static void -perfmon_softint(unsigned long ignored) -{ - notification_info_t *info; - int my_cpu = smp_processor_id(); - struct task_struct *task; - struct siginfo si; - - info = notify_info+my_cpu; - - DBprintk((" CPU%d current=%d to_pid=%d from_pid=%d bv=0x%lx\n", \ - smp_processor_id(), current->pid, info->to_pid, info->from_pid, info->bitvect)); - - /* assumption check */ - if (info->from_pid == info->to_pid) { - DBprintk((" Tasklet assumption error: from=%d tor=%d\n", info->from_pid, info->to_pid)); - return; - } - - if (notification_is_invalid(info)) { - DBprintk((" invalid notification information\n")); - return; - } - - /* sanity check */ - if (info->to_pid == 1) { - DBprintk((" cannot notify init\n")); - return; - } - /* - * XXX: needs way more checks here to make sure we send to a task we have control over - */ - read_lock(&tasklist_lock); - - task = find_task_by_pid(info->to_pid); - - DBprintk((" after find %p\n", (void *)task)); - - if (task) { - int ret; - - si.si_signo = SIGPROF; - si.si_errno = 0; - si.si_code = PROF_OVFL; /* goes to user */ - si.si_addr = NULL; - si.si_pid = info->from_pid; /* who is sending */ - si.si_pfm_ovfl = info->bitvect; - - DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task)); - - /* must be done with tasklist_lock locked */ - ret = send_sig_info(SIGPROF, &si, task); - if (ret != 0) - DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", info->to_pid, ret)); - - /* invalidate notification */ - info->to_pid = info->from_pid = 0; - info->bitvect = 0; - } - - read_unlock(&tasklist_lock); - - DBprintk((" after unlock %p\n", (void *)task)); - - if (!task) { - printk("perfmon: CPU%d cannot find process %d\n", smp_processor_id(), info->to_pid); - } -} - /* * main overflow processing routine. * it can be called from the interrupt path or explicitely during the context switch code * Return: - * 0 : do not unfreeze the PMU - * 1 : PMU can be unfrozen + * new value of pmc[0]. if 0x0 then unfreeze, else keep frozen */ -static unsigned long -update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) +unsigned long +update_counters (struct task_struct *task, u64 pmc0, struct pt_regs *regs) { unsigned long mask, i, cnum; struct thread_struct *th; @@ -1317,7 +1404,9 @@ update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) unsigned long bv = 0; int my_cpu = smp_processor_id(); int ret = 1, buffer_is_full = 0; - int ovfl_is_smpl, can_notify, need_reset_pmd16=0; + int ovfl_has_long_recovery, can_notify, need_reset_pmd16=0; + struct siginfo si; + /* * It is never safe to access the task for which the overflow interrupt is destinated * using the current variable as the interrupt may occur in the middle of a context switch @@ -1331,23 +1420,23 @@ update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) * valid one, i.e. the one that caused the interrupt. */ - if (ta == NULL) { + if (task == NULL) { DBprintk((" owners[%d]=NULL\n", my_cpu)); return 0x1; } - th = &ta->thread; + th = &task->thread; ctx = th->pfm_context; /* * XXX: debug test * Don't think this could happen given upfront tests */ - if ((th->flags & IA64_THREAD_PM_VALID) == 0) { - printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", ta->pid); + if ((th->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system == 0) { + printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", task->pid); return 0x1; } if (!ctx) { - printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", ta->pid); + printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", task->pid); return 0; } @@ -1355,16 +1444,21 @@ update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) * sanity test. Should never happen */ if ((pmc0 & 0x1 )== 0) { - printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", ta->pid, pmc0); + printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", task->pid, pmc0); return 0x0; } mask = pmc0 >> PMU_FIRST_COUNTER; - DBprintk(("pmc0=0x%lx pid=%d\n", pmc0, ta->pid)); - - DBprintk(("ctx is in %s mode\n", CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK")); + DBprintk(("pmc0=0x%lx pid=%d owner=%d iip=0x%lx, ctx is in %s mode used_pmds=0x%lx used_pmcs=0x%lx\n", + pmc0, task->pid, PMU_OWNER()->pid, regs->cr_iip, + CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK", + ctx->ctx_used_pmds[0], + ctx->ctx_used_pmcs[0])); + /* + * XXX: need to record sample only when an EAR/BTB has overflowed + */ if (CTX_HAS_SMPL(ctx)) { pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; unsigned long *e, m, idx=0; @@ -1372,11 +1466,15 @@ update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) int j; idx = ia64_fetch_and_add(1, &psb->psb_index); - DBprintk((" trying to record index=%ld entries=%ld\n", idx, psb->psb_entries)); + DBprintk((" recording index=%ld entries=%ld\n", idx, psb->psb_entries)); /* * XXX: there is a small chance that we could run out on index before resetting * but index is unsigned long, so it will take some time..... + * We use > instead of == because fetch_and_add() is off by one (see below) + * + * This case can happen in non-blocking mode or with multiple processes. + * For non-blocking, we need to reload and continue. */ if (idx > psb->psb_entries) { buffer_is_full = 1; @@ -1388,7 +1486,7 @@ update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size)); - h->pid = ta->pid; + h->pid = task->pid; h->cpu = my_cpu; h->rate = 0; h->ip = regs ? regs->cr_iip : 0x0; /* where did the fault happened */ @@ -1398,6 +1496,7 @@ update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) h->stamp = perfmon_get_stamp(); e = (unsigned long *)(h+1); + /* * selectively store PMDs in increasing index number */ @@ -1406,35 +1505,66 @@ update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) if (PMD_IS_COUNTER(j)) *e = ctx->ctx_pmds[j-PMU_FIRST_COUNTER].val + (ia64_get_pmd(j) & pmu_conf.perf_ovfl_val); - else + else { *e = ia64_get_pmd(j); /* slow */ + } DBprintk((" e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); e++; } } - /* make the new entry visible to user, needs to be atomic */ + /* + * make the new entry visible to user, needs to be atomic + */ ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count); DBprintk((" index=%ld entries=%ld hdr_count=%ld\n", idx, psb->psb_entries, psb->psb_hdr->hdr_count)); - - /* sampling buffer full ? */ + /* + * sampling buffer full ? + */ if (idx == (psb->psb_entries-1)) { - bv = mask; + /* + * will cause notification, cannot be 0 + */ + bv = mask << PMU_FIRST_COUNTER; + buffer_is_full = 1; DBprintk((" sampling buffer full must notify bv=0x%lx\n", bv)); - if (!CTX_OVFL_NOBLOCK(ctx)) goto buffer_full; + /* + * we do not reload here, when context is blocking + */ + if (!CTX_OVFL_NOBLOCK(ctx)) goto no_reload; + /* * here, we have a full buffer but we are in non-blocking mode - * so we need to reloads overflowed PMDs with sampling reset values - * and restart + * so we need to reload overflowed PMDs with sampling reset values + * and restart right away. */ } + /* FALL THROUGH */ } reload_pmds: - ovfl_is_smpl = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full; - can_notify = CTX_HAS_SMPL(ctx) == 0 && ctx->ctx_notify_pid; + + /* + * in the case of a non-blocking context, we reload + * with the ovfl_rval when no user notification is taking place (short recovery) + * otherwise when the buffer is full which requires user interaction) then we use + * smpl_rval which is the long_recovery path (disturbance introduce by user execution). + * + * XXX: implies that when buffer is full then there is always notification. + */ + ovfl_has_long_recovery = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full; + + /* + * XXX: CTX_HAS_SMPL() should really be something like CTX_HAS_SMPL() and is activated,i.e., + * one of the PMC is configured for EAR/BTB. + * + * When sampling, we can only notify when the sampling buffer is full. + */ + can_notify = CTX_HAS_SMPL(ctx) == 0 && ctx->ctx_notify_task; + + DBprintk((" ovfl_has_long_recovery=%d can_notify=%d\n", ovfl_has_long_recovery, can_notify)); for (i = 0, cnum = PMU_FIRST_COUNTER; mask ; cnum++, i++, mask >>= 1) { @@ -1456,7 +1586,7 @@ reload_pmds: DBprintk((" pmod[%ld].val=0x%lx pmd=0x%lx\n", i, ctx->ctx_pmds[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); if (can_notify && PMD_OVFL_NOTIFY(ctx, i)) { - DBprintk((" CPU%d should notify process %d with signal %d\n", my_cpu, ctx->ctx_notify_pid, ctx->ctx_notify_sig)); + DBprintk((" CPU%d should notify task %p with signal %d\n", my_cpu, ctx->ctx_notify_task, ctx->ctx_notify_sig)); bv |= 1 << i; } else { DBprintk((" CPU%d PMD[%ld] overflow, no notification\n", my_cpu, cnum)); @@ -1467,93 +1597,150 @@ reload_pmds: */ /* writes to upper part are ignored, so this is safe */ - if (ovfl_is_smpl) { - DBprintk((" CPU%d PMD[%ld] reloaded with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); + if (ovfl_has_long_recovery) { + DBprintk((" CPU%d PMD[%ld] reload with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); } else { - DBprintk((" CPU%d PMD[%ld] reloaded with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); + DBprintk((" CPU%d PMD[%ld] reload with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); ia64_set_pmd(cnum, ctx->ctx_pmds[i].ovfl_rval); } } if (cnum == ctx->ctx_btb_counter) need_reset_pmd16=1; } /* - * In case of BTB, overflow - * we need to reset the BTB index. + * In case of BTB overflow we need to reset the BTB index. */ if (need_reset_pmd16) { DBprintk(("reset PMD16\n")); ia64_set_pmd(16, 0); } -buffer_full: - /* see pfm_overflow_notify() on details for why we use |= here */ - ctx->ctx_ovfl_regs |= bv; - /* nobody to notify, return and unfreeze */ +no_reload: + + /* + * some counters overflowed, but they did not require + * user notification, so after having reloaded them above + * we simply restart + */ if (!bv) return 0x0; + ctx->ctx_ovfl_regs = bv; /* keep track of what to reset when unblocking */ + /* + * Now we know that: + * - we have some counters which overflowed (contains in bv) + * - someone has asked to be notified on overflow. + */ + + + /* + * If the notification task is still present, then notify_task is non + * null. It is clean by that task if it ever exits before we do. + */ - if (ctx->ctx_notify_pid == ta->pid) { - struct siginfo si; + if (ctx->ctx_notify_task) { si.si_errno = 0; si.si_addr = NULL; - si.si_pid = ta->pid; /* who is sending */ - + si.si_pid = task->pid; /* who is sending */ si.si_signo = ctx->ctx_notify_sig; /* is SIGPROF */ si.si_code = PROF_OVFL; /* goes to user */ si.si_pfm_ovfl = bv; + /* - * in this case, we don't stop the task, we let it go on. It will - * necessarily go to the signal handler (if any) when it goes back to - * user mode. + * when the target of the signal is not ourself, we have to be more + * careful. The notify_task may being cleared by the target task itself + * in release_thread(). We must ensure mutual exclusion here such that + * the signal is delivered (even to a dying task) safely. */ - DBprintk((" sending %d notification to self %d\n", si.si_signo, ta->pid)); + if (ctx->ctx_notify_task != current) { + /* + * grab the notification lock for this task + */ + spin_lock(&ctx->ctx_notify_lock); - /* this call is safe in an interrupt handler */ - ret = send_sig_info(ctx->ctx_notify_sig, &si, ta); - if (ret != 0) - printk(" send_sig_info(process %d, SIGPROF)=%d\n", ta->pid, ret); - /* - * no matter if we block or not, we keep PMU frozen and do not unfreeze on ctxsw - */ - ctx->ctx_fl_frozen = 1; - - } else { -#if 0 /* - * The tasklet is guaranteed to be scheduled for this CPU only + * now notify_task cannot be modified until we're done + * if NULL, they it got modified while we were in the handler */ - notify_info[my_cpu].to_pid = ctx->notify_pid; - notify_info[my_cpu].from_pid = ta->pid; /* for debug only */ - notify_info[my_cpu].bitvect = bv; - /* tasklet is inserted and active */ - tasklet_schedule(&pfm_tasklet); -#endif + if (ctx->ctx_notify_task == NULL) { + spin_unlock(&ctx->ctx_notify_lock); + goto lost_notify; + } /* - * stored the vector of overflowed registers for use in notification - * mark that a notification/blocking is pending (arm the trap) + * required by send_sig_info() to make sure the target + * task does not disappear on us. */ - th->pfm_pend_notify = 1; + read_lock(&tasklist_lock); + } + /* + * in this case, we don't stop the task, we let it go on. It will + * necessarily go to the signal handler (if any) when it goes back to + * user mode. + */ + DBprintk((" %d sending %d notification to %d\n", task->pid, si.si_signo, ctx->ctx_notify_task->pid)); + + /* + * this call is safe in an interrupt handler, so does read_lock() on tasklist_lock + */ + ret = send_sig_info(ctx->ctx_notify_sig, &si, ctx->ctx_notify_task); + if (ret != 0) printk(" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_task->pid, ret); + /* + * now undo the protections in order + */ + if (ctx->ctx_notify_task != current) { + read_unlock(&tasklist_lock); + spin_unlock(&ctx->ctx_notify_lock); + } + + /* + * if we block set the pfm_must_block bit + * when in block mode, we can effectively block only when the notified + * task is not self, otherwise we would deadlock. + * in this configuration, the notification is sent, the task will not + * block on the way back to user mode, but the PMU will be kept frozen + * until PFM_RESTART. + * Note that here there is still a race condition with notify_task + * possibly being nullified behind our back, but this is fine because + * it can only be changed to NULL which by construction, can only be + * done when notify_task != current. So if it was already different + * before, changing it to NULL will still maintain this invariant. + * Of course, when it is equal to current it cannot change at this point. + */ + if (!CTX_OVFL_NOBLOCK(ctx) && ctx->ctx_notify_task != current) { + th->pfm_must_block = 1; /* will cause blocking */ + } + } else { +lost_notify: + DBprintk((" notification task has disappeared !\n")); /* - * if we do block, then keep PMU frozen until restart + * for a non-blocking context, we make sure we do not fall into the pfm_overflow_notify() + * trap. Also in the case of a blocking context with lost notify process, then we do not + * want to block either (even though it is interruptible). In this case, the PMU will be kept + * frozen and the process will run to completion without monitoring enabled. + * + * Of course, we cannot loose notify process when self-monitoring. */ - if (!CTX_OVFL_NOBLOCK(ctx)) ctx->ctx_fl_frozen = 1; + th->pfm_must_block = 0; - DBprintk((" process %d notify ovfl_regs=0x%lx\n", ta->pid, bv)); } /* - * keep PMU frozen (and overflowed bits cleared) when we have to stop, - * otherwise return a resume 'value' for PMC[0] - * - * XXX: maybe that's enough to get rid of ctx_fl_frozen ? + * if we block, we keep the PMU frozen. If non-blocking we restart. + * in the case of non-blocking were the notify process is lost, we also + * restart. */ - DBprintk((" will return pmc0=0x%x\n",ctx->ctx_fl_frozen ? 0x1 : 0x0)); + if (!CTX_OVFL_NOBLOCK(ctx)) + ctx->ctx_fl_frozen = 1; + else + ctx->ctx_fl_frozen = 0; + + DBprintk((" reload pmc0=0x%x must_block=%ld\n", + ctx->ctx_fl_frozen ? 0x1 : 0x0, th->pfm_must_block)); + return ctx->ctx_fl_frozen ? 0x1 : 0x0; } @@ -1595,10 +1782,17 @@ perfmon_proc_info(char *page) u64 pmc0 = ia64_get_pmc(0); int i; - p += sprintf(p, "PMC[0]=%lx\nPerfmon debug: %s\n", pmc0, pfm_debug ? "On" : "Off"); + p += sprintf(p, "CPU%d.pmc[0]=%lx\nPerfmon debug: %s\n", smp_processor_id(), pmc0, pfm_debug ? "On" : "Off"); + p += sprintf(p, "proc_sessions=%lu sys_sessions=%lu\n", + pfs_info.pfs_proc_sessions, + pfs_info.pfs_sys_session); + for(i=0; i < NR_CPUS; i++) { - if (cpu_is_online(i)) - p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: 0); + if (cpu_is_online(i)) { + p += sprintf(p, "CPU%d.pmu_owner: %-6d\n", + i, + pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1); + } } return p - page; } @@ -1648,8 +1842,8 @@ perfmon_init (void) } pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; pmu_conf.max_counters = pm_info.pal_perf_mon_info_s.generic; - pmu_conf.num_pmds = find_num_pm_regs(pmu_conf.impl_regs); - pmu_conf.num_pmcs = find_num_pm_regs(&pmu_conf.impl_regs[4]); + pmu_conf.num_pmcs = find_num_pm_regs(pmu_conf.impl_regs); + pmu_conf.num_pmds = find_num_pm_regs(&pmu_conf.impl_regs[4]); printk("perfmon: %d bits counters (max value 0x%lx)\n", pm_info.pal_perf_mon_info_s.width, pmu_conf.perf_ovfl_val); printk("perfmon: %ld PMC/PMD pairs, %ld PMCs, %ld PMDs\n", pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds); @@ -1681,21 +1875,19 @@ perfmon_init_percpu (void) ia64_srlz_d(); } -/* - * XXX: for system wide this function MUST never be called - */ void pfm_save_regs (struct task_struct *ta) { struct task_struct *owner; + pfm_context_t *ctx; struct thread_struct *t; u64 pmc0, psr; + unsigned long mask; int i; - if (ta == NULL) { - panic(__FUNCTION__" task is NULL\n"); - } - t = &ta->thread; + t = &ta->thread; + ctx = ta->thread.pfm_context; + /* * We must make sure that we don't loose any potential overflow * interrupt while saving PMU context. In this code, external @@ -1715,7 +1907,7 @@ pfm_save_regs (struct task_struct *ta) * in kernel. * By now, we could still have an overflow interrupt in-flight. */ - __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + __asm__ __volatile__ ("rsm psr.up|psr.pp;;"::: "memory"); /* * Mark the PMU as not owned @@ -1744,7 +1936,6 @@ pfm_save_regs (struct task_struct *ta) * next process does not start with monitoring on if not requested */ ia64_set_pmc(0, 1); - ia64_srlz_d(); /* * Check for overflow bits and proceed manually if needed @@ -1755,94 +1946,111 @@ pfm_save_regs (struct task_struct *ta) * next time the task exits from the kernel. */ if (pmc0 & ~0x1) { - if (owner != ta) printk(__FUNCTION__" owner=%p task=%p\n", (void *)owner, (void *)ta); - printk(__FUNCTION__" Warning: pmc[0]=0x%lx explicit call\n", pmc0); - - pmc0 = update_counters(owner, pmc0, NULL); + update_counters(owner, pmc0, NULL); /* we will save the updated version of pmc0 */ } - /* * restore PSR for context switch to save */ __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory"); + /* + * we do not save registers if we can do lazy + */ + if (PFM_CAN_DO_LAZY()) { + SET_PMU_OWNER(owner); + return; + } /* * XXX needs further optimization. * Also must take holes into account */ - for (i=0; i< pmu_conf.num_pmds; i++) { - t->pmd[i] = ia64_get_pmd(i); + mask = ctx->ctx_used_pmds[0]; + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); } /* skip PMC[0], we handle it separately */ - for (i=1; i< pmu_conf.num_pmcs; i++) { - t->pmc[i] = ia64_get_pmc(i); + mask = ctx->ctx_used_pmcs[0]>>1; + for (i=1; mask; i++, mask>>=1) { + if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i); } - /* * Throughout this code we could have gotten an overflow interrupt. It is transformed * into a spurious interrupt as soon as we give up pmu ownership. */ } -void -pfm_load_regs (struct task_struct *ta) +static void +pfm_lazy_save_regs (struct task_struct *ta) { - struct thread_struct *t = &ta->thread; - pfm_context_t *ctx = ta->thread.pfm_context; + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long mask; int i; + DBprintk((" on [%d] by [%d]\n", ta->pid, current->pid)); + + t = &ta->thread; + ctx = ta->thread.pfm_context; /* * XXX needs further optimization. * Also must take holes into account */ - for (i=0; i< pmu_conf.num_pmds; i++) { - ia64_set_pmd(i, t->pmd[i]); + mask = ctx->ctx_used_pmds[0]; + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); } - - /* skip PMC[0] to avoid side effects */ - for (i=1; i< pmu_conf.num_pmcs; i++) { - ia64_set_pmc(i, t->pmc[i]); + + /* skip PMC[0], we handle it separately */ + mask = ctx->ctx_used_pmcs[0]>>1; + for (i=1; mask; i++, mask>>=1) { + if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i); } + SET_PMU_OWNER(NULL); +} + +void +pfm_load_regs (struct task_struct *ta) +{ + struct thread_struct *t = &ta->thread; + pfm_context_t *ctx = ta->thread.pfm_context; + struct task_struct *owner; + unsigned long mask; + int i; + + owner = PMU_OWNER(); + if (owner == ta) goto skip_restore; + if (owner) pfm_lazy_save_regs(owner); - /* - * we first restore ownership of the PMU to the 'soon to be current' - * context. This way, if, as soon as we unfreeze the PMU at the end - * of this function, we get an interrupt, we attribute it to the correct - * task - */ SET_PMU_OWNER(ta); -#if 0 - /* - * check if we had pending overflow before context switching out - * If so, we invoke the handler manually, i.e. simulate interrupt. - * - * XXX: given that we do not use the tasklet anymore to stop, we can - * move this back to the pfm_save_regs() routine. - */ - if (t->pmc[0] & ~0x1) { - /* freeze set in pfm_save_regs() */ - DBprintk((" pmc[0]=0x%lx manual interrupt\n",t->pmc[0])); - update_counters(ta, t->pmc[0], NULL); + mask = ctx->ctx_used_pmds[0]; + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) ia64_set_pmd(i, t->pmd[i]); } -#endif + /* skip PMC[0] to avoid side effects */ + mask = ctx->ctx_used_pmcs[0]>>1; + for (i=1; mask; i++, mask>>=1) { + if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]); + } +skip_restore: /* * unfreeze only when possible */ if (ctx->ctx_fl_frozen == 0) { ia64_set_pmc(0, 0); ia64_srlz_d(); + /* place where we potentially (kernel level) start monitoring again */ } } /* * This function is called when a thread exits (from exit_thread()). - * This is a simplified pfm_save_regs() that simply flushes hthe current + * This is a simplified pfm_save_regs() that simply flushes the current * register state into the save area taking into account any pending * overflow. This time no notification is sent because the taks is dying * anyway. The inline processing of overflows avoids loosing some counts. @@ -1933,12 +2141,20 @@ pfm_flush_regs (struct task_struct *ta) /* collect latest results */ ctx->ctx_pmds[i].val += ia64_get_pmd(j) & pmu_conf.perf_ovfl_val; + /* + * now everything is in ctx_pmds[] and we need + * to clear the saved context from save_regs() such that + * pfm_read_pmds() gets the correct value + */ + ta->thread.pmd[j] = 0; + /* take care of overflow inline */ if (mask & 0x1) { ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val; DBprintk((" PMD[%d] overflowed pmd=0x%lx pmds.val=0x%lx\n", j, ia64_get_pmd(j), ctx->ctx_pmds[i].val)); } + mask >>=1; } } @@ -1977,7 +2193,7 @@ ia64_reset_pmu(void) /* clears all PMD registers */ for(i=0;i< pmu_conf.num_pmds; i++) { - if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0); + if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0); } ia64_srlz_d(); } @@ -1986,20 +2202,30 @@ ia64_reset_pmu(void) * task is the newly created task */ int -pfm_inherit(struct task_struct *task) +pfm_inherit(struct task_struct *task, struct pt_regs *regs) { pfm_context_t *ctx = current->thread.pfm_context; pfm_context_t *nctx; struct thread_struct *th = &task->thread; int i, cnum; + /* + * bypass completely for system wide + */ + if (pfs_info.pfs_sys_session) { + DBprintk((" enabling psr.pp for %d\n", task->pid)); + ia64_psr(regs)->pp = pfs_info.pfs_pp; + return 0; + } + /* * takes care of easiest case first */ if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) { DBprintk((" removing PFM context for %d\n", task->pid)); task->thread.pfm_context = NULL; - task->thread.pfm_pend_notify = 0; + task->thread.pfm_must_block = 0; + atomic_set(&task->thread.pfm_notifiers_check, 0); /* copy_thread() clears IA64_THREAD_PM_VALID */ return 0; } @@ -2009,9 +2235,11 @@ pfm_inherit(struct task_struct *task) /* copy content */ *nctx = *ctx; - if (ctx->ctx_fl_inherit == PFM_FL_INHERIT_ONCE) { + if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_ONCE) { nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; + atomic_set(&task->thread.pfm_notifiers_check, 0); DBprintk((" downgrading to INHERIT_NONE for %d\n", task->pid)); + pfs_info.pfs_proc_sessions++; } /* initialize counters in new context */ @@ -2033,7 +2261,7 @@ pfm_inherit(struct task_struct *task) sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */ /* clear pending notification */ - th->pfm_pend_notify = 0; + th->pfm_must_block = 0; /* link with new task */ th->pfm_context = nctx; @@ -2052,7 +2280,10 @@ pfm_inherit(struct task_struct *task) return 0; } -/* called from exit_thread() */ +/* + * called from release_thread(), at this point this task is not in the + * tasklist anymore + */ void pfm_context_exit(struct task_struct *task) { @@ -2068,16 +2299,126 @@ pfm_context_exit(struct task_struct *task) pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; /* if only user left, then remove */ - DBprintk((" pid %d: task %d sampling psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter)); + DBprintk((" [%d] [%d] psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter)); if (atomic_dec_and_test(&psb->psb_refcnt) ) { rvfree(psb->psb_hdr, psb->psb_size); vfree(psb); - DBprintk((" pid %d: cleaning task %d sampling buffer\n", current->pid, task->pid )); + DBprintk((" [%d] cleaning [%d] sampling buffer\n", current->pid, task->pid )); + } + } + DBprintk((" [%d] cleaning [%d] pfm_context @%p\n", current->pid, task->pid, (void *)ctx)); + + /* + * To avoid getting the notified task scan the entire process list + * when it exits because it would have pfm_notifiers_check set, we + * decrease it by 1 to inform the task, that one less task is going + * to send it notification. each new notifer increases this field by + * 1 in pfm_context_create(). Of course, there is race condition between + * decreasing the value and the notified task exiting. The danger comes + * from the fact that we have a direct pointer to its task structure + * thereby bypassing the tasklist. We must make sure that if we have + * notify_task!= NULL, the target task is still somewhat present. It may + * already be detached from the tasklist but that's okay. Note that it is + * okay if we 'miss the deadline' and the task scans the list for nothing, + * it will affect performance but not correctness. The correctness is ensured + * by using the notify_lock whic prevents the notify_task from changing on us. + * Once holdhing this lock, if we see notify_task!= NULL, then it will stay like + * that until we release the lock. If it is NULL already then we came too late. + */ + spin_lock(&ctx->ctx_notify_lock); + + if (ctx->ctx_notify_task) { + DBprintk((" [%d] [%d] atomic_sub on [%d] notifiers=%u\n", current->pid, task->pid, + ctx->ctx_notify_task->pid, + atomic_read(&ctx->ctx_notify_task->thread.pfm_notifiers_check))); + + atomic_sub(1, &ctx->ctx_notify_task->thread.pfm_notifiers_check); + } + + spin_unlock(&ctx->ctx_notify_lock); + + if (ctx->ctx_fl_system) { + /* + * if included interrupts (true by default), then reset + * to get default value + */ + if (ctx->ctx_fl_exclintr == 0) { + /* + * reload kernel default DCR value + */ + ia64_set_dcr(pfs_info.pfs_dfl_dcr); + DBprintk((" restored dcr to 0x%lx\n", pfs_info.pfs_dfl_dcr)); } + /* + * free system wide session slot + */ + pfs_info.pfs_sys_session = 0; + } else { + pfs_info.pfs_proc_sessions--; } - DBprintk((" pid %d: task %d pfm_context is freed @%p\n", current->pid, task->pid, (void *)ctx)); + pfm_context_free(ctx); + /* + * clean pfm state in thread structure, + */ + task->thread.pfm_context = NULL; + task->thread.pfm_must_block = 0; + /* pfm_notifiers is cleaned in pfm_cleanup_notifiers() */ + +} + +void +pfm_cleanup_notifiers(struct task_struct *task) +{ + struct task_struct *p; + pfm_context_t *ctx; + + DBprintk((" [%d] called\n", task->pid)); + + read_lock(&tasklist_lock); + + for_each_task(p) { + /* + * It is safe to do the 2-step test here, because thread.ctx + * is cleaned up only in release_thread() and at that point + * the task has been detached from the tasklist which is an + * operation which uses the write_lock() on the tasklist_lock + * so it cannot run concurrently to this loop. So we have the + * guarantee that if we find p and it has a perfmon ctx then + * it is going to stay like this for the entire execution of this + * loop. + */ + ctx = p->thread.pfm_context; + + DBprintk((" [%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); + + if (ctx && ctx->ctx_notify_task == task) { + DBprintk((" trying for notifier %d in %d\n", task->pid, p->pid)); + /* + * the spinlock is required to take care of a race condition + * with the send_sig_info() call. We must make sure that + * either the send_sig_info() completes using a valid task, + * or the notify_task is cleared before the send_sig_info() + * can pick up a stale value. Note that by the time this + * function is executed the 'task' is already detached from the + * tasklist. The problem is that the notifiers have a direct + * pointer to it. It is okay to send a signal to a task in this + * stage, it simply will have no effect. But it is better than sending + * to a completely destroyed task or worse to a new task using the same + * task_struct address. + */ + spin_lock(&ctx->ctx_notify_lock); + + ctx->ctx_notify_task = NULL; + + spin_unlock(&ctx->ctx_notify_lock); + + DBprintk((" done for notifier %d in %d\n", task->pid, p->pid)); + } + } + read_unlock(&tasklist_lock); + } #else /* !CONFIG_PERFMON */ diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 004b93544d14..b66b6ec9e469 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -63,7 +63,8 @@ show_regs (struct pt_regs *regs) { unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri; - printk("\npsr : %016lx ifs : %016lx ip : [<%016lx>] %s\n", + printk("\nPid: %d, comm: %20s\n", current->pid, current->comm); + printk("psr : %016lx ifs : %016lx ip : [<%016lx>] %s\n", regs->cr_ipsr, regs->cr_ifs, ip, print_tainted()); printk("unat: %016lx pfs : %016lx rsc : %016lx\n", regs->ar_unat, regs->ar_pfs, regs->ar_rsc); @@ -201,7 +202,7 @@ copy_thread (int nr, unsigned long clone_flags, { unsigned long rbs, child_rbs, rbs_size, stack_offset, stack_top, stack_used; struct switch_stack *child_stack, *stack; - extern char ia64_ret_from_clone; + extern char ia64_ret_from_clone, ia32_ret_from_clone; struct pt_regs *child_ptregs; int retval = 0; @@ -250,7 +251,10 @@ copy_thread (int nr, unsigned long clone_flags, child_ptregs->r12 = (unsigned long) (child_ptregs + 1); /* kernel sp */ child_ptregs->r13 = (unsigned long) p; /* set `current' pointer */ } - child_stack->b0 = (unsigned long) &ia64_ret_from_clone; + if (IS_IA32_PROCESS(regs)) + child_stack->b0 = (unsigned long) &ia32_ret_from_clone; + else + child_stack->b0 = (unsigned long) &ia64_ret_from_clone; child_stack->ar_bspstore = child_rbs + rbs_size; /* copy parts of thread_struct: */ @@ -285,9 +289,8 @@ copy_thread (int nr, unsigned long clone_flags, ia32_save_state(p); #endif #ifdef CONFIG_PERFMON - p->thread.pfm_pend_notify = 0; if (p->thread.pfm_context) - retval = pfm_inherit(p); + retval = pfm_inherit(p, child_ptregs); #endif return retval; } @@ -441,11 +444,24 @@ flush_thread (void) } #ifdef CONFIG_PERFMON +/* + * By the time we get here, the task is detached from the tasklist. This is important + * because it means that no other tasks can ever find it as a notifiied task, therfore + * there is no race condition between this code and let's say a pfm_context_create(). + * Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if + * this other task is in the middle of its own pfm_context_exit() because it would alreayd + * be out of the task list. Note that this case is very unlikely between a direct child + * and its parents (if it is the notified process) because of the way the exit is notified + * via SIGCHLD. + */ void release_thread (struct task_struct *task) { if (task->thread.pfm_context) pfm_context_exit(task); + + if (atomic_read(&task->thread.pfm_notifiers_check) > 0) + pfm_cleanup_notifiers(task); } #endif @@ -515,6 +531,29 @@ get_wchan (struct task_struct *p) # undef last_sched } +void +cpu_halt (void) +{ + pal_power_mgmt_info_u_t power_info[8]; + unsigned long min_power; + int i, min_power_state; + + if (ia64_pal_halt_info(power_info) != 0) + return; + + min_power_state = 0; + min_power = power_info[0].pal_power_mgmt_info_s.power_consumption; + for (i = 1; i < 8; ++i) + if (power_info[i].pal_power_mgmt_info_s.im + && power_info[i].pal_power_mgmt_info_s.power_consumption < min_power) { + min_power = power_info[i].pal_power_mgmt_info_s.power_consumption; + min_power_state = i; + } + + while (1) + ia64_pal_halt(min_power_state); +} + void machine_restart (char *restart_cmd) { @@ -524,6 +563,7 @@ machine_restart (char *restart_cmd) void machine_halt (void) { + cpu_halt(); } void @@ -531,4 +571,5 @@ machine_power_off (void) { if (pm_power_off) pm_power_off(); + machine_halt(); } diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 56b07ecb1de4..fc69cf6e2a5e 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -2,7 +2,7 @@ * Kernel support for the ptrace() and syscall tracing interfaces. * * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2001 David Mosberger-Tang + * David Mosberger-Tang * * Derived from the x86 and Alpha versions. Most of the code in here * could actually be factored into a common set of routines. @@ -794,11 +794,14 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data * * Make sure the single step bit is not set. */ -void ptrace_disable(struct task_struct *child) +void +ptrace_disable (struct task_struct *child) { + struct ia64_psr *child_psr = ia64_psr(ia64_task_regs(child)); + /* make sure the single step/take-branch tra bits are not set: */ - ia64_psr(pt)->ss = 0; - ia64_psr(pt)->tb = 0; + child_psr->ss = 0; + child_psr->tb = 0; /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; @@ -809,7 +812,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt, *regs = (struct pt_regs *) &stack; - unsigned long flags, urbs_end; + unsigned long urbs_end; struct task_struct *child; struct switch_stack *sw; long ret; @@ -855,6 +858,19 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, if (child->p_pptr != current) goto out_tsk; + if (request != PTRACE_KILL) { + if (child->state != TASK_STOPPED) + goto out_tsk; + +#ifdef CONFIG_SMP + while (child->has_cpu) { + if (child->state != TASK_STOPPED) + goto out_tsk; + barrier(); + } +#endif + } + pt = ia64_task_regs(child); sw = (struct switch_stack *) (child->thread.ksp + 16); @@ -925,7 +941,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, child->ptrace &= ~PT_TRACESYS; child->exit_code = data; - /* make sure the single step/take-branch tra bits are not set: */ + /* make sure the single step/taken-branch trap bits are not set: */ ia64_psr(pt)->ss = 0; ia64_psr(pt)->tb = 0; diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c index 56059a306615..61f86ebade06 100644 --- a/arch/ia64/kernel/sal.c +++ b/arch/ia64/kernel/sal.c @@ -1,8 +1,8 @@ /* * System Abstraction Layer (SAL) interface routines. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * David Mosberger-Tang * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond */ @@ -18,8 +18,6 @@ #include #include -#define SAL_DEBUG - spinlock_t sal_lock = SPIN_LOCK_UNLOCKED; static struct { @@ -122,10 +120,8 @@ ia64_sal_init (struct ia64_sal_systab *systab) switch (*p) { case SAL_DESC_ENTRY_POINT: ep = (struct ia64_sal_desc_entry_point *) p; -#ifdef SAL_DEBUG - printk("sal[%d] - entry: pal_proc=0x%lx, sal_proc=0x%lx\n", - i, ep->pal_proc, ep->sal_proc); -#endif + printk("SAL: entry: pal_proc=0x%lx, sal_proc=0x%lx\n", + ep->pal_proc, ep->sal_proc); ia64_pal_handler_init(__va(ep->pal_proc)); ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp)); break; @@ -138,17 +134,12 @@ ia64_sal_init (struct ia64_sal_systab *systab) #ifdef CONFIG_SMP { struct ia64_sal_desc_ap_wakeup *ap = (void *) p; -# ifdef SAL_DEBUG - printk("sal[%d] - wakeup type %x, 0x%lx\n", - i, ap->mechanism, ap->vector); -# endif + switch (ap->mechanism) { case IA64_SAL_AP_EXTERNAL_INT: ap_wakeup_vector = ap->vector; -# ifdef SAL_DEBUG printk("SAL: AP wakeup using external interrupt " "vector 0x%lx\n", ap_wakeup_vector); -# endif break; default: @@ -163,21 +154,13 @@ ia64_sal_init (struct ia64_sal_systab *systab) struct ia64_sal_desc_platform_feature *pf = (void *) p; printk("SAL: Platform features "); -#ifdef CONFIG_IA64_HAVE_IRQREDIR - /* - * Early versions of SAL say we don't have - * IRQ redirection, even though we do... - */ - pf->feature_mask |= (1 << 1); -#endif - if (pf->feature_mask & (1 << 0)) printk("BusLock "); if (pf->feature_mask & (1 << 1)) { printk("IRQ_Redirection "); #ifdef CONFIG_SMP - if (no_int_routing) + if (no_int_routing) smp_int_redirect &= ~SMP_IRQ_REDIRECTION; else smp_int_redirect |= SMP_IRQ_REDIRECTION; diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 7f15ccdd2120..7fb3b658b75d 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -534,10 +534,13 @@ cpu_init (void) /* * Initialize default control register to defer all speculative faults. The * kernel MUST NOT depend on a particular setting of these bits (in other words, - * the kernel must have recovery code for all speculative accesses). + * the kernel must have recovery code for all speculative accesses). Turn on + * dcr.lc as per recommendation by the architecture team. Most IA-32 apps + * shouldn't be affected by this (moral: keep your ia32 locks aligned and you'll + * be fine). */ ia64_set_dcr( IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR - | IA64_DCR_DA | IA64_DCR_DD); + | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC); #ifndef CONFIG_SMP ia64_set_fpu_owner(0); #endif diff --git a/arch/ia64/kernel/sigframe.h b/arch/ia64/kernel/sigframe.h index 77decb790d8c..797c6733a726 100644 --- a/arch/ia64/kernel/sigframe.h +++ b/arch/ia64/kernel/sigframe.h @@ -1,3 +1,9 @@ +struct sigscratch { + unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */ + unsigned long pad; + struct pt_regs pt; +}; + struct sigframe { /* * Place signal handler args where user-level unwinder can find them easily. @@ -7,10 +13,11 @@ struct sigframe { unsigned long arg0; /* signum */ unsigned long arg1; /* siginfo pointer */ unsigned long arg2; /* sigcontext pointer */ + /* + * End of architected state. + */ - unsigned long rbs_base; /* base of new register backing store (or NULL) */ void *handler; /* pointer to the plabel of the signal handler */ - struct siginfo info; struct sigcontext sc; }; diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 11c59f6bc2e7..04a08e56cbc6 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -2,7 +2,7 @@ * Architecture-specific signal handling support. * * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2001 David Mosberger-Tang + * David Mosberger-Tang * * Derived from i386 and Alpha versions. */ @@ -39,12 +39,6 @@ # define GET_SIGSET(k,u) __get_user((k)->sig[0], &(u)->sig[0]) #endif -struct sigscratch { - unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */ - unsigned long pad; - struct pt_regs pt; -}; - extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */ long @@ -55,6 +49,10 @@ ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr) /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; + + if (!access_ok(VERIFY_READ, uset, sigsetsize)) + return -EFAULT; + if (GET_SIGSET(&set, uset)) return -EFAULT; @@ -73,15 +71,9 @@ ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr) * pre-set the correct error code here to ensure that the right values * get saved in sigcontext by ia64_do_signal. */ -#ifdef CONFIG_IA32_SUPPORT - if (IS_IA32_PROCESS(&scr->pt)) { - scr->pt.r8 = -EINTR; - } else -#endif - { - scr->pt.r8 = EINTR; - scr->pt.r10 = -1; - } + scr->pt.r8 = EINTR; + scr->pt.r10 = -1; + while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -139,10 +131,9 @@ restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) struct ia64_psr *psr = ia64_psr(&scr->pt); __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16); - if (!psr->dfh) { - psr->mfh = 0; + psr->mfh = 0; /* drop signal handler's fph contents... */ + if (!psr->dfh) __ia64_load_fpu(current->thread.fph); - } } return err; } @@ -380,7 +371,8 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, err = __put_user(sig, &frame->arg0); err |= __put_user(&frame->info, &frame->arg1); err |= __put_user(&frame->sc, &frame->arg2); - err |= __put_user(new_rbs, &frame->rbs_base); + err |= __put_user(new_rbs, &frame->sc.sc_rbs_base); + err |= __put_user(0, &frame->sc.sc_loadrs); /* initialize to zero */ err |= __put_user(ka->sa.sa_handler, &frame->handler); err |= copy_siginfo_to_user(&frame->info, info); @@ -460,6 +452,7 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) { + struct signal_struct *sig; struct k_sigaction *ka; siginfo_t info; long restart = in_syscall; @@ -571,8 +564,8 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) case SIGSTOP: current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags - & SA_NOCLDSTOP)) + sig = current->p_pptr->sig; + if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 59f0c55ecfa4..8f6f1ffd005a 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -48,6 +48,7 @@ #include #include #include +#include /* The 'big kernel lock' */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; @@ -70,20 +71,18 @@ static volatile struct call_data_struct *call_data; #define IPI_CALL_FUNC 0 #define IPI_CPU_STOP 1 -#ifndef CONFIG_ITANIUM_PTCG -# define IPI_FLUSH_TLB 2 -#endif /*!CONFIG_ITANIUM_PTCG */ static void stop_this_cpu (void) { + extern void cpu_halt (void); /* * Remove this CPU: */ clear_bit(smp_processor_id(), &cpu_online_map); max_xtp(); __cli(); - for (;;); + cpu_halt(); } void @@ -136,49 +135,6 @@ handle_IPI (int irq, void *dev_id, struct pt_regs *regs) stop_this_cpu(); break; -#ifndef CONFIG_ITANIUM_PTCG - case IPI_FLUSH_TLB: - { - extern unsigned long flush_start, flush_end, flush_nbits, flush_rid; - extern atomic_t flush_cpu_count; - unsigned long saved_rid = ia64_get_rr(flush_start); - unsigned long end = flush_end; - unsigned long start = flush_start; - unsigned long nbits = flush_nbits; - - /* - * Current CPU may be running with different RID so we need to - * reload the RID of flushed address. Purging the translation - * also needs ALAT invalidation; we do not need "invala" here - * since it is done in ia64_leave_kernel. - */ - ia64_srlz_d(); - if (saved_rid != flush_rid) { - ia64_set_rr(flush_start, flush_rid); - ia64_srlz_d(); - } - - do { - /* - * Purge local TLB entries. - */ - __asm__ __volatile__ ("ptc.l %0,%1" :: - "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - - ia64_insn_group_barrier(); - ia64_srlz_i(); /* srlz.i implies srlz.d */ - - if (saved_rid != flush_rid) { - ia64_set_rr(flush_start, saved_rid); - ia64_srlz_d(); - } - atomic_dec(&flush_cpu_count); - break; - } -#endif /* !CONFIG_ITANIUM_PTCG */ - default: printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; @@ -228,30 +184,6 @@ smp_send_reschedule (int cpu) platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); } -#ifndef CONFIG_ITANIUM_PTCG - -void -smp_send_flush_tlb (void) -{ - send_IPI_allbutself(IPI_FLUSH_TLB); -} - -void -smp_resend_flush_tlb (void) -{ - int i; - - /* - * Really need a null IPI but since this rarely should happen & since this code - * will go away, lets not add one. - */ - for (i = 0; i < smp_num_cpus; ++i) - if (i != smp_processor_id()) - smp_send_reschedule(i); -} - -#endif /* !CONFIG_ITANIUM_PTCG */ - void smp_flush_tlb_all (void) { @@ -277,10 +209,6 @@ smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int { struct call_data_struct data; int cpus = 1; -#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) - unsigned long timeout; -#endif if (cpuid == smp_processor_id()) { printk(__FUNCTION__" trying to call self\n"); @@ -295,26 +223,15 @@ smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int atomic_set(&data.finished, 0); spin_lock_bh(&call_lock); - call_data = &data; - -#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) - resend: - send_IPI_single(cpuid, IPI_CALL_FUNC); - /* Wait for response */ - timeout = jiffies + HZ; - while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout)) - barrier(); - if (atomic_read(&data.started) != cpus) - goto resend; -#else + call_data = &data; + mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ send_IPI_single(cpuid, IPI_CALL_FUNC); /* Wait for response */ while (atomic_read(&data.started) != cpus) barrier(); -#endif + if (wait) while (atomic_read(&data.finished) != cpus) barrier(); @@ -348,10 +265,6 @@ smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wai { struct call_data_struct data; int cpus = smp_num_cpus-1; -#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) - unsigned long timeout; -#endif if (!cpus) return 0; @@ -364,27 +277,14 @@ smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wai atomic_set(&data.finished, 0); spin_lock_bh(&call_lock); - call_data = &data; - -#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) - resend: - /* Send a message to all other CPUs and wait for them to respond */ - send_IPI_allbutself(IPI_CALL_FUNC); - /* Wait for response */ - timeout = jiffies + HZ; - while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout)) - barrier(); - if (atomic_read(&data.started) != cpus) - goto resend; -#else + call_data = &data; + mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ send_IPI_allbutself(IPI_CALL_FUNC); /* Wait for response */ while (atomic_read(&data.started) != cpus) barrier(); -#endif if (wait) while (atomic_read(&data.finished) != cpus) diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 52e393aa2c81..abc38103dd9a 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,8 @@ #include #include +#define SMP_DEBUG 0 + #if SMP_DEBUG #define Dprintk(x...) printk(x) #else @@ -310,7 +313,7 @@ smp_commence (void) } -void __init +static void __init smp_callin (void) { int cpuid, phys_id; @@ -324,8 +327,7 @@ smp_callin (void) phys_id = hard_smp_processor_id(); if (test_and_set_bit(cpuid, &cpu_online_map)) { - printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", - phys_id, cpuid); + printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", phys_id, cpuid); BUG(); } @@ -341,6 +343,12 @@ smp_callin (void) * Get our bogomips. */ ia64_init_itm(); + +#ifdef CONFIG_IA64_MCA + ia64_mca_cmc_vector_setup(); /* Setup vector on AP & enable */ + ia64_mca_check_errors(); /* For post-failure MCA error logging */ +#endif + #ifdef CONFIG_PERFMON perfmon_init_percpu(); #endif @@ -364,14 +372,15 @@ start_secondary (void *unused) { extern int cpu_idle (void); + Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id()); efi_map_pal_code(); cpu_init(); smp_callin(); - Dprintk("CPU %d is set to go. \n", smp_processor_id()); + Dprintk("CPU %d is set to go.\n", smp_processor_id()); while (!atomic_read(&smp_commenced)) ; - Dprintk("CPU %d is starting idle. \n", smp_processor_id()); + Dprintk("CPU %d is starting idle.\n", smp_processor_id()); return cpu_idle(); } @@ -415,7 +424,7 @@ do_boot_cpu (int sapicid) unhash_process(idle); init_tasks[cpu] = idle; - Dprintk("Sending Wakeup Vector to AP 0x%x/0x%x.\n", cpu, sapicid); + Dprintk("Sending wakeup vector %u to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); @@ -424,7 +433,6 @@ do_boot_cpu (int sapicid) */ Dprintk("Waiting on callin_map ..."); for (timeout = 0; timeout < 100000; timeout++) { - Dprintk("."); if (test_bit(cpu, &cpu_callin_map)) break; /* It has booted */ udelay(100); diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index 577ed872b3db..cc312ad8b18f 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -19,24 +19,29 @@ #include #include -#define COLOR_ALIGN(addr) (((addr) + SHMLBA - 1) & ~(SHMLBA - 1)) - unsigned long arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct vm_area_struct * vmm; long map_shared = (flags & MAP_SHARED); + unsigned long align_mask = PAGE_SIZE - 1; + struct vm_area_struct * vmm; if (len > RGN_MAP_LIMIT) return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (map_shared) - addr = COLOR_ALIGN(addr); - else - addr = PAGE_ALIGN(addr); + if (map_shared && (TASK_SIZE > 0xfffffffful)) + /* + * For 64-bit tasks, align shared segments to 1MB to avoid potential + * performance penalty due to virtual aliasing (see ASDM). For 32-bit + * tasks, we prefer to avoid exhausting the address space too quickly by + * limiting alignment to a single page. + */ + align_mask = SHMLBA - 1; + + addr = (addr + align_mask) & ~align_mask; for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { /* At this point: (!vmm || addr < vmm->vm_end). */ @@ -46,9 +51,7 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; - addr = vmm->vm_end; - if (map_shared) - addr = COLOR_ALIGN(addr); + addr = (vmm->vm_end + align_mask) & ~align_mask; } } @@ -184,8 +187,10 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, un if (!file) return -EBADF; - if (!file->f_op || !file->f_op->mmap) - return -ENODEV; + if (!file->f_op || !file->f_op->mmap) { + addr = -ENODEV; + goto out; + } } /* @@ -194,22 +199,26 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, un */ len = PAGE_ALIGN(len); if (len == 0) - return addr; + goto out; /* don't permit mappings into unmapped space or the virtual page table of a region: */ roff = rgn_offset(addr); - if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT) - return -EINVAL; + if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT) { + addr = -EINVAL; + goto out; + } /* don't permit mappings that would cross a region boundary: */ - if (rgn_index(addr) != rgn_index(addr + len)) - return -EINVAL; + if (rgn_index(addr) != rgn_index(addr + len)) { + addr = -EINVAL; + goto out; + } down_write(¤t->mm->mmap_sem); addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); - if (file) +out: if (file) fput(file); return addr; } diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index dc6500b7a167..d11dcf4534c4 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -145,6 +145,9 @@ do_gettimeofday (struct timeval *tv) tv->tv_usec = usec; } +/* XXX there should be a cleaner way for declaring an alias... */ +asm (".global get_fast_time; get_fast_time = do_gettimeofday"); + static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index 53eab244b9ac..8b949be0169e 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -1,20 +1,19 @@ /* * Architecture-specific trap handling. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang * * 05/12/00 grao : added isr in siginfo for SIGFPE */ /* - * The fpu_fault() handler needs to be able to access and update all - * floating point registers. Those saved in pt_regs can be accessed - * through that structure, but those not saved, will be accessed - * directly. To make this work, we need to ensure that the compiler - * does not end up using a preserved floating point register on its - * own. The following achieves this by declaring preserved registers - * that are not marked as "fixed" as global register variables. + * fp_emulate() needs to be able to access and update all floating point registers. Those + * saved in pt_regs can be accessed through that structure, but those not saved, will be + * accessed directly. To make this work, we need to ensure that the compiler does not end + * up using a preserved floating point register on its own. The following achieves this + * by declaring preserved registers that are not marked as "fixed" as global register + * variables. */ register double f2 asm ("f2"); register double f3 asm ("f3"); register double f4 asm ("f4"); register double f5 asm ("f5"); @@ -33,13 +32,17 @@ register double f30 asm ("f30"); register double f31 asm ("f31"); #include #include #include +#include /* For unblank_screen() */ +#include #include #include #include #include +extern spinlock_t timerlist_lock; + static fpswa_interface_t *fpswa_interface; void __init @@ -51,30 +54,74 @@ trap_init (void) fpswa_interface = __va(ia64_boot_param->fpswa); } +/* + * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock + * is acquired through the console unblank code) + */ void -die_if_kernel (char *str, struct pt_regs *regs, long err) +bust_spinlocks (int yes) { - if (user_mode(regs)) { -#if 0 - /* XXX for debugging only */ - printk ("!!die_if_kernel: %s(%d): %s %ld\n", - current->comm, current->pid, str, err); - show_regs(regs); + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + global_irq_lock = 0; /* Many serial drivers do __global_cli() */ #endif - return; + } else { + int loglevel_save = console_loglevel; +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() without + * oops_in_progress set so that printk will give klogd a poke. Hold onto + * your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; } +} - printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); - - show_regs(regs); +void +die (const char *str, struct pt_regs *regs, long err) +{ + static struct { + spinlock_t lock; + int lock_owner; + int lock_owner_depth; + } die = { + lock: SPIN_LOCK_UNLOCKED, + lock_owner: -1, + lock_owner_depth: 0 + }; - if (current->thread.flags & IA64_KERNEL_DEATH) { - printk("die_if_kernel recursion detected.\n"); - sti(); - while (1); + if (die.lock_owner != smp_processor_id()) { + console_verbose(); + spin_lock_irq(&die.lock); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); } - current->thread.flags |= IA64_KERNEL_DEATH; - do_exit(SIGSEGV); + + if (++die.lock_owner_depth < 3) { + printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); + show_regs(regs); + } else + printk(KERN_ERR "Recursive die() failure, output suppressed\n"); + + bust_spinlocks(0); + die.lock_owner = -1; + spin_unlock_irq(&die.lock); + do_exit(SIGSEGV); +} + +void +die_if_kernel (char *str, struct pt_regs *regs, long err) +{ + if (!user_mode(regs)) + die(str, regs, err); } void @@ -169,14 +216,12 @@ ia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, uns } /* - * disabled_fph_fault() is called when a user-level process attempts - * to access one of the registers f32..f127 when it doesn't own the - * fp-high register partition. When this happens, we save the current - * fph partition in the task_struct of the fpu-owner (if necessary) - * and then load the fp-high partition of the current task (if - * necessary). Note that the kernel has access to fph by the time we - * get here, as the IVT's "Diabled FP-Register" handler takes care of - * clearing psr.dfh. + * disabled_fph_fault() is called when a user-level process attempts to access f32..f127 + * and it doesn't own the fp-high register partition. When this happens, we save the + * current fph partition in the task_struct of the fpu-owner (if necessary) and then load + * the fp-high partition of the current task (if necessary). Note that the kernel has + * access to fph by the time we get here, as the IVT's "Disabled FP-Register" handler takes + * care of clearing psr.dfh. */ static inline void disabled_fph_fault (struct pt_regs *regs) @@ -277,7 +322,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) if (jiffies - last_time > 5*HZ) fpu_swa_count = 0; - if (++fpu_swa_count < 5) { + if ((++fpu_swa_count < 5) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { last_time = jiffies; printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n", current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri); @@ -478,12 +523,12 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, case 32: /* fp fault */ case 33: /* fp trap */ result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); - if (result < 0) { + if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; siginfo.si_code = FPE_FLTINV; siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - force_sig(SIGFPE, current); + force_sig_info(SIGFPE, &siginfo, current); } return; @@ -510,6 +555,10 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, break; case 46: +#ifdef CONFIG_IA32_SUPPORT + if (ia32_intercept(regs, isr) == 0) + return; +#endif printk("Unexpected IA-32 intercept trap (Trap 46)\n"); printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n", regs->cr_iip, ifa, isr, iim); diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index 7dc41e5a7c41..90596f9fc2c7 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -5,6 +5,8 @@ * Copyright (C) 1999-2000 Stephane Eranian * Copyright (C) 2001 David Mosberger-Tang * + * 2001/10/11 Fix unaligned access to rotating registers in s/w pipelined loops. + * 2001/08/13 Correct size of extended floats (float_fsz) from 16 to 10 bytes. * 2001/01/17 Add support emulation of unaligned kernel accesses. */ #include @@ -282,9 +284,19 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) unsigned long rnats, nat_mask; unsigned long on_kbs; long sof = (regs->cr_ifs) & 0x7f; + long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); + long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; + long ridx; + + if ((r1 - 32) > sor) + ridx = -sof + (r1 - 32); + else if ((r1 - 32) < (sor - rrb_gr)) + ridx = -sof + (r1 - 32) + rrb_gr; + else + ridx = -sof + (r1 - 32) - (sor - rrb_gr); - DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", - r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); if ((r1 - 32) >= sof) { /* this should never happen, as the "rsvd register fault" has higher priority */ @@ -293,7 +305,7 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) } on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); - addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx); if (addr >= kbs) { /* the register is on the kernel backing store: easy... */ rnat_addr = ia64_rse_rnat_addr(addr); @@ -318,12 +330,12 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) return; } - bspstore = (unsigned long *) regs->ar_bspstore; + bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); bsp = ia64_rse_skip_regs(ubs_end, -sof); - addr = ia64_rse_skip_regs(bsp, r1 - 32); + addr = ia64_rse_skip_regs(bsp, ridx + sof); - DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr); + DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); ia64_poke(current, sw, (unsigned long) ubs_end, (unsigned long) addr, val); @@ -353,9 +365,19 @@ get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *na unsigned long rnats, nat_mask; unsigned long on_kbs; long sof = (regs->cr_ifs) & 0x7f; + long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); + long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; + long ridx; + + if ((r1 - 32) > sor) + ridx = -sof + (r1 - 32); + else if ((r1 - 32) < (sor - rrb_gr)) + ridx = -sof + (r1 - 32) + rrb_gr; + else + ridx = -sof + (r1 - 32) - (sor - rrb_gr); - DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", - r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); if ((r1 - 32) >= sof) { /* this should never happen, as the "rsvd register fault" has higher priority */ @@ -364,7 +386,7 @@ get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *na } on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); - addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx); if (addr >= kbs) { /* the register is on the kernel backing store: easy... */ *val = *addr; @@ -390,7 +412,7 @@ get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *na bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); bsp = ia64_rse_skip_regs(ubs_end, -sof); - addr = ia64_rse_skip_regs(bsp, r1 - 32); + addr = ia64_rse_skip_regs(bsp, ridx + sof); DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); @@ -908,7 +930,7 @@ emulate_store_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs) * floating point operations sizes in bytes */ static const unsigned char float_fsz[4]={ - 16, /* extended precision (e) */ + 10, /* extended precision (e) */ 8, /* integer (8) */ 4, /* single precision (s) */ 8 /* double precision (d) */ @@ -978,11 +1000,11 @@ emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs unsigned long len = float_fsz[ld.x6_sz]; /* - * fr0 & fr1 don't need to be checked because Illegal Instruction - * faults have higher priority than unaligned faults. + * fr0 & fr1 don't need to be checked because Illegal Instruction faults have + * higher priority than unaligned faults. * - * r0 cannot be found as the base as it would never generate an - * unaligned reference. + * r0 cannot be found as the base as it would never generate an unaligned + * reference. */ /* @@ -996,8 +1018,10 @@ emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs * invalidate the ALAT entry and execute updates, if any. */ if (ld.x6_op != 0x2) { - /* this assumes little-endian byte-order: */ - + /* + * This assumes little-endian byte-order. Note that there is no "ldfpe" + * instruction: + */ if (copy_from_user(&fpr_init[0], (void *) ifa, len) || copy_from_user(&fpr_init[1], (void *) (ifa + len), len)) return -1; @@ -1337,7 +1361,7 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) /* * IMPORTANT: - * Notice that the swictch statement DOES not cover all possible instructions + * Notice that the switch statement DOES not cover all possible instructions * that DO generate unaligned references. This is made on purpose because for some * instructions it DOES NOT make sense to try and emulate the access. Sometimes it * is WRONG to try and emulate. Here is a list of instruction we don't emulate i.e., diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index bdd277fbe990..ea6284e366d2 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -504,7 +504,7 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int return 0; } -inline int +int unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write) { unsigned long *addr; diff --git a/arch/ia64/lib/clear_page.S b/arch/ia64/lib/clear_page.S index 810d51be909c..ed6867838823 100644 --- a/arch/ia64/lib/clear_page.S +++ b/arch/ia64/lib/clear_page.S @@ -47,5 +47,5 @@ GLOBAL_ENTRY(clear_page) br.cloop.dptk.few 1b ;; mov ar.lc = r2 // restore lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(clear_page) diff --git a/arch/ia64/lib/clear_user.S b/arch/ia64/lib/clear_user.S index eac872d77ac8..eecd8577b209 100644 --- a/arch/ia64/lib/clear_user.S +++ b/arch/ia64/lib/clear_user.S @@ -8,7 +8,7 @@ * r8: number of bytes that didn't get cleared due to a fault * * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1999 Stephane Eranian + * Stephane Eranian */ #include @@ -62,11 +62,11 @@ GLOBAL_ENTRY(__do_clear_user) ;; // avoid WAW on CFM adds tmp=-1,len // br.ctop is repeat/until mov ret0=len // return value is length at this point -(p6) br.ret.spnt.few rp +(p6) br.ret.spnt.many rp ;; cmp.lt p6,p0=16,len // if len > 16 then long memset mov ar.lc=tmp // initialize lc for small count -(p6) br.cond.dptk.few long_do_clear +(p6) br.cond.dptk .long_do_clear ;; // WAR on ar.lc // // worst case 16 iterations, avg 8 iterations @@ -79,7 +79,7 @@ GLOBAL_ENTRY(__do_clear_user) 1: EX( .Lexit1, st1 [buf]=r0,1 ) adds len=-1,len // countdown length using len - br.cloop.dptk.few 1b + br.cloop.dptk 1b ;; // avoid RAW on ar.lc // // .Lexit4: comes from byte by byte loop @@ -87,7 +87,7 @@ GLOBAL_ENTRY(__do_clear_user) .Lexit1: mov ret0=len // faster than using ar.lc mov ar.lc=saved_lc - br.ret.sptk.few rp // end of short clear_user + br.ret.sptk.many rp // end of short clear_user // @@ -98,7 +98,7 @@ GLOBAL_ENTRY(__do_clear_user) // instead of ret0 is due to the fact that the exception code // changes the values of r8. // -long_do_clear: +.long_do_clear: tbit.nz p6,p0=buf,0 // odd alignment (for long_do_clear) ;; EX( .Lexit3, (p6) st1 [buf]=r0,1 ) // 1-byte aligned @@ -119,7 +119,7 @@ long_do_clear: ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt -(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left +(p6) br.cond.dpnt .dotail // we have less than 16 bytes left ;; adds buf2=8,buf // setup second base pointer mov ar.lc=tmp @@ -148,7 +148,7 @@ long_do_clear: ;; // needed to get len correct when error st8 [buf2]=r0,16 adds len=-16,len - br.cloop.dptk.few 2b + br.cloop.dptk 2b ;; mov ar.lc=saved_lc // @@ -178,7 +178,7 @@ long_do_clear: ;; EX( .Lexit2, (p7) st1 [buf]=r0 ) // only 1 byte left mov ret0=r0 // success - br.ret.dptk.few rp // end of most likely path + br.ret.sptk.many rp // end of most likely path // // Outlined error handling code @@ -205,5 +205,5 @@ long_do_clear: .Lexit3: mov ret0=len mov ar.lc=saved_lc - br.ret.dptk.few rp + br.ret.sptk.many rp END(__do_clear_user) diff --git a/arch/ia64/lib/copy_page.S b/arch/ia64/lib/copy_page.S index 5739223f99a6..fd9bd9094bdf 100644 --- a/arch/ia64/lib/copy_page.S +++ b/arch/ia64/lib/copy_page.S @@ -90,5 +90,5 @@ GLOBAL_ENTRY(copy_page) mov pr=saved_pr,0xffffffffffff0000 // restore predicates mov ar.pfs=saved_pfs mov ar.lc=saved_lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(copy_page) diff --git a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S index dc8cd56e7835..af798de023d1 100644 --- a/arch/ia64/lib/copy_user.S +++ b/arch/ia64/lib/copy_user.S @@ -19,8 +19,8 @@ * ret0 0 in case of success. The number of bytes NOT copied in * case of error. * - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 Stephane Eranian + * Copyright (C) 2000-2001 Hewlett-Packard Co + * Stephane Eranian * * Fixme: * - handle the case where we have more than 16 bytes and the alignment @@ -85,7 +85,7 @@ GLOBAL_ENTRY(__copy_user) cmp.eq p8,p0=r0,len // check for zero length .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) -(p8) br.ret.spnt.few rp // empty mempcy() +(p8) br.ret.spnt.many rp // empty mempcy() ;; add enddst=dst,len // first byte after end of source add endsrc=src,len // first byte after end of destination @@ -103,26 +103,26 @@ GLOBAL_ENTRY(__copy_user) cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy xor tmp=src,dst // same alignment test prepare -(p10) br.cond.dptk.few long_copy_user +(p10) br.cond.dptk .long_copy_user ;; // RAW pr.rot/p16 ? // // Now we do the byte by byte loop with software pipeline // // p7 is necessarily false by now 1: - EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + EX(.failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) + EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 1b ;; mov ar.lc=saved_lc mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs // restore ar.ec - br.ret.sptk.few rp // end of short memcpy + br.ret.sptk.many rp // end of short memcpy // // Not 8-byte aligned // -diff_align_copy_user: +.diff_align_copy_user: // At this point we know we have more than 16 bytes to copy // and also that src and dest do _not_ have the same alignment. and src2=0x7,src1 // src offset @@ -153,7 +153,7 @@ diff_align_copy_user: // We know src1 is not 8-byte aligned in this case. // cmp.eq p14,p15=r0,dst2 -(p15) br.cond.spnt.few 1f +(p15) br.cond.spnt 1f ;; sub t1=8,src2 mov t2=src2 @@ -163,7 +163,7 @@ diff_align_copy_user: ;; sub lshift=64,rshift ;; - br.cond.spnt.few word_copy_user + br.cond.spnt .word_copy_user ;; 1: cmp.leu p14,p15=src2,dst2 @@ -192,15 +192,15 @@ diff_align_copy_user: mov ar.lc=cnt ;; 2: - EX(failure_in_pipe2,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + EX(.failure_in_pipe2,(p16) ld1 val1[0]=[src1],1) + EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 2b ;; clrrrb ;; -word_copy_user: +.word_copy_user: cmp.gtu p9,p0=16,len1 -(p9) br.cond.spnt.few 4f // if (16 > len1) skip 8-byte copy +(p9) br.cond.spnt 4f // if (16 > len1) skip 8-byte copy ;; shr.u cnt=len1,3 // number of 64-bit words ;; @@ -232,24 +232,24 @@ word_copy_user: #define EPI_1 p[PIPE_DEPTH-2] #define SWITCH(pred, shift) cmp.eq pred,p0=shift,rshift #define CASE(pred, shift) \ - (pred) br.cond.spnt.few copy_user_bit##shift + (pred) br.cond.spnt .copy_user_bit##shift #define BODY(rshift) \ -copy_user_bit##rshift: \ +.copy_user_bit##rshift: \ 1: \ - EX(failure_out,(EPI) st8 [dst1]=tmp,8); \ + EX(.failure_out,(EPI) st8 [dst1]=tmp,8); \ (EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ EX(3f,(p16) ld8 val1[0]=[src1],8); \ - br.ctop.dptk.few 1b; \ + br.ctop.dptk 1b; \ ;; \ - br.cond.sptk.few .diff_align_do_tail; \ + br.cond.sptk.many .diff_align_do_tail; \ 2: \ (EPI) st8 [dst1]=tmp,8; \ (EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ 3: \ (p16) mov val1[0]=r0; \ - br.ctop.dptk.few 2b; \ + br.ctop.dptk 2b; \ ;; \ - br.cond.sptk.few failure_in2 + br.cond.sptk.many .failure_in2 // // Since the instruction 'shrp' requires a fixed 128-bit value @@ -301,25 +301,25 @@ copy_user_bit##rshift: \ mov ar.lc=len1 ;; 5: - EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + EX(.failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) + EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 5b ;; mov ar.lc=saved_lc mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp // // Beginning of long mempcy (i.e. > 16 bytes) // -long_copy_user: +.long_copy_user: tbit.nz p6,p7=src1,0 // odd alignement and tmp=7,tmp ;; cmp.eq p10,p8=r0,tmp mov len1=len // copy because of rotation -(p8) br.cond.dpnt.few diff_align_copy_user +(p8) br.cond.dpnt .diff_align_copy_user ;; // At this point we know we have more than 16 bytes to copy // and also that both src and dest have the same alignment @@ -327,11 +327,11 @@ long_copy_user: // forward slowly until we reach 16byte alignment: no need to // worry about reaching the end of buffer. // - EX(failure_in1,(p6) ld1 val1[0]=[src1],1) // 1-byte aligned + EX(.failure_in1,(p6) ld1 val1[0]=[src1],1) // 1-byte aligned (p6) adds len1=-1,len1;; tbit.nz p7,p0=src1,1 ;; - EX(failure_in1,(p7) ld2 val1[1]=[src1],2) // 2-byte aligned + EX(.failure_in1,(p7) ld2 val1[1]=[src1],2) // 2-byte aligned (p7) adds len1=-2,len1;; tbit.nz p8,p0=src1,2 ;; @@ -339,28 +339,28 @@ long_copy_user: // Stop bit not required after ld4 because if we fail on ld4 // we have never executed the ld1, therefore st1 is not executed. // - EX(failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned + EX(.failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned ;; - EX(failure_out,(p6) st1 [dst1]=val1[0],1) + EX(.failure_out,(p6) st1 [dst1]=val1[0],1) tbit.nz p9,p0=src1,3 ;; // // Stop bit not required after ld8 because if we fail on ld8 // we have never executed the ld2, therefore st2 is not executed. // - EX(failure_in1,(p9) ld8 val2[1]=[src1],8) // 8-byte aligned - EX(failure_out,(p7) st2 [dst1]=val1[1],2) + EX(.failure_in1,(p9) ld8 val2[1]=[src1],8) // 8-byte aligned + EX(.failure_out,(p7) st2 [dst1]=val1[1],2) (p8) adds len1=-4,len1 ;; - EX(failure_out, (p8) st4 [dst1]=val2[0],4) + EX(.failure_out, (p8) st4 [dst1]=val2[0],4) (p9) adds len1=-8,len1;; shr.u cnt=len1,4 // number of 128-bit (2x64bit) words ;; - EX(failure_out, (p9) st8 [dst1]=val2[1],8) + EX(.failure_out, (p9) st8 [dst1]=val2[1],8) tbit.nz p6,p0=len1,3 cmp.eq p7,p0=r0,cnt adds tmp=-1,cnt // br.ctop is repeat/until -(p7) br.cond.dpnt.few .dotail // we have less than 16 bytes left +(p7) br.cond.dpnt .dotail // we have less than 16 bytes left ;; adds src2=8,src1 adds dst2=8,dst1 @@ -370,12 +370,12 @@ long_copy_user: // 16bytes/iteration // 2: - EX(failure_in3,(p16) ld8 val1[0]=[src1],16) + EX(.failure_in3,(p16) ld8 val1[0]=[src1],16) (p16) ld8 val2[0]=[src2],16 - EX(failure_out, (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16) + EX(.failure_out, (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16) (EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16 - br.ctop.dptk.few 2b + br.ctop.dptk 2b ;; // RAW on src1 when fall through from loop // // Tail correction based on len only @@ -384,29 +384,28 @@ long_copy_user: // is 16 byte aligned AND we have less than 16 bytes to copy. // .dotail: - EX(failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes + EX(.failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes tbit.nz p7,p0=len1,2 ;; - EX(failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes + EX(.failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes tbit.nz p8,p0=len1,1 ;; - EX(failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes + EX(.failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes tbit.nz p9,p0=len1,0 ;; - EX(failure_out, (p6) st8 [dst1]=val1[0],8) + EX(.failure_out, (p6) st8 [dst1]=val1[0],8) ;; - EX(failure_in1,(p9) ld1 val2[1]=[src1]) // only 1 byte left + EX(.failure_in1,(p9) ld1 val2[1]=[src1]) // only 1 byte left mov ar.lc=saved_lc ;; - EX(failure_out,(p7) st4 [dst1]=val1[1],4) + EX(.failure_out,(p7) st4 [dst1]=val1[1],4) mov pr=saved_pr,0xffffffffffff0000 ;; - EX(failure_out, (p8) st2 [dst1]=val2[0],2) + EX(.failure_out, (p8) st2 [dst1]=val2[0],2) mov ar.pfs=saved_pfs ;; - EX(failure_out, (p9) st1 [dst1]=val2[1]) - br.ret.dptk.few rp - + EX(.failure_out, (p9) st1 [dst1]=val2[1]) + br.ret.sptk.many rp // @@ -433,32 +432,32 @@ long_copy_user: // pipeline going. We can't really do this inline because // p16 is always reset to 1 when lc > 0. // -failure_in_pipe1: +.failure_in_pipe1: sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied 1: (p16) mov val1[0]=r0 (EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1 - br.ctop.dptk.few 1b + br.ctop.dptk 1b ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp // // This is the case where the byte by byte copy fails on the load // when we copy the head. We need to finish the pipeline and copy // zeros for the rest of the destination. Since this happens // at the top we still need to fill the body and tail. -failure_in_pipe2: +.failure_in_pipe2: sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied 2: (p16) mov val1[0]=r0 (EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1 - br.ctop.dptk.few 2b + br.ctop.dptk 2b ;; sub len=enddst,dst1,1 // precompute len - br.cond.dptk.few failure_in1bis + br.cond.dptk.many .failure_in1bis ;; // @@ -533,9 +532,7 @@ failure_in_pipe2: // This means that we are in a situation similar the a fault in the // head part. That's nice! // -failure_in1: -// sub ret0=enddst,dst1 // number of bytes to zero, i.e. not copied -// sub len=enddst,dst1,1 +.failure_in1: sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied sub len=endsrc,src1,1 // @@ -546,18 +543,17 @@ failure_in1: // calling side. // ;; -failure_in1bis: // from (failure_in3) +.failure_in1bis: // from (.failure_in3) mov ar.lc=len // Continue with a stupid byte store. ;; 5: st1 [dst1]=r0,1 - br.cloop.dptk.few 5b + br.cloop.dptk 5b ;; -skip_loop: mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp // // Here we simply restart the loop but instead @@ -569,7 +565,7 @@ skip_loop: // we MUST use src1/endsrc here and not dst1/enddst because // of the pipeline effect. // -failure_in3: +.failure_in3: sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied ;; 2: @@ -577,36 +573,36 @@ failure_in3: (p16) mov val2[0]=r0 (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16 (EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16 - br.ctop.dptk.few 2b + br.ctop.dptk 2b ;; cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len -(p6) br.cond.dptk.few failure_in1bis +(p6) br.cond.dptk .failure_in1bis ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp -failure_in2: +.failure_in2: sub ret0=endsrc,src1 cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len -(p6) br.cond.dptk.few failure_in1bis +(p6) br.cond.dptk .failure_in1bis ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp // // handling of failures on stores: that's the easy part // -failure_out: +.failure_out: sub ret0=enddst,dst1 mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp END(__copy_user) diff --git a/arch/ia64/lib/do_csum.S b/arch/ia64/lib/do_csum.S index 628cb9053a62..398a2b933861 100644 --- a/arch/ia64/lib/do_csum.S +++ b/arch/ia64/lib/do_csum.S @@ -16,7 +16,6 @@ * back-to-back 8-byte words per loop. Clean up the initialization * for the loop. Support the cases where load latency = 1 or 2. * Set CONFIG_IA64_LOAD_LATENCY to 1 or 2 (default). - * */ #include @@ -130,7 +129,7 @@ GLOBAL_ENTRY(do_csum) ;; // avoid WAW on CFM mov tmp3=0x7 // a temporary mask/value add tmp1=buf,len // last byte's address -(p6) br.ret.spnt.few rp // return if true (hope we can avoid that) +(p6) br.ret.spnt.many rp // return if true (hope we can avoid that) and firstoff=7,buf // how many bytes off for first1 element tbit.nz p15,p0=buf,0 // is buf an odd address ? @@ -181,9 +180,9 @@ GLOBAL_ENTRY(do_csum) cmp.ltu p6,p0=result1[0],word1[0] // check the carry ;; (p6) adds result1[0]=1,result1[0] -(p8) br.cond.dptk.few do_csum_exit // if (within an 8-byte word) +(p8) br.cond.dptk .do_csum_exit // if (within an 8-byte word) ;; -(p11) br.cond.dptk.few do_csum16 // if (count is even) +(p11) br.cond.dptk .do_csum16 // if (count is even) ;; // Here count is odd. ld8 word1[1]=[first1],8 // load an 8-byte word @@ -196,14 +195,14 @@ GLOBAL_ENTRY(do_csum) ;; (p6) adds result1[0]=1,result1[0] ;; -(p9) br.cond.sptk.few do_csum_exit // if (count == 1) exit +(p9) br.cond.sptk .do_csum_exit // if (count == 1) exit // Fall through to caluculate the checksum, feeding result1[0] as // the initial value in result1[0]. ;; // // Calculate the checksum loading two 8-byte words per loop. // -do_csum16: +.do_csum16: mov saved_lc=ar.lc shr.u count=count,1 // we do 16 bytes per loop ;; @@ -225,7 +224,7 @@ do_csum16: ;; add first2=8,first1 ;; -(p9) br.cond.sptk.few do_csum_exit +(p9) br.cond.sptk .do_csum_exit ;; nop.m 0 nop.i 0 @@ -241,7 +240,7 @@ do_csum16: 2: (p16) ld8 word1[0]=[first1],16 (p16) ld8 word2[0]=[first2],16 - br.ctop.sptk.few 1b + br.ctop.sptk 1b ;; // Since len is a 32-bit value, carry cannot be larger than // a 64-bit value. @@ -263,7 +262,7 @@ do_csum16: ;; (p6) adds result1[0]=1,result1[0] ;; -do_csum_exit: +.do_csum_exit: movl tmp3=0xffffffff ;; // XXX Fixme @@ -299,7 +298,7 @@ do_csum_exit: ;; mov ar.lc=saved_lc (p15) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes - br.ret.sptk.few rp + br.ret.sptk.many rp // I (Jun Nakajima) wrote an equivalent code (see below), but it was // not much better than the original. So keep the original there so that @@ -331,6 +330,6 @@ do_csum_exit: //(p15) mux1 ret0=ret0,@rev // reverse word // ;; //(p15) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes -// br.ret.sptk.few rp +// br.ret.sptk.many rp END(do_csum) diff --git a/arch/ia64/lib/idiv32.S b/arch/ia64/lib/idiv32.S index 13f4608c3571..2ac28bf0a662 100644 --- a/arch/ia64/lib/idiv32.S +++ b/arch/ia64/lib/idiv32.S @@ -79,5 +79,5 @@ GLOBAL_ENTRY(NAME) ;; #endif getf.sig r8 = f6 // transfer result to result register - br.ret.sptk rp + br.ret.sptk.many rp END(NAME) diff --git a/arch/ia64/lib/idiv64.S b/arch/ia64/lib/idiv64.S index 3dbd96c4416c..404ebeca6655 100644 --- a/arch/ia64/lib/idiv64.S +++ b/arch/ia64/lib/idiv64.S @@ -89,5 +89,5 @@ GLOBAL_ENTRY(NAME) #endif getf.sig r8 = f17 // transfer result to result register ldf.fill f17 = [sp] - br.ret.sptk rp + br.ret.sptk.many rp END(NAME) diff --git a/arch/ia64/lib/memcpy.S b/arch/ia64/lib/memcpy.S index 7307df43b697..1a2fce766839 100644 --- a/arch/ia64/lib/memcpy.S +++ b/arch/ia64/lib/memcpy.S @@ -9,20 +9,14 @@ * Output: * no return value * - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 Stephane Eranian - * Copyright (C) 2000 David Mosberger-Tang + * Copyright (C) 2000-2001 Hewlett-Packard Co + * Stephane Eranian + * David Mosberger-Tang */ #include #include -#if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) -# define BRP(args...) nop.b 0 -#else -# define BRP(args...) brp.loop.imp args -#endif - GLOBAL_ENTRY(bcopy) .regstk 3,0,0,0 mov r8=in0 @@ -103,8 +97,8 @@ GLOBAL_ENTRY(memcpy) cmp.ne p6,p0=t0,r0 mov src=in1 // copy because of rotation -(p7) br.cond.spnt.few memcpy_short -(p6) br.cond.spnt.few memcpy_long +(p7) br.cond.spnt.few .memcpy_short +(p6) br.cond.spnt.few .memcpy_long ;; nop.m 0 ;; @@ -119,7 +113,7 @@ GLOBAL_ENTRY(memcpy) 1: { .mib (p[0]) ld8 val[0]=[src],8 nop.i 0 - BRP(1b, 2f) + brp.loop.imp 1b, 2f } 2: { .mfb (p[N-1])st8 [dst]=val[N-1],8 @@ -139,14 +133,14 @@ GLOBAL_ENTRY(memcpy) * issues, we want to avoid read-modify-write of entire words. */ .align 32 -memcpy_short: +.memcpy_short: adds cnt=-1,in2 // br.ctop is repeat/until mov ar.ec=MEM_LAT - BRP(1f, 2f) + brp.loop.imp 1f, 2f ;; mov ar.lc=cnt ;; - nop.m 0 + nop.m 0 ;; nop.m 0 nop.i 0 @@ -163,7 +157,7 @@ memcpy_short: 1: { .mib (p[0]) ld1 val[0]=[src],1 nop.i 0 - BRP(1b, 2f) + brp.loop.imp 1b, 2f } ;; 2: { .mfb (p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1 @@ -202,7 +196,7 @@ memcpy_short: #define LOG_LOOP_SIZE 6 -memcpy_long: +.memcpy_long: alloc t3=ar.pfs,3,Nrot,0,Nrot // resize register frame and t0=-8,src // t0 = src & ~7 and t2=7,src // t2 = src & 7 @@ -247,7 +241,7 @@ memcpy_long: mov t4=ip } ;; and src2=-8,src // align source pointer - adds t4=memcpy_loops-1b,t4 + adds t4=.memcpy_loops-1b,t4 mov ar.ec=N and t0=7,src // t0 = src & 7 @@ -266,7 +260,7 @@ memcpy_long: mov pr=cnt,0x38 // set (p5,p4,p3) to # of bytes last-word bytes to copy mov ar.lc=t2 ;; - nop.m 0 + nop.m 0 ;; nop.m 0 nop.i 0 @@ -278,7 +272,7 @@ memcpy_long: br.sptk.few b6 ;; -memcpy_tail: +.memcpy_tail: // At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is // less than 8) and t0 contains the last few bytes of the src buffer: (p5) st4 [dst]=t0,4 @@ -300,7 +294,7 @@ memcpy_tail: 1: { .mib \ (p[0]) ld8 val[0]=[src2],8; \ (p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift; \ - BRP(1b, 2f) \ + brp.loop.imp 1b, 2f \ }; \ 2: { .mfb \ (p[MEM_LAT+4]) st8 [dst]=w[1],8; \ @@ -311,8 +305,8 @@ memcpy_tail: ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */ \ ;; \ shrp t0=val[N-1],val[N-index],shift; \ - br memcpy_tail -memcpy_loops: + br .memcpy_tail +.memcpy_loops: COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */ COPY(8, 0) COPY(16, 0) diff --git a/arch/ia64/lib/memset.S b/arch/ia64/lib/memset.S index a7b8bdc38d11..00806c1bd1c9 100644 --- a/arch/ia64/lib/memset.S +++ b/arch/ia64/lib/memset.S @@ -43,11 +43,11 @@ GLOBAL_ENTRY(memset) adds tmp=-1,len // br.ctop is repeat/until tbit.nz p6,p0=buf,0 // odd alignment -(p8) br.ret.spnt.few rp +(p8) br.ret.spnt.many rp cmp.lt p7,p0=16,len // if len > 16 then long memset mux1 val=val,@brcst // prepare value -(p7) br.cond.dptk.few long_memset +(p7) br.cond.dptk .long_memset ;; mov ar.lc=tmp // initialize lc for small count ;; // avoid RAW and WAW on ar.lc @@ -57,11 +57,11 @@ GLOBAL_ENTRY(memset) ;; // avoid RAW on ar.lc mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.sptk.few rp // end of short memset + br.ret.sptk.many rp // end of short memset // at this point we know we have more than 16 bytes to copy // so we focus on alignment -long_memset: +.long_memset: (p6) st1 [buf]=val,1 // 1-byte aligned (p6) adds len=-1,len;; // sync because buf is modified tbit.nz p6,p0=buf,1 @@ -80,7 +80,7 @@ long_memset: ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt -(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left +(p6) br.cond.dpnt .dotail // we have less than 16 bytes left ;; adds buf2=8,buf // setup second base pointer mov ar.lc=tmp @@ -104,5 +104,5 @@ long_memset: mov ar.lc=saved_lc ;; (p6) st1 [buf]=val // only 1 byte left - br.ret.dptk.few rp + br.ret.sptk.many rp END(memset) diff --git a/arch/ia64/lib/strlen.S b/arch/ia64/lib/strlen.S index 16f0e8b5c70e..e0cdac0a85b8 100644 --- a/arch/ia64/lib/strlen.S +++ b/arch/ia64/lib/strlen.S @@ -11,7 +11,7 @@ * does not count the \0 * * Copyright (C) 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1999 Stephane Eranian + * Stephane Eranian * * 09/24/99 S.Eranian add speculation recovery code */ @@ -116,7 +116,7 @@ GLOBAL_ENTRY(strlen) ld8.s w[0]=[src],8 // speculatively load next to next cmp.eq.and p6,p0=8,val1 // p6 = p6 and val1==8 cmp.eq.and p6,p0=8,val2 // p6 = p6 and mask==8 -(p6) br.wtop.dptk.few 1b // loop until p6 == 0 +(p6) br.wtop.dptk 1b // loop until p6 == 0 ;; // // We must return try the recovery code iff @@ -127,14 +127,14 @@ GLOBAL_ENTRY(strlen) // cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) tnat.nz p6,p7=val1 // test NaT on val1 -(p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT +(p6) br.cond.spnt .recover // jump to recovery if val1 is NaT ;; // // if we come here p7 is true, i.e., initialized for // cmp // cmp.eq.and p7,p0=8,val1// val1==8? tnat.nz.and p7,p0=val2 // test NaT if val2 -(p7) br.cond.spnt.few recover// jump to recovery if val2 is NaT +(p7) br.cond.spnt .recover // jump to recovery if val2 is NaT ;; (p8) mov val1=val2 // the other test got us out of the loop (p8) adds src=-16,src // correct position when 3 ahead @@ -146,7 +146,7 @@ GLOBAL_ENTRY(strlen) ;; sub ret0=ret0,tmp // adjust mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of normal execution + br.ret.sptk.many rp // end of normal execution // // Outlined recovery code when speculation failed @@ -165,7 +165,7 @@ GLOBAL_ENTRY(strlen) // - today we restart from the beginning of the string instead // of trying to continue where we left off. // -recover: +.recover: ld8 val=[base],8 // will fail if unrecoverable fault ;; or val=val,mask // remask first bytes @@ -180,7 +180,7 @@ recover: czx1.r val1=val // search 0 byte from right ;; cmp.eq p6,p0=8,val1 // val1==8 ? -(p6) br.wtop.dptk.few 2b // loop until p6 == 0 +(p6) br.wtop.dptk 2b // loop until p6 == 0 ;; // (avoid WAW on p63) sub ret0=base,orig // distance from base sub tmp=8,val1 @@ -188,5 +188,5 @@ recover: ;; sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of successful recovery code + br.ret.sptk.many rp // end of successful recovery code END(strlen) diff --git a/arch/ia64/lib/strlen_user.S b/arch/ia64/lib/strlen_user.S index d4b9f878df91..c71eded4285e 100644 --- a/arch/ia64/lib/strlen_user.S +++ b/arch/ia64/lib/strlen_user.S @@ -8,8 +8,8 @@ * ret0 0 in case of fault, strlen(buffer)+1 otherwise * * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang - * Copyright (C) 1998, 1999 Stephane Eranian + * David Mosberger-Tang + * Stephane Eranian * * 01/19/99 S.Eranian heavily enhanced version (see details below) * 09/24/99 S.Eranian added speculation recovery code @@ -108,7 +108,7 @@ GLOBAL_ENTRY(__strlen_user) mov ar.ec=r0 // clear epilogue counter (saved in ar.pfs) ;; add base=-16,src // keep track of aligned base - chk.s v[1], recover // if already NaT, then directly skip to recover + chk.s v[1], .recover // if already NaT, then directly skip to recover or v[1]=v[1],mask // now we have a safe initial byte pattern ;; 1: @@ -130,14 +130,14 @@ GLOBAL_ENTRY(__strlen_user) // cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) tnat.nz p6,p7=val1 // test NaT on val1 -(p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT +(p6) br.cond.spnt .recover // jump to recovery if val1 is NaT ;; // // if we come here p7 is true, i.e., initialized for // cmp // cmp.eq.and p7,p0=8,val1// val1==8? tnat.nz.and p7,p0=val2 // test NaT if val2 -(p7) br.cond.spnt.few recover// jump to recovery if val2 is NaT +(p7) br.cond.spnt .recover // jump to recovery if val2 is NaT ;; (p8) mov val1=val2 // val2 contains the value (p8) adds src=-16,src // correct position when 3 ahead @@ -149,7 +149,7 @@ GLOBAL_ENTRY(__strlen_user) ;; sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of normal execution + br.ret.sptk.many rp // end of normal execution // // Outlined recovery code when speculation failed @@ -162,7 +162,7 @@ GLOBAL_ENTRY(__strlen_user) // - today we restart from the beginning of the string instead // of trying to continue where we left off. // -recover: +.recover: EX(.Lexit1, ld8 val=[base],8) // load the initial bytes ;; or val=val,mask // remask first bytes @@ -185,7 +185,7 @@ recover: ;; sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of successful recovery code + br.ret.sptk.many rp // end of successful recovery code // // We failed even on the normal load (called from exception handler) @@ -194,5 +194,5 @@ recover: mov ret0=0 mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp + br.ret.sptk.many rp END(__strlen_user) diff --git a/arch/ia64/lib/strncpy_from_user.S b/arch/ia64/lib/strncpy_from_user.S index 783341b3e3a4..a504381f31eb 100644 --- a/arch/ia64/lib/strncpy_from_user.S +++ b/arch/ia64/lib/strncpy_from_user.S @@ -40,5 +40,5 @@ GLOBAL_ENTRY(__strncpy_from_user) (p6) mov r8=in2 // buffer filled up---return buffer length (p7) sub r8=in1,r9,1 // return string length (excluding NUL character) [.Lexit:] - br.ret.sptk.few rp + br.ret.sptk.many rp END(__strncpy_from_user) diff --git a/arch/ia64/lib/strnlen_user.S b/arch/ia64/lib/strnlen_user.S index 66e701bc2a82..d09066b1e49d 100644 --- a/arch/ia64/lib/strnlen_user.S +++ b/arch/ia64/lib/strnlen_user.S @@ -33,7 +33,7 @@ GLOBAL_ENTRY(__strnlen_user) add r9=1,r9 ;; cmp.eq p6,p0=r8,r0 -(p6) br.dpnt.few .Lexit +(p6) br.cond.dpnt .Lexit br.cloop.dptk.few .Loop1 add r9=1,in1 // NUL not found---return N+1 @@ -41,5 +41,5 @@ GLOBAL_ENTRY(__strnlen_user) .Lexit: mov r8=r9 mov ar.lc=r16 // restore ar.lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(__strnlen_user) diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c index c67432bacc05..11d3f6112149 100644 --- a/arch/ia64/lib/swiotlb.c +++ b/arch/ia64/lib/swiotlb.c @@ -398,7 +398,7 @@ swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int d BUG(); for (i = 0; i < nelems; i++, sg++) { - sg->orig_address = sg->address; + sg->page = sg->address; if ((virt_to_phys(sg->address) & ~hwdev->dma_mask) != 0) { sg->address = map_single(hwdev, sg->address, sg->length, direction); } @@ -419,9 +419,9 @@ swiotlb_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int BUG(); for (i = 0; i < nelems; i++, sg++) - if (sg->orig_address != sg->address) { + if (sg->page != sg->address) { unmap_single(hwdev, sg->address, sg->length, direction); - sg->address = sg->orig_address; + sg->address = sg->page; } else if (direction == PCI_DMA_FROMDEVICE) mark_clean(sg->address, sg->length); } @@ -442,7 +442,7 @@ swiotlb_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int BUG(); for (i = 0; i < nelems; i++, sg++) - if (sg->orig_address != sg->address) + if (sg->page != sg->address) sync_single(hwdev, sg->address, sg->length, direction); } diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 6d15aac5e8eb..295962275889 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -1,8 +1,8 @@ /* * MMU fault handling support. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang */ #include #include @@ -16,7 +16,7 @@ #include #include -extern void die_if_kernel (char *, struct pt_regs *, long); +extern void die (char *, struct pt_regs *, long); /* * This routine is analogous to expand_stack() but instead grows the @@ -46,16 +46,15 @@ expand_backing_store (struct vm_area_struct *vma, unsigned long address) void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { + int signal = SIGSEGV, code = SEGV_MAPERR; + struct vm_area_struct *vma, *prev_vma; struct mm_struct *mm = current->mm; struct exception_fixup fix; - struct vm_area_struct *vma, *prev_vma; struct siginfo si; - int signal = SIGSEGV; unsigned long mask; /* - * If we're in an interrupt or have no user - * context, we must not take the fault.. + * If we're in an interrupt or have no user context, we must not take the fault.. */ if (in_interrupt() || !mm) goto no_context; @@ -71,6 +70,8 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re goto check_expansion; good_area: + code = SEGV_ACCERR; + /* OK, we've got a good vm_area for this memory area. Check the access permissions: */ # define VM_READ_BIT 0 @@ -89,12 +90,13 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re if ((vma->vm_flags & mask) != mask) goto bad_area; + survive: /* * If for any reason at all we couldn't handle the fault, make * sure we exit gracefully rather than endlessly redo the * fault. */ - switch (handle_mm_fault(mm, vma, address, mask) != 0) { + switch (handle_mm_fault(mm, vma, address, mask)) { case 1: ++current->min_flt; break; @@ -147,7 +149,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re if (user_mode(regs)) { si.si_signo = signal; si.si_errno = 0; - si.si_code = SI_KERNEL; + si.si_code = code; si.si_addr = (void *) address; force_sig_info(signal, &si, current); return; @@ -174,17 +176,29 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re } /* - * Oops. The kernel tried to access some bad page. We'll have - * to terminate things with extreme prejudice. + * Oops. The kernel tried to access some bad page. We'll have to terminate things + * with extreme prejudice. */ - printk(KERN_ALERT "Unable to handle kernel paging request at " - "virtual address %016lx\n", address); - die_if_kernel("Oops", regs, isr); + bust_spinlocks(1); + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request at " + "virtual address %016lx\n", address); + die("Oops", regs, isr); + bust_spinlocks(0); do_exit(SIGKILL); return; out_of_memory: up_read(&mm->mmap_sem); + if (current->pid == 1) { + current->policy |= SCHED_YIELD; + schedule(); + down_read(&mm->mmap_sem); + goto survive; + } printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 4e01b44c547b..29a6937dbc5e 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -167,13 +167,40 @@ si_meminfo (struct sysinfo *val) } void -show_mem (void) +show_mem(void) { int i, total = 0, reserved = 0; int shared = 0, cached = 0; printk("Mem-info:\n"); show_free_areas(); + +#ifdef CONFIG_DISCONTIGMEM + { + pg_data_t *pgdat = pgdat_list; + + printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + do { + printk("Node ID: %d\n", pgdat->node_id); + for(i = 0; i < pgdat->node_size; i++) { + if (PageReserved(pgdat->node_mem_map+i)) + reserved++; + else if (PageSwapCache(pgdat->node_mem_map+i)) + cached++; + else if (page_count(pgdat->node_mem_map + i)) + shared += page_count(pgdat->node_mem_map + i) - 1; + } + printk("\t%d pages of RAM\n", pgdat->node_size); + printk("\t%d reserved pages\n", reserved); + printk("\t%d pages shared\n", shared); + printk("\t%d pages swap cached\n", cached); + pgdat = pgdat->node_next; + } while (pgdat); + printk("Total of %ld pages in page table cache\n", pgtable_cache_size); + show_buffers(); + printk("%d free buffer pages\n", nr_free_buffer_pages()); + } +#else /* !CONFIG_DISCONTIGMEM */ printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); i = max_mapnr; while (i-- > 0) { @@ -191,6 +218,7 @@ show_mem (void) printk("%d pages swap cached\n", cached); printk("%ld pages in page table cache\n", pgtable_cache_size); show_buffers(); +#endif /* !CONFIG_DISCONTIGMEM */ } /* @@ -248,7 +276,7 @@ ia64_mmu_init (void *my_cpu_data) ia64_clear_ic(flags); rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); - ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (KERNEL_PG_SHIFT << 2)); + ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (IA64_GRANULE_SHIFT << 2)); rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index 8eb07ab94739..d6e04201709f 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -2,7 +2,7 @@ * TLB support routines. * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang + * David Mosberger-Tang * * 08/02/00 A. Mallick * Modified RID allocation for SMP @@ -40,89 +40,6 @@ struct ia64_ctx ia64_ctx = { max_ctx: ~0U }; -/* - * Seralize usage of ptc.g - */ -spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see */ - -#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG) - -#include - -unsigned long flush_end, flush_start, flush_nbits, flush_rid; -atomic_t flush_cpu_count; - -/* - * flush_tlb_no_ptcg is called with ptcg_lock locked - */ -static inline void -flush_tlb_no_ptcg (unsigned long start, unsigned long end, unsigned long nbits) -{ - extern void smp_send_flush_tlb (void); - unsigned long saved_tpr = 0; - unsigned long flags; - - /* - * Some times this is called with interrupts disabled and causes - * dead-lock; to avoid this we enable interrupt and raise the TPR - * to enable ONLY IPI. - */ - __save_flags(flags); - if (!(flags & IA64_PSR_I)) { - saved_tpr = ia64_get_tpr(); - ia64_srlz_d(); - ia64_set_tpr(IA64_IPI_VECTOR - 16); - ia64_srlz_d(); - local_irq_enable(); - } - - spin_lock(&ptcg_lock); - flush_rid = ia64_get_rr(start); - ia64_srlz_d(); - flush_start = start; - flush_end = end; - flush_nbits = nbits; - atomic_set(&flush_cpu_count, smp_num_cpus - 1); - smp_send_flush_tlb(); - /* - * Purge local TLB entries. ALAT invalidation is done in ia64_leave_kernel. - */ - do { - asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - - ia64_srlz_i(); /* srlz.i implies srlz.d */ - - /* - * Wait for other CPUs to finish purging entries. - */ -#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) - { - extern void smp_resend_flush_tlb (void); - unsigned long start = ia64_get_itc(); - - while (atomic_read(&flush_cpu_count) > 0) { - if ((ia64_get_itc() - start) > 400000UL) { - smp_resend_flush_tlb(); - start = ia64_get_itc(); - } - } - } -#else - while (atomic_read(&flush_cpu_count)) { - /* Nothing */ - } -#endif - if (!(flags & IA64_PSR_I)) { - local_irq_disable(); - ia64_set_tpr(saved_tpr); - ia64_srlz_d(); - } -} - -#endif /* CONFIG_SMP && !CONFIG_ITANIUM_PTCG */ - /* * Acquire the ia64_ctx.lock before calling this function! */ @@ -162,6 +79,26 @@ wrap_mmu_context (struct mm_struct *mm) flush_tlb_all(); } +static inline void +ia64_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) +{ + static spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; + + /* HW requires global serialization of ptc.ga. */ + spin_lock(&ptcg_lock); + { + do { + /* + * Flush ALAT entries also. + */ + asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) + : "memory"); + start += (1UL << nbits); + } while (start < end); + } + spin_unlock(&ptcg_lock); +} + void __flush_tlb_all (void) { @@ -222,23 +159,15 @@ flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end) } start &= ~((1UL << nbits) - 1); -#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG) - flush_tlb_no_ptcg(start, end, nbits); -#else - spin_lock(&ptcg_lock); - do { # ifdef CONFIG_SMP - /* - * Flush ALAT entries also. - */ - asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) : "memory"); + platform_global_tlb_purge(start, end, nbits); # else + do { asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); -# endif start += (1UL << nbits); } while (start < end); -#endif /* CONFIG_SMP && !defined(CONFIG_ITANIUM_PTCG) */ - spin_unlock(&ptcg_lock); +# endif + ia64_insn_group_barrier(); ia64_srlz_i(); /* srlz.i implies srlz.d */ ia64_insn_group_barrier(); diff --git a/arch/ia64/sn/sn1/llsc4.c b/arch/ia64/sn/sn1/llsc4.c index b026c128b064..d58bf0305ec3 100644 --- a/arch/ia64/sn/sn1/llsc4.c +++ b/arch/ia64/sn/sn1/llsc4.c @@ -35,16 +35,6 @@ extern void bringup_set_led_bits(u8 bits, u8 mask); static int inttest=0; #endif -#ifdef IA64_SEMFIX_INSN -#undef IA64_SEMFIX_INSN -#endif -#ifdef IA64_SEMFIX -#undef IA64_SEMFIX -#endif -# define IA64_SEMFIX_INSN -# define IA64_SEMFIX "" - - /* * Test parameter table for AUTOTEST */ @@ -192,7 +182,6 @@ static void print_params(void) printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); - printk (" SEMFIX: %s\n", IA64_SEMFIX); printk ("\n"); } __setup("autotest", autotest_enable); diff --git a/arch/ia64/tools/print_offsets.c b/arch/ia64/tools/print_offsets.c index 140611cd1e73..29f733241595 100644 --- a/arch/ia64/tools/print_offsets.c +++ b/arch/ia64/tools/print_offsets.c @@ -57,11 +57,8 @@ tab[] = { "IA64_TASK_PROCESSOR_OFFSET", offsetof (struct task_struct, processor) }, { "IA64_TASK_THREAD_OFFSET", offsetof (struct task_struct, thread) }, { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, -#ifdef CONFIG_IA32_SUPPORT - { "IA64_TASK_THREAD_SIGMASK_OFFSET",offsetof (struct task_struct, thread.un.sigmask) }, -#endif #ifdef CONFIG_PERFMON - { "IA64_TASK_PFM_NOTIFY_OFFSET", offsetof(struct task_struct, thread.pfm_pend_notify) }, + { "IA64_TASK_PFM_MUST_BLOCK_OFFSET",offsetof(struct task_struct, thread.pfm_must_block) }, #endif { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, { "IA64_TASK_MM_OFFSET", offsetof (struct task_struct, mm) }, @@ -165,17 +162,18 @@ tab[] = { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, { "IA64_SIGCONTEXT_PR_OFFSET", offsetof (struct sigcontext, sc_pr) }, { "IA64_SIGCONTEXT_R12_OFFSET", offsetof (struct sigcontext, sc_gr[12]) }, + { "IA64_SIGCONTEXT_RBS_BASE_OFFSET",offsetof (struct sigcontext, sc_rbs_base) }, + { "IA64_SIGCONTEXT_LOADRS_OFFSET", offsetof (struct sigcontext, sc_loadrs) }, { "IA64_SIGFRAME_ARG0_OFFSET", offsetof (struct sigframe, arg0) }, { "IA64_SIGFRAME_ARG1_OFFSET", offsetof (struct sigframe, arg1) }, { "IA64_SIGFRAME_ARG2_OFFSET", offsetof (struct sigframe, arg2) }, - { "IA64_SIGFRAME_RBS_BASE_OFFSET", offsetof (struct sigframe, rbs_base) }, { "IA64_SIGFRAME_HANDLER_OFFSET", offsetof (struct sigframe, handler) }, { "IA64_SIGFRAME_SIGCONTEXT_OFFSET", offsetof (struct sigframe, sc) }, { "IA64_CLONE_VFORK", CLONE_VFORK }, { "IA64_CLONE_VM", CLONE_VM }, { "IA64_CPU_IRQ_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.irq_count) }, { "IA64_CPU_BH_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.bh_count) }, - { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET", offsetof (struct cpuinfo_ia64, phys_stacked_size_p8) }, + { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET",offsetof (struct cpuinfo_ia64, phys_stacked_size_p8)}, }; static const char *tabs = "\t\t\t\t\t\t\t\t\t\t"; diff --git a/arch/s390/config.in b/arch/s390/config.in index 9ff9efb2cba4..c545c3614420 100644 --- a/arch/s390/config.in +++ b/arch/s390/config.in @@ -9,6 +9,7 @@ define_bool CONFIG_MCA n define_bool CONFIG_UID16 y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n +define_bool CONFIG_GENERIC_BUST_SPINLOCK n mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_ARCH_S390 y diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 14c29b19088c..6d2b7366df1b 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -7,6 +7,7 @@ CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_BUST_SPINLOCK=n CONFIG_ARCH_S390=y # @@ -72,6 +73,7 @@ CONFIG_BLK_DEV_MD=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID5=m +# CONFIG_MD_MULTIPATH is not set CONFIG_BLK_DEV_LVM=m # @@ -183,19 +185,25 @@ CONFIG_IPV6=m # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_CMS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set +# CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -218,6 +226,7 @@ CONFIG_EXT2_FS=y # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -235,6 +244,8 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -247,6 +258,7 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_IBM_PARTITION=y # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index f4beccc08941..bc4535cf737a 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -256,9 +256,17 @@ sysc_signal_return: # sysc_tracesys: l %r1,BASED(.Ltrace) - l %r2,BASED(.Lc_ENOSYS) - st %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval + l %r7,BASED(.Lc_ENOSYS) + st %r7,SP_R2(%r15) # give sysc_trace an -ENOSYS retval basr %r14,%r1 + l %r2,SP_R2(%r15) + cr %r2,%r7 # compare with saved -ENOSYS + be BASED(sysc_tracesys_dn1) + # strace wants to change the syscall + sll %r2,24 + srl %r2,22 + l %r8,sys_call_table-entry_base(2,%r13) # get address of system call +sysc_tracesys_dn1: lm %r3,%r6,SP_R3(%r15) l %r2,SP_ORIG_R2(%r15) basr %r14,%r8 # call sys_xxx @@ -689,10 +697,7 @@ pgm_no_sv: l %r5,SP_PSW+4(15) # load psw addr sr %r5,%r7 # substract ilc from psw st %r5,SP_PSW+4(15) # store corrected psw addr -pgm_per:cl %r3,BASED(.Lc20) # pseudo page fault ? - be BASED(pgm_go) # if yes then don't reenable interrupts - stosm 24(%r15),0x03 # reenable interrupts -pgm_go: basr %r14,%r1 # branch to interrupt-handler +pgm_per:basr %r14,%r1 # branch to interrupt-handler pgm_dn: n %r8,BASED(.Lc128) # check for per excepton be BASED(pgm_return) la %r2,SP_PTREGS(15) # address of register-save area diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 21f035d4195d..656178e3b6b3 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -338,12 +338,12 @@ iplstart: # reset files in VM reader # stidp __LC_CPUID # store cpuid - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on P/390 ? - be start # no -> skip reset + tm __LC_CPUID,0xff # running VM ? + bno .Lnoreset la %r2,.Lreset lhi %r3,26 .long 0x83230008 +.Lnoreset: #endif # diff --git a/arch/s390/kernel/init_task.c b/arch/s390/kernel/init_task.c index 630264ab0e91..3e2600776631 100644 --- a/arch/s390/kernel/init_task.c +++ b/arch/s390/kernel/init_task.c @@ -12,6 +12,7 @@ #include #include +static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 3cc63c67f509..617db282d550 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -59,4 +59,3 @@ EXPORT_SYMBOL(console_device); EXPORT_SYMBOL_NOVERS(do_call_softirq); - diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 4bffad069c04..e5b83c653f81 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -94,8 +94,16 @@ asmlinkage void name(struct pt_regs * regs, long interruption_code) \ static void inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) { + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (regs->psw.mask & PSW_PROBLEM_STATE) { struct task_struct *tsk = current; + tsk->thread.trap_no = interruption_code; if (info) force_sig_info(signr, info, tsk); @@ -160,20 +168,27 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) __u8 opcode[6]; __u16 *location; int signal = 0; - int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); - if(problem_state) + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + + if (regs->psw.mask & PSW_PROBLEM_STATE) get_user(*((__u16 *) opcode), location); else *((__u16 *)opcode)=*((__u16 *)location); - if(*((__u16 *)opcode)==S390_BREAKPOINT_U16) + if (*((__u16 *)opcode)==S390_BREAKPOINT_U16) { if(do_debugger_trap(regs,SIGTRAP)) signal = SIGILL; } #ifdef CONFIG_MATHEMU - else if (problem_state) + else if (regs->psw.mask & PSW_PROBLEM_STATE) { if (opcode[0] == 0xb3) { get_user(*((__u16 *) (opcode+2)), location+1); @@ -216,8 +231,16 @@ specification_exception(struct pt_regs * regs, long interruption_code) __u16 *location = NULL; int signal = 0; + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (regs->psw.mask & PSW_PROBLEM_STATE) { - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ @@ -267,6 +290,14 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) int signal = 0; location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (MACHINE_HAS_IEEE) __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index e19c7897356e..896fa2526a7b 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -159,14 +159,17 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) /* * Check whether we have a user MM in the first place. */ - if (in_interrupt() || !mm) + if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT)) goto no_context; /* * When we get here, the fault happened in the current - * task's user address space, so we search the VMAs + * task's user address space, so we can switch on the + * interrupts again and then search the VMAs */ + __sti(); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); @@ -415,7 +418,11 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code) " la 2,0(%0)\n" " sacf 512\n" " ic 2,0(2)\n" - " sacf 0" + "0:sacf 0\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,0b\n" + ".previous" : : "a" (address) : "2" ); return; @@ -513,7 +520,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code) * external interrupt. */ subcode = S390_lowcore.cpu_addr; - if ((subcode & 0xff00) != 0x0600) + if ((subcode & 0xff00) != 0x0200) return; /* @@ -522,6 +529,13 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code) tsk = (struct task_struct *) (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE); + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (subcode & 0x0080) { /* signal bit is set -> a page has been swapped in by VM */ qp = (wait_queue_head_t *) diff --git a/arch/s390x/defconfig b/arch/s390x/defconfig index eaffc7492c42..ecc6f7af6dda 100644 --- a/arch/s390x/defconfig +++ b/arch/s390x/defconfig @@ -185,19 +185,25 @@ CONFIG_IPV6=m # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_CMS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set +# CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -220,6 +226,7 @@ CONFIG_EXT2_FS=y # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -237,6 +244,8 @@ CONFIG_LOCKD=y # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types diff --git a/arch/s390x/kernel/entry.S b/arch/s390x/kernel/entry.S index 16006eda0435..567bff52719f 100644 --- a/arch/s390x/kernel/entry.S +++ b/arch/s390x/kernel/entry.S @@ -247,6 +247,17 @@ sysc_tracesys: lghi %r2,-ENOSYS stg %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval brasl %r14,syscall_trace + lg %r2,SP_R2(%r15) + cghi %r2,-ENOSYS + je sysc_tracesys_dn1 + sllg %r2,%r2,56 # strace wants to change the syscall + srlg %r2,%r2,53 # zap unused bits & multiply by 8 + tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ? + jo sysc_tracesys_noemu + la %r2,4(%r2) # use 31 bit emulation system calls +sysc_tracesys_noemu: + lgf %r8,0(%r2,%r7) # load address of system call routine +sysc_tracesys_dn1: lmg %r3,%r6,SP_R3(%r15) lg %r2,SP_ORIG_R2(%r15) basr %r14,%r8 # call sys_xxx @@ -672,7 +683,6 @@ pgm_sv: GET_CURRENT pgm_no_sv: llgh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it - stosm 48(%r15),0x03 # reenable interrupts lghi %r3,0x7f nr %r3,%r8 # clear per-event-bit & move to r3 je pgm_dn # none of Martins exceptions occurred bypass diff --git a/arch/s390x/kernel/head.S b/arch/s390x/kernel/head.S index 189f48803264..7b88e62a99e3 100644 --- a/arch/s390x/kernel/head.S +++ b/arch/s390x/kernel/head.S @@ -337,12 +337,12 @@ iplstart: # reset files in VM reader # stidp __LC_CPUID # store cpuid - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on P/390 ? - be start # no -> skip reset + tm __LC_CPUID,0xff # running VM ? + bno .Lnoreset la %r2,.Lreset lhi %r3,26 .long 0x83230008 +.Lnoreset: #endif # diff --git a/arch/s390x/kernel/init_task.c b/arch/s390x/kernel/init_task.c index 39d3825fd6d2..74cf730b0fc8 100644 --- a/arch/s390x/kernel/init_task.c +++ b/arch/s390x/kernel/init_task.c @@ -12,6 +12,7 @@ #include #include +static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; diff --git a/arch/s390x/kernel/traps.c b/arch/s390x/kernel/traps.c index 3eaed7e25f24..a475d4d44415 100644 --- a/arch/s390x/kernel/traps.c +++ b/arch/s390x/kernel/traps.c @@ -92,6 +92,13 @@ asmlinkage void name(struct pt_regs * regs, long interruption_code) \ static void inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) { + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (regs->psw.mask & PSW_PROBLEM_STATE) { struct task_struct *tsk = current; tsk->thread.trap_no = interruption_code; @@ -161,6 +168,14 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) int do_sig = 0; location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + /* WARNING don't change this check back to */ /* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */ /* & then doing if(problem_state) an int is too small for this */ @@ -186,6 +201,14 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) int do_sig = 0; location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); /* Same code should work when we implement fpu emulation */ diff --git a/arch/s390x/kernel/wrapper32.S b/arch/s390x/kernel/wrapper32.S index 38576550a5ce..a11ee19b21ff 100644 --- a/arch/s390x/kernel/wrapper32.S +++ b/arch/s390x/kernel/wrapper32.S @@ -629,8 +629,10 @@ sys32_setfsgid16_wrapper: .globl sys32_llseek_wrapper sys32_llseek_wrapper: llgfr %r2,%r2 # unsigned int - lgfr %r3,%r3 # off_t - llgfr %r4,%r4 # unsigned int + llgfr %r3,%r3 # unsigned long + llgfr %r4,%r4 # unsigned long + llgtr %r5,%r5 # loff_t * + llgfr %r6,%r6 # unsigned int jg sys_llseek # branch to system call .globl sys32_getdents_wrapper diff --git a/arch/s390x/mm/fault.c b/arch/s390x/mm/fault.c index c4f0180e611d..2569b9af182e 100644 --- a/arch/s390x/mm/fault.c +++ b/arch/s390x/mm/fault.c @@ -159,14 +159,17 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) /* * Check whether we have a user MM in the first place. */ - if (in_interrupt() || !mm) + if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT)) goto no_context; /* * When we get here, the fault happened in the current - * task's user address space, so we search the VMAs + * task's user address space, so we can switch on the + * interrupts again and then search the VMAs */ + __sti(); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); @@ -420,6 +423,13 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code) tsk = (struct task_struct *) (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE); + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (subcode & 0x0080) { /* signal bit is set -> a page has been swapped in by VM */ qp = (wait_queue_head_t *) diff --git a/arch/s390x/mm/init.c b/arch/s390x/mm/init.c index b6675a3dfce9..a9a4a75e7b8a 100644 --- a/arch/s390x/mm/init.c +++ b/arch/s390x/mm/init.c @@ -59,7 +59,7 @@ int do_check_pgt_cache(int low, int high) } if(pte_quicklist) { pte_free_slow(pte_alloc_one_fast(NULL, 0)); - freed += 4; + freed += 1; } } while(pgtable_cache_size > low); } diff --git a/drivers/acpi/os.c b/drivers/acpi/os.c index a1c2b6562583..6dbcbbbe8b81 100644 --- a/drivers/acpi/os.c +++ b/drivers/acpi/os.c @@ -189,11 +189,6 @@ acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, u32 size, void **virt) return AE_ERROR; } - if ((unsigned long) phys < virt_to_phys(high_memory)) { - *virt = phys_to_virt((unsigned long) phys); - return AE_OK; - } - *virt = ioremap((unsigned long) phys, size); if (!*virt) return AE_ERROR; @@ -204,8 +199,7 @@ acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, u32 size, void **virt) void acpi_os_unmap_memory(void *virt, u32 size) { - if (virt >= high_memory) - iounmap(virt); + iounmap(virt); } acpi_status diff --git a/drivers/acpi/ospm/processor/pr_osl.c b/drivers/acpi/ospm/processor/pr_osl.c index 7c7cf61ae1f9..36d6c984bec5 100644 --- a/drivers/acpi/ospm/processor/pr_osl.c +++ b/drivers/acpi/ospm/processor/pr_osl.c @@ -143,7 +143,7 @@ pr_osl_add_device( PR_CONTEXT *processor) { u32 i = 0; - struct proc_dir_entry *proc_entry = NULL; + struct proc_dir_entry *proc_entry = NULL, *proc; char processor_uid[16]; if (!processor) { @@ -165,15 +165,18 @@ pr_osl_add_device( sprintf(processor_uid, "%d", processor->uid); proc_entry = proc_mkdir(processor_uid, pr_proc_root); - if (!proc_entry) { + if (!proc_entry) return(AE_ERROR); - } - create_proc_read_entry(PR_PROC_STATUS, S_IFREG | S_IRUGO, - proc_entry, pr_osl_proc_read_status, (void*)processor); + proc = create_proc_read_entry(PR_PROC_STATUS, S_IFREG | S_IRUGO, + proc_entry, pr_osl_proc_read_status, (void*)processor); + if (!proc_entry) + return(AE_ERROR); - create_proc_read_entry(PR_PROC_INFO, S_IFREG | S_IRUGO, - proc_entry, pr_osl_proc_read_info, (void*)processor); + proc = create_proc_read_entry(PR_PROC_INFO, S_IFREG | S_IRUGO, + proc_entry, pr_osl_proc_read_info, (void*)processor); + if (!proc_entry) + return(AE_ERROR); return(AE_OK); } diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 8c048e78cdc6..9ca723bb68a2 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -2266,7 +2266,7 @@ static int __devinit eni_init_one(struct pci_dev *pci_dev, } dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL); if (!dev) goto out2; - pci_dev->driver_data = dev; + pci_set_drvdata(pci_dev, dev); eni_dev->pci_dev = pci_dev; ENI_DEV(dev) = eni_dev; eni_dev->asic = ent->driver_data; diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 3e93450f1131..a6a9046dea8d 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -912,6 +912,9 @@ static int fs_open(struct atm_vcc *atm_vcc, short vpi, int vci) if (IS_FS50(dev)) { /* Increment the channel numer: take a free one next time. */ for (to=33;to;to--, dev->channo++) { + /* We only have 32 channels */ + if (dev->channo >= 32) + dev->channo = 0; /* If we need to do RX, AND the RX is inuse, try the next */ if (DO_DIRECTION(rxtp) && dev->atm_vccs[dev->channo]) continue; @@ -1226,7 +1229,7 @@ static int fs_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) { func_enter (); func_exit (); - return 0; + return -ENOIOCTLCMD; } diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index ecd28150c792..4975d1b2c0c8 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -1134,14 +1134,8 @@ static int acsi_ioctl( struct inode *inode, struct file *file, put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id ); return 0; - case BLKGETSIZE: /* Return device size */ - return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects, - (unsigned long *) arg); - - case BLKGETSIZE64: /* Return device size */ - return put_user((u64)acsi_part[MINOR(inode->i_rdev)].nr_sects << 9, - (u64 *) arg); - + case BLKGETSIZE: + case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKFLSBUF: diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index f4ee23751ff3..9f9f2aee381d 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1307,6 +1307,8 @@ queue_next: if (( c = cmd_alloc(h, 1)) == NULL) goto startio; + blkdev_dequeue_request(creq); + spin_unlock_irq(&io_request_lock); c->cmd_type = CMD_RWREQ; @@ -1386,12 +1388,6 @@ queue_next: spin_lock_irq(&io_request_lock); - blkdev_dequeue_request(creq); - - /* - * ehh, we can't really end the request here since it's not - * even started yet. for now it shouldn't hurt though - */ addQ(&(h->reqQ),c); h->Qdepth++; if(h->Qdepth > h->maxQsinceinit) @@ -1928,7 +1924,7 @@ static int __init cciss_init_one(struct pci_dev *pdev, /* Initialize the pdev driver private data. have it point to hba[i]. */ - pdev->driver_data = hba[i]; + pci_set_drvdata(pdev, hba[i]); /* command and error info recs zeroed out before they are used */ memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32)); @@ -1987,12 +1983,12 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) ctlr_info_t *tmp_ptr; int i; - if (pdev->driver_data == NULL) + if (pci_get_drvdata(pdev) == NULL) { printk( KERN_ERR "cciss: Unable to remove device \n"); return; } - tmp_ptr = (ctlr_info_t *) pdev->driver_data; + tmp_ptr = pci_get_drvdata(pdev); i = tmp_ptr->ctlr; if (hba[i] == NULL) { @@ -2003,7 +1999,7 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) /* Turn board interrupts off */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); free_irq(hba[i]->intr, hba[i]); - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); iounmap((void*)hba[i]->vaddr); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 9f03363f6b4d..da76b0bc74f7 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -942,6 +942,8 @@ queue_next: if ((c = cmd_alloc(h,1)) == NULL) goto startio; + blkdev_dequeue_request(creq); + spin_unlock_irq(&io_request_lock); bh = creq->bh; @@ -987,14 +989,11 @@ DBGPX( DBGPX( printk("Submitting %d sectors in %d segments\n", sect, seg); ); c->req.hdr.sg_cnt = seg; c->req.hdr.blk_cnt = creq->nr_sectors; - - spin_lock_irq(&io_request_lock); - - blkdev_dequeue_request(creq); - c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE; c->type = CMD_RWREQ; + spin_lock_irq(&io_request_lock); + /* Put the request on the tail of the request queue */ addQ(&h->reqQ, c); h->Qdepth++; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index d45700a2b9b8..fe541d5c57d5 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -186,6 +186,8 @@ static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize, data = bh->b_data; while (len > 0) { int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize; + int transfer_result; + size = PAGE_CACHE_SIZE - offset; if (size > len) size = len; @@ -197,10 +199,19 @@ static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize, goto unlock; kaddr = page_address(page); flush_dcache_page(page); - if (lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV)) - goto write_fail; + transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV); + if (transfer_result) { + /* + * The transfer failed, but we still write the data to + * keep prepare/commit calls balanced. + */ + printk(KERN_ERR "loop: transfer error block %ld\n", index); + memset(kaddr + offset, 0, size); + } if (aops->commit_write(file, page, offset, offset+size)) goto unlock; + if (transfer_result) + goto unlock; data += size; len -= size; offset = 0; @@ -211,10 +222,6 @@ static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize, } return 0; -write_fail: - printk(KERN_ERR "loop: transfer error block %ld\n", index); - ClearPageUptodate(page); - kunmap(page); unlock: UnlockPage(page); page_cache_release(page); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index b970c7df0e73..740bc08eb9d3 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -475,18 +475,12 @@ static int pd_ioctl(struct inode *inode,struct file *file, } put_user(pd_hd[dev].start_sect,(long *)&geo->start); return 0; - case BLKGETSIZE: - if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE,(unsigned long *) arg,sizeof(unsigned long)); - if (err) return (err); - put_user(pd_hd[dev].nr_sects,(unsigned long *) arg); - return (0); - case BLKGETSIZE64: - return put_user((u64)pd_hd[dev].nr_sects << 9, (u64 *)arg); case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return pd_revalidate(inode->i_rdev); + case BLKGETSIZE: + case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKRASET: diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 2cf36fdbdc2b..bbb8e682b7ce 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -1107,24 +1107,13 @@ static int ps2esdi_ioctl(struct inode *inode, } break; - case BLKGETSIZE: - if (arg) { - if ((err = verify_area(VERIFY_WRITE, (unsigned long *) arg, sizeof(unsigned long)))) - return (err); - put_user(ps2esdi[MINOR(inode->i_rdev)].nr_sects, (unsigned long *) arg); - - return (0); - } - break; - - case BLKGETSIZE64: - return put_user((u64)ps2esdi[MINOR(inode->i_rdev)].nr_sects << 9, (u64 *) arg); - case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return (ps2esdi_reread_partitions(inode->i_rdev)); + case BLKGETSIZE: + case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKRASET: diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 4cdaa8893b6a..7263e3b0ef7a 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -809,9 +809,6 @@ int swim3_fd_eject(int devnum); static void __init rd_load_disk(int n) { -#ifdef CONFIG_BLK_DEV_INITRD - extern kdev_t real_root_dev; -#endif if (rd_doload == 0) return; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 5ebc0434ce47..43d856343268 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -332,11 +332,6 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) g.start = xd_struct[MINOR(inode->i_rdev)].start_sect; return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } - case BLKGETSIZE: - if (!arg) return -EINVAL; - return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(unsigned long *) arg); - case BLKGETSIZE64: - return put_user((u64)xd_struct[MINOR(inode->i_rdev)].nr_sects << 9, (u64 *)arg); case HDIO_SET_DMA: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; @@ -355,6 +350,8 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) return -EACCES; return xd_reread_partitions(inode->i_rdev); + case BLKGETSIZE: + case BLKGETSIZE64: case BLKFLSBUF: case BLKROSET: case BLKROGET: diff --git a/drivers/char/acpi_serial.c b/drivers/char/acpi_serial.c new file mode 100644 index 000000000000..b1bf421d4760 --- /dev/null +++ b/drivers/char/acpi_serial.c @@ -0,0 +1,194 @@ +/* + * linux/drivers/char/acpi_serial.c + * + * Copyright (C) 2000 Hewlett-Packard Co. + * Copyright (C) 2000 Khalid Aziz + * + * Detect and initialize the headless console serial port defined in + * SPCR table and debug serial port defined in DBGP table + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include */ + +#undef SERIAL_DEBUG_ACPI + +/* + * Query ACPI tables for a debug and a headless console serial + * port. If found, add them to rs_table[]. A pointer to either SPCR + * or DBGP table is passed as parameter. This function should be called + * before serial_console_init() is called to make sure the SPCR serial + * console will be available for use. IA-64 kernel calls this function + * from within acpi.c when it encounters SPCR or DBGP tables as it parses + * the ACPI 2.0 tables during bootup. + * + */ +void __init setup_serial_acpi(void *tablep) +{ + acpi_ser_t *acpi_ser_p; + struct serial_struct serial_req; + unsigned long iobase; + int global_sys_irq; + +#ifdef SERIAL_DEBUG_ACPI + printk("Entering setup_serial_acpi()\n"); +#endif + + /* Now get the table */ + if (tablep == NULL) { + return; + } + + acpi_ser_p = (acpi_ser_t *)tablep; + + /* + * Perform a sanity check on the table. Table should have a + * signature of "SPCR" or "DBGP" and it should be atleast 52 bytes + * long. + */ + if ((strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, + ACPI_SIG_LEN) != 0) && + (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, + ACPI_SIG_LEN) != 0)) { + return; + } + if (acpi_ser_p->length < 52) { + return; + } + + iobase = (((u64) acpi_ser_p->base_addr.addrh) << 32) | acpi_ser_p->base_addr.addrl; + global_sys_irq = (acpi_ser_p->global_int[3] << 24) | + (acpi_ser_p->global_int[2] << 16) | + (acpi_ser_p->global_int[1] << 8) | + acpi_ser_p->global_int[0]; + +#ifdef SERIAL_DEBUG_ACPI + printk("setup_serial_acpi(): table pointer = 0x%p\n", acpi_ser_p); + printk(" sig = '%c%c%c%c'\n", + acpi_ser_p->signature[0], + acpi_ser_p->signature[1], + acpi_ser_p->signature[2], + acpi_ser_p->signature[3]); + printk(" length = %d\n", acpi_ser_p->length); + printk(" Rev = %d\n", acpi_ser_p->rev); + printk(" Interface type = %d\n", acpi_ser_p->intfc_type); + printk(" Base address = 0x%lX\n", iobase); + printk(" IRQ = %d\n", acpi_ser_p->irq); + printk(" Global System Int = %d\n", global_sys_irq); + printk(" Baud rate = "); + switch (acpi_ser_p->baud) { + case ACPI_SERIAL_BAUD_9600: + printk("9600\n"); + break; + + case ACPI_SERIAL_BAUD_19200: + printk("19200\n"); + break; + + case ACPI_SERIAL_BAUD_57600: + printk("57600\n"); + break; + + case ACPI_SERIAL_BAUD_115200: + printk("115200\n"); + break; + + default: + printk("Huh (%d)\n", acpi_ser_p->baud); + break; + + } + if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { + printk(" PCI serial port:\n"); + printk(" Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n", + acpi_ser_p->pci_bus, acpi_ser_p->pci_dev, + acpi_ser_p->pci_vendor_id, acpi_ser_p->pci_dev_id); + } +#endif + + /* + * Now build a serial_req structure to update the entry in + * rs_table for the headless console port. + */ + switch (acpi_ser_p->intfc_type) { + case ACPI_SERIAL_INTFC_16550: + serial_req.type = PORT_16550; + serial_req.baud_base = BASE_BAUD; + break; + + case ACPI_SERIAL_INTFC_16450: + serial_req.type = PORT_16450; + serial_req.baud_base = BASE_BAUD; + break; + + default: + serial_req.type = PORT_UNKNOWN; + break; + } + if (strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, + ACPI_SIG_LEN) == 0) { + serial_req.line = ACPI_SERIAL_CONSOLE_PORT; + } + else if (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, + ACPI_SIG_LEN) == 0) { + serial_req.line = ACPI_SERIAL_DEBUG_PORT; + } + /* + * Check if this is an I/O mapped address or a memory mapped address + */ + if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_MEM_SPACE) { + serial_req.port = 0; + serial_req.port_high = 0; + serial_req.iomem_base = (void *)ioremap(iobase, 64); + serial_req.io_type = SERIAL_IO_MEM; + } + else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_IO_SPACE) { + serial_req.port = (unsigned long) iobase & 0xffffffff; + serial_req.port_high = (unsigned long)(((u64)iobase) >> 32); + serial_req.iomem_base = NULL; + serial_req.io_type = SERIAL_IO_PORT; + } + else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { + printk("WARNING: No support for PCI serial console\n"); + return; + } + + /* + * If the table does not have IRQ information, use 0 for IRQ. + * This will force rs_init() to probe for IRQ. + */ + if (acpi_ser_p->length < 53) { + serial_req.irq = 0; + } + else { + if (acpi_ser_p->int_type & + (ACPI_SERIAL_INT_APIC | ACPI_SERIAL_INT_SAPIC)) { + serial_req.irq = global_sys_irq; + } + else if (acpi_ser_p->int_type & ACPI_SERIAL_INT_PCAT) { + serial_req.irq = acpi_ser_p->irq; + } + } + + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ; + serial_req.xmit_fifo_size = serial_req.custom_divisor = 0; + serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0; + serial_req.iomem_reg_shift = 0; + if (early_serial_setup(&serial_req) < 0) { + printk("early_serial_setup() for ACPI serial console port failed\n"); + return; + } + +#ifdef SERIAL_DEBUG_ACPI + printk("Leaving setup_serial_acpi()\n"); +#endif +} diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 15c93d6a5096..1b70fabaa46f 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -170,12 +170,27 @@ struct agp_bridge_data { #ifndef PCI_DEVICE_ID_INTEL_810_0 #define PCI_DEVICE_ID_INTEL_810_0 0x7120 #endif +#ifndef PCI_DEVICE_ID_INTEL_830_M_0 +#define PCI_DEVICE_ID_INTEL_830_M_0 0x3575 +#endif +#ifndef PCI_DEVICE_ID_INTEL_830_M_1 +#define PCI_DEVICE_ID_INTEL_830_M_1 0x3577 +#endif +#ifndef PCI_DEVICE_ID_INTEL_820_0 +#define PCI_DEVICE_ID_INTEL_820_0 0x2500 +#endif #ifndef PCI_DEVICE_ID_INTEL_840_0 #define PCI_DEVICE_ID_INTEL_840_0 0x1a21 #endif +#ifndef PCI_DEVICE_ID_INTEL_845_0 +#define PCI_DEVICE_ID_INTEL_845_0 0x1a30 +#endif #ifndef PCI_DEVICE_ID_INTEL_850_0 #define PCI_DEVICE_ID_INTEL_850_0 0x2530 #endif +#ifndef PCI_DEVICE_ID_INTEL_860_0 +#define PCI_DEVICE_ID_INTEL_860_0 0x2532 +#endif #ifndef PCI_DEVICE_ID_INTEL_810_DC100_0 #define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122 #endif @@ -200,12 +215,6 @@ struct agp_bridge_data { #ifndef PCI_DEVICE_ID_INTEL_815_1 #define PCI_DEVICE_ID_INTEL_815_1 0x1132 #endif -#ifndef PCI_DEVICE_ID_INTEL_830_M_0 -#define PCI_DEVICE_ID_INTEL_830_M_0 0x3575 -#endif -#ifndef PCI_DEVICE_ID_INTEL_830_M_1 -#define PCI_DEVICE_ID_INTEL_830_M_1 0x3577 -#endif #ifndef PCI_DEVICE_ID_INTEL_82443GX_1 #define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1 #endif @@ -251,14 +260,42 @@ struct agp_bridge_data { #define INTEL_NBXCFG 0x50 #define INTEL_ERRSTS 0x91 +/* intel i830 registers */ +#define I830_GMCH_CTRL 0x52 +#define I830_GMCH_ENABLED 0x4 +#define I830_GMCH_MEM_MASK 0x1 +#define I830_GMCH_MEM_64M 0x1 +#define I830_GMCH_MEM_128M 0 +#define I830_GMCH_GMS_MASK 0x70 +#define I830_GMCH_GMS_DISABLED 0x00 +#define I830_GMCH_GMS_LOCAL 0x10 +#define I830_GMCH_GMS_STOLEN_512 0x20 +#define I830_GMCH_GMS_STOLEN_1024 0x30 +#define I830_GMCH_GMS_STOLEN_8192 0x40 +#define I830_RDRAM_CHANNEL_TYPE 0x03010 +#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5) +#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3) + +/* intel i820 registers */ +#define INTEL_I820_RDCR 0x51 +#define INTEL_I820_ERRSTS 0xc8 + /* intel i840 registers */ #define INTEL_I840_MCHCFG 0x50 -#define INTEL_I840_ERRSTS 0xc8 +#define INTEL_I840_ERRSTS 0xc8 + +/* intel i845 registers */ +#define INTEL_I845_AGPM 0x51 +#define INTEL_I845_ERRSTS 0xc8 /* intel i850 registers */ #define INTEL_I850_MCHCFG 0x50 #define INTEL_I850_ERRSTS 0xc8 +/* intel i860 registers */ +#define INTEL_I860_MCHCFG 0x50 +#define INTEL_I860_ERRSTS 0xc8 + /* intel i810 registers */ #define I810_GMADDR 0x10 #define I810_MMADDR 0x14 @@ -277,21 +314,7 @@ struct agp_bridge_data { #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 -/* intel i830 registers */ -#define I830_GMCH_CTRL 0x52 -#define I830_GMCH_ENABLED 0x4 -#define I830_GMCH_MEM_MASK 0x1 -#define I830_GMCH_MEM_64M 0x1 -#define I830_GMCH_MEM_128M 0 -#define I830_GMCH_GMS_MASK 0x70 -#define I830_GMCH_GMS_DISABLED 0x00 -#define I830_GMCH_GMS_LOCAL 0x10 -#define I830_GMCH_GMS_STOLEN_512 0x20 -#define I830_GMCH_GMS_STOLEN_1024 0x30 -#define I830_GMCH_GMS_STOLEN_8192 0x40 -#define I830_RDRAM_CHANNEL_TYPE 0x03010 -#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5) -#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3) + /* VIA register */ #define VIA_APBASE 0x10 diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index 7e0f53e55189..7595677f15a5 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -387,8 +387,8 @@ int agp_unbind_memory(agp_memory * curr) /* * Driver routines - start * Currently this module supports the following chipsets: - * i810, i815, 440lx, 440bx, 440gx, i840, i850, via vp3, via mvp3, - * via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541, + * i810, i815, 440lx, 440bx, 440gx, i830, i840, i845, i850, i860, via vp3, + * via mvp3, via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541, * and generic support for the SiS chipsets. */ @@ -645,6 +645,7 @@ static int agp_generic_suspend(void) static void agp_generic_resume(void) { + return; } static int agp_generic_free_gatt_table(void) @@ -1397,6 +1398,10 @@ static int __init intel_i830_setup(struct pci_dev *i830_dev) return(0); } +#endif /* CONFIG_AGP_I810 */ + + #ifdef CONFIG_AGP_INTEL + #endif /* CONFIG_AGP_I810 */ #ifdef CONFIG_AGP_INTEL @@ -1422,12 +1427,45 @@ static int intel_fetch_size(void) return 0; } + +static int intel_8xx_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + pci_read_config_byte(agp_bridge.dev, INTEL_APSIZE, &temp); + values = A_SIZE_8(agp_bridge.aperture_sizes); + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + static void intel_tlbflush(agp_memory * mem) { pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); } + +static void intel_8xx_tlbflush(agp_memory * mem) +{ + u32 temp; + pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp & ~(1 << 7)); + pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp & (1 << 7)); +} + + static void intel_cleanup(void) { u16 temp; @@ -1440,6 +1478,20 @@ static void intel_cleanup(void) previous_size->size_value); } + +static void intel_8xx_cleanup(void) +{ + u16 temp; + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + + static int intel_configure(void) { u32 temp; @@ -1472,17 +1524,70 @@ static int intel_configure(void) return 0; } +static void intel_820_tlbflush(agp_memory * mem) +{ + return; +} + +static void intel_820_cleanup(void) +{ + u8 temp; + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp); + pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, + temp & ~(1 << 1)); + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + + +static int intel_820_configure(void) +{ + u32 temp; + u8 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* global enable aperture access */ + /* This flag is not accessed through MCHCFG register as in */ + /* i850 chipset. */ + pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp2); + pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, + temp2 | (1 << 1)); + /* clear any possible AGP-related error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I820_ERRSTS, 0x001c); + return 0; +} + static int intel_840_configure(void) { u32 temp; u16 temp2; - aper_size_info_16 *current_size; + aper_size_info_8 *current_size; - current_size = A_SIZE_16(agp_bridge.current_size); + current_size = A_SIZE_8(agp_bridge.current_size); /* aperture size */ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - (char)current_size->size_value); + current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); @@ -1504,17 +1609,49 @@ static int intel_840_configure(void) return 0; } +static int intel_845_configure(void) +{ + u32 temp; + u8 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* agpm */ + pci_read_config_byte(agp_bridge.dev, INTEL_I845_AGPM, &temp2); + pci_write_config_byte(agp_bridge.dev, INTEL_I845_AGPM, + temp2 | (1 << 1)); + /* clear any possible error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I845_ERRSTS, 0x001c); + return 0; +} + static int intel_850_configure(void) { u32 temp; u16 temp2; - aper_size_info_16 *current_size; + aper_size_info_8 *current_size; - current_size = A_SIZE_16(agp_bridge.current_size); + current_size = A_SIZE_8(agp_bridge.current_size); /* aperture size */ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - (char)current_size->size_value); + current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); @@ -1536,6 +1673,38 @@ static int intel_850_configure(void) return 0; } +static int intel_860_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* mcgcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, + temp2 | (1 << 9)); + /* clear any possible AGP-related error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I860_ERRSTS, 0xf700); + return 0; +} + static unsigned long intel_mask_memory(unsigned long addr, int type) { /* Memory type is ignored */ @@ -1554,6 +1723,17 @@ static gatt_mask intel_generic_masks[] = {0x00000017, 0} }; +static aper_size_info_8 intel_8xx_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 32}, + {64, 16384, 4, 48}, + {32, 8192, 3, 56}, + {16, 4096, 2, 60}, + {8, 2048, 1, 62}, + {4, 1024, 0, 63} +}; + static aper_size_info_16 intel_generic_sizes[7] = { {256, 65536, 6, 0}, @@ -1598,19 +1778,84 @@ static int __init intel_generic_setup (struct pci_dev *pdev) (void) pdev; /* unused */ } + +static int __init intel_820_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_820_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_cleanup; + agp_bridge.tlb_flush = intel_820_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + + return 0; + + (void) pdev; /* unused */ +} + + static int __init intel_840_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_generic_sizes; - agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; agp_bridge.dev_private_data = NULL; agp_bridge.needs_scratch_page = FALSE; agp_bridge.configure = intel_840_configure; - agp_bridge.fetch_size = intel_fetch_size; - agp_bridge.cleanup = intel_cleanup; - agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + +static int __init intel_845_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_845_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; agp_bridge.mask_memory = intel_mask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; @@ -1635,15 +1880,15 @@ static int __init intel_850_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_generic_sizes; - agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; agp_bridge.dev_private_data = NULL; agp_bridge.needs_scratch_page = FALSE; agp_bridge.configure = intel_850_configure; - agp_bridge.fetch_size = intel_fetch_size; - agp_bridge.cleanup = intel_cleanup; - agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; agp_bridge.mask_memory = intel_mask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; @@ -1664,6 +1909,39 @@ static int __init intel_850_setup (struct pci_dev *pdev) (void) pdev; /* unused */ } +static int __init intel_860_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_860_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_VIA @@ -3103,6 +3381,8 @@ static int __init serverworks_setup (struct pci_dev *pdev) agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; agp_bridge.cant_use_aperture = 0; pci_read_config_dword(agp_bridge.dev, @@ -3215,6 +3495,12 @@ static struct { "AMD", "Irongate", amd_irongate_setup }, + { PCI_DEVICE_ID_AMD_762_0, + PCI_VENDOR_ID_AMD, + AMD_IRONGATE, + "AMD", + "AMD 760MP", + amd_irongate_setup }, { PCI_DEVICE_ID_AMD_761_0, PCI_VENDOR_ID_AMD, AMD_761, @@ -3260,6 +3546,12 @@ static struct { "Intel", "i815", intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_820_0, + PCI_VENDOR_ID_INTEL, + INTEL_I820, + "Intel", + "i820", + intel_820_setup }, { PCI_DEVICE_ID_INTEL_830_M_0, PCI_VENDOR_ID_INTEL, INTEL_I830_M, @@ -3272,12 +3564,24 @@ static struct { "Intel", "i840", intel_840_setup }, + { PCI_DEVICE_ID_INTEL_845_0, + PCI_VENDOR_ID_INTEL, + INTEL_I845, + "Intel", + "i845", + intel_845_setup }, { PCI_DEVICE_ID_INTEL_850_0, PCI_VENDOR_ID_INTEL, INTEL_I850, "Intel", "i850", intel_850_setup }, + { PCI_DEVICE_ID_INTEL_860_0, + PCI_VENDOR_ID_INTEL, + INTEL_I860, + "Intel", + "i860", + intel_860_setup }, { 0, PCI_VENDOR_ID_INTEL, INTEL_GENERIC, @@ -3288,6 +3592,36 @@ static struct { #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_SIS + { PCI_DEVICE_ID_SI_740, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "740", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_650, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "650", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_645, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "645", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_735, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "735", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_730, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "730", + sis_generic_setup }, { PCI_DEVICE_ID_SI_630, PCI_VENDOR_ID_SI, SIS_GENERIC, @@ -3312,11 +3646,11 @@ static struct { "SiS", "530", sis_generic_setup }, - { PCI_DEVICE_ID_SI_735, + { PCI_DEVICE_ID_SI_550, PCI_VENDOR_ID_SI, SIS_GENERIC, "SiS", - "735", + "550", sis_generic_setup }, { 0, PCI_VENDOR_ID_SI, @@ -3530,13 +3864,13 @@ static int __init agp_find_supported_device(void) PCI_DEVICE_ID_INTEL_815_1, NULL); if (i810_dev == NULL) { - printk(KERN_ERR PFX "Detected an " + printk(KERN_ERR PFX "agpgart: Detected an " "Intel i815, but could not find the" " secondary device. Assuming a " "non-integrated video card.\n"); break; } - printk(KERN_INFO PFX "Detected an Intel i815 " + printk(KERN_INFO PFX "agpgart: Detected an Intel i815 " "Chipset.\n"); agp_bridge.type = INTEL_I810; return intel_i810_setup(i810_dev); diff --git a/drivers/char/drm/drm_agpsupport.h b/drivers/char/drm/drm_agpsupport.h index e51bf490d786..3c588f93f2a3 100644 --- a/drivers/char/drm/drm_agpsupport.h +++ b/drivers/char/drm/drm_agpsupport.h @@ -273,7 +273,9 @@ drm_agp_head_t *DRM(agp_init)(void) #if LINUX_VERSION_CODE >= 0x020400 case INTEL_I815: head->chipset = "Intel i815"; break; + case INTEL_I820: head->chipset = "Intel i820"; break; case INTEL_I840: head->chipset = "Intel i840"; break; + case INTEL_I845: head->chipset = "Intel i845"; break; case INTEL_I850: head->chipset = "Intel i850"; break; #endif diff --git a/drivers/char/esp.c b/drivers/char/esp.c index c1649b2395d6..5560c565dea7 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -2123,7 +2123,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (info->blocked_open) { if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); @@ -2156,7 +2156,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) while ((serial_in(info, UART_ESI_STAT1) != 0x03) || (serial_in(info, UART_ESI_STAT2) != 0xff)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); if (signal_pending(current)) @@ -2170,7 +2170,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) } restore_flags(flags); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); } /* @@ -2203,6 +2203,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; + unsigned long flags; /* * If the device is in the middle of being closed, then block @@ -2274,12 +2275,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready before block: ttys%d, count = %d\n", info->line, info->count); #endif + save_flags(flags); cli(); if (!tty_hung_up_p(filp)) info->count--; - sti(); + restore_flags(flags); info->blocked_open++; while (1) { + save_flags(flags); cli(); if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) { @@ -2293,7 +2296,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, serial_out(info, UART_ESI_CMD2, scratch | UART_MCR_DTR | UART_MCR_RTS); } - sti(); + restore_flags(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { @@ -2326,7 +2329,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; diff --git a/drivers/char/hp_keyb.c b/drivers/char/hp_keyb.c new file mode 100644 index 000000000000..1453a661db01 --- /dev/null +++ b/drivers/char/hp_keyb.c @@ -0,0 +1,519 @@ +/* + * linux/drivers/char/hp_keyb.c + * helper-functions for the keyboard/psaux driver for HP-PARISC workstations + * + * based on pc_keyb.c by Geert Uytterhoeven & Martin Mares + * + * 2000/10/26 Debacker Xavier + * Marteau Thomas + * Djoudi Malek + * - fixed some keysym defines + * + * 2001/04/28 Debacker Xavier + * - scancode translation rewritten in handle_at_scancode() + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN + +#define KBD_ESCAPEE0 0xe0 /* in */ +#define KBD_ESCAPEE1 0xe1 /* in */ + +#define ESCE0(x) (0xe000|(x)) +#define ESCE1(x) (0xe100|(x)) + +#define KBD_BAT 0xaa /* in */ +#define KBD_SETLEDS 0xed /* out */ +#define KBD_ECHO 0xee /* in/out */ +#define KBD_BREAK 0xf0 /* in */ +#define KBD_TYPRATEDLY 0xf3 /* out */ +#define KBD_SCANENABLE 0xf4 /* out */ +#define KBD_DEFDISABLE 0xf5 /* out */ +#define KBD_DEFAULT 0xf6 /* out */ +#define KBD_ACK 0xfa /* in */ +#define KBD_DIAGFAIL 0xfd /* in */ +#define KBD_RESEND 0xfe /* in/out */ +#define KBD_RESET 0xff /* out */ + +#define CODE_BREAK 1 +#define CODE_ESCAPEE0 2 +#define CODE_ESCAPEE1 4 +#define CODE_ESCAPE12 8 + +#define K_NONE 0x7f +#define K_ESC 0x01 +#define K_F1 0x3b +#define K_F2 0x3c +#define K_F3 0x3d +#define K_F4 0x3e +#define K_F5 0x3f +#define K_F6 0x40 +#define K_F7 0x41 +#define K_F8 0x42 +#define K_F9 0x43 +#define K_F10 0x44 +#define K_F11 0x57 +#define K_F12 0x58 +#define K_PRNT 0x54 +#define K_SCRL 0x46 +#define K_BRK 0x77 +#define K_AGR 0x29 +#define K_1 0x02 +#define K_2 0x03 +#define K_3 0x04 +#define K_4 0x05 +#define K_5 0x06 +#define K_6 0x07 +#define K_7 0x08 +#define K_8 0x09 +#define K_9 0x0a +#define K_0 0x0b +#define K_MINS 0x0c +#define K_EQLS 0x0d +#define K_BKSP 0x0e +#define K_INS 0x6e +#define K_HOME 0x66 +#define K_PGUP 0x68 +#define K_NUML 0x45 +#define KP_SLH 0x62 +#define KP_STR 0x37 +#define KP_MNS 0x4a +#define K_TAB 0x0f +#define K_Q 0x10 +#define K_W 0x11 +#define K_E 0x12 +#define K_R 0x13 +#define K_T 0x14 +#define K_Y 0x15 +#define K_U 0x16 +#define K_I 0x17 +#define K_O 0x18 +#define K_P 0x19 +#define K_LSBK 0x1a +#define K_RSBK 0x1b +#define K_ENTR 0x1c +#define K_DEL 111 +#define K_END 0x6b +#define K_PGDN 0x6d +#define KP_7 0x47 +#define KP_8 0x48 +#define KP_9 0x49 +#define KP_PLS 0x4e +#define K_CAPS 0x3a +#define K_A 0x1e +#define K_S 0x1f +#define K_D 0x20 +#define K_F 0x21 +#define K_G 0x22 +#define K_H 0x23 +#define K_J 0x24 +#define K_K 0x25 +#define K_L 0x26 +#define K_SEMI 0x27 +#define K_SQOT 0x28 +#define K_HASH K_NONE +#define KP_4 0x4b +#define KP_5 0x4c +#define KP_6 0x4d +#define K_LSFT 0x2a +#define K_BSLH 0x2b +#define K_Z 0x2c +#define K_X 0x2d +#define K_C 0x2e +#define K_V 0x2f +#define K_B 0x30 +#define K_N 0x31 +#define K_M 0x32 +#define K_COMA 0x33 +#define K_DOT 0x34 +#define K_FSLH 0x35 +#define K_RSFT 0x36 +#define K_UP 0x67 +#define KP_1 0x4f +#define KP_2 0x50 +#define KP_3 0x51 +#define KP_ENT 0x60 +#define K_LCTL 0x1d +#define K_LALT 0x38 +#define K_SPCE 0x39 +#define K_RALT 0x64 +#define K_RCTL 0x61 +#define K_LEFT 0x69 +#define K_DOWN 0x6c +#define K_RGHT 0x6a +#define KP_0 0x52 +#define KP_DOT 0x53 + +static unsigned char keycode_translate[256] = +{ +/* 00 */ K_NONE, K_F9 , K_NONE, K_F5 , K_F3 , K_F1 , K_F2 , K_F12 , +/* 08 */ K_NONE, K_F10 , K_F8 , K_F6 , K_F4 , K_TAB , K_AGR , K_NONE, +/* 10 */ K_NONE, K_LALT, K_LSFT, K_NONE, K_LCTL, K_Q , K_1 , K_NONE, +/* 18 */ K_NONE, K_NONE, K_Z , K_S , K_A , K_W , K_2 , K_NONE, +/* 20 */ K_NONE, K_C , K_X , K_D , K_E , K_4 , K_3 , K_NONE, +/* 28 */ K_NONE, K_SPCE, K_V , K_F , K_T , K_R , K_5 , K_NONE, +/* 30 */ K_NONE, K_N , K_B , K_H , K_G , K_Y , K_6 , K_NONE, +/* 38 */ K_NONE, K_NONE, K_M , K_J , K_U , K_7 , K_8 , K_NONE, +/* 40 */ K_NONE, K_COMA, K_K , K_I , K_O , K_0 , K_9 , K_NONE, +/* 48 */ K_NONE, K_DOT , K_FSLH, K_L , K_SEMI, K_P , K_MINS, K_NONE, +/* 50 */ K_NONE, K_NONE, K_SQOT, K_NONE, K_LSBK, K_EQLS, K_NONE, K_NONE, +/* 58 */ K_CAPS, K_RSFT, K_ENTR, K_RSBK, K_NONE, K_BSLH, K_NONE, K_NONE, +/* 60 */ K_NONE, K_HASH, K_NONE, K_NONE, K_NONE, K_NONE, K_BKSP, K_NONE, +/* 68 */ K_NONE, KP_1 , K_NONE, KP_4 , KP_7 , K_NONE, K_NONE, K_NONE, +/* 70 */ KP_0 , KP_DOT, KP_2 , KP_5 , KP_6 , KP_8 , K_ESC , K_NUML, +/* 78 */ K_F11 , KP_PLS, KP_3 , KP_MNS, KP_STR, KP_9 , K_SCRL, K_PRNT, +/* 80 */ K_NONE, K_NONE, K_NONE, K_F7 , K_NONE, K_NONE, K_NONE, K_NONE, +/* 88 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* 90 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* 98 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* a0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* a8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* b0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* b8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* c0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* c8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* d0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* d8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* e0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* e8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* f0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* f8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, KBD_RESEND, K_NONE +}; + +/* ----- the following code stolen from pc_keyb.c */ + + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char hp_ps2kbd_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable. + * The keycodes 1-88,96-111,119 are fairly standard, and + * should probably not be changed - changing might confuse X. + * X also interprets scancode 0x5d (KEY_Begin). + * + * For 1-88 keycode equals scancode. + */ + +#define E0_KPENTER 96 +#define E0_RCTRL 97 +#define E0_KPSLASH 98 +#define E0_PRSCR 99 +#define E0_RALT 100 +#define E0_BREAK 101 /* (control-pause) */ +#define E0_HOME 102 +#define E0_UP 103 +#define E0_PGUP 104 +#define E0_LEFT 105 +#define E0_RIGHT 106 +#define E0_END 107 +#define E0_DOWN 108 +#define E0_PGDN 109 +#define E0_INS 110 +#define E0_DEL 111 + +#define E1_PAUSE 119 + +/* + * The keycodes below are randomly located in 89-95,112-118,120-127. + * They could be thrown away (and all occurrences below replaced by 0), + * but that would force many users to use the `setkeycodes' utility, where + * they needed not before. It does not matter that there are duplicates, as + * long as no duplication occurs for any single keyboard. + */ +#define SC_LIM 89 /* 0x59 == 89 */ + +#define FOCUS_PF1 85 /* actual code! */ +#define FOCUS_PF2 89 +#define FOCUS_PF3 90 +#define FOCUS_PF4 91 +#define FOCUS_PF5 92 +#define FOCUS_PF6 93 +#define FOCUS_PF7 94 +#define FOCUS_PF8 95 +#define FOCUS_PF9 120 +#define FOCUS_PF10 121 +#define FOCUS_PF11 122 +#define FOCUS_PF12 123 + +#define JAP_86 124 +/* tfj@olivia.ping.dk: + * The four keys are located over the numeric keypad, and are + * labelled A1-A4. It's an rc930 keyboard, from + * Regnecentralen/RC International, Now ICL. + * Scancodes: 59, 5a, 5b, 5c. + */ +#define RGN1 124 +#define RGN2 125 +#define RGN3 126 +#define RGN4 127 + +static unsigned char high_keys[128 - SC_LIM] = { + RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ + 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ + FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ + FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ +}; + +/* BTC */ +#define E0_MACRO 112 +/* LK450 */ +#define E0_F13 113 +#define E0_F14 114 +#define E0_HELP 115 +#define E0_DO 116 +#define E0_F17 117 +#define E0_KPMINPLUS 118 +/* + * My OmniKey generates e0 4c for the "OMNI" key and the + * right alt key does nada. [kkoller@nyx10.cs.du.edu] + */ +#define E0_OK 124 +/* + * New microsoft keyboard is rumoured to have + * e0 5b (left window button), e0 5c (right window button), + * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] + * [or: Windows_L, Windows_R, TaskMan] + */ +#define E0_MSLW 125 +#define E0_MSRW 126 +#define E0_MSTM 127 + +static unsigned char e0_keys[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ + E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ + E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ + E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ + E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + if (scancode < SC_LIM || scancode > 255 || keycode > 127) + return -EINVAL; + if (scancode < 128) + high_keys[scancode - SC_LIM] = keycode; + else + e0_keys[scancode - 128] = keycode; + return 0; +} + +int pckbd_getkeycode(unsigned int scancode) +{ + return + (scancode < SC_LIM || scancode > 255) ? -EINVAL : + (scancode < 128) ? high_keys[scancode - SC_LIM] : + e0_keys[scancode - 128]; +} + +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + static int prev_scancode; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + scancode &= 0x7f; + + if (prev_scancode) { + /* + * usually it will be 0xe0, but a Pause key generates + * e1 1d 45 e1 9d c5 when pressed, and nothing when released + */ + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = E1_PAUSE; + prev_scancode = 0; + } else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); +#endif + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + /* + * The keyboard maintains its own internal caps lock and + * num lock statuses. In caps lock mode E0 AA precedes make + * code and E0 2A follows break code. In num lock mode, + * E0 2A precedes make code and E0 AA follows break code. + * We do our own book-keeping, so we will just ignore these. + */ + /* + * For my keyboard there is no caps lock mode, but there are + * both Shift-L and Shift-R modes. The former mode generates + * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. + * So, we should also ignore the latter. - aeb@cwi.nl + */ + if (scancode == 0x2a || scancode == 0x36) + return 0; + + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); +#endif + return 0; + } + } + } else if (scancode >= SC_LIM) { + /* This happens with the FOCUS 9000 keyboard + Its keys PF1..PF12 are reported to generate + 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f + Moreover, unless repeated, they do not generate + key-down events, so we have to zero up_flag below */ + /* Also, Japanese 86/106 keyboards are reported to + generate 0x73 and 0x7d for \ - and \ | respectively. */ + /* Also, some Brazilian keyboard is reported to produce + 0x73 and 0x7e for \ ? and KP-dot, respectively. */ + + *keycode = high_keys[scancode - SC_LIM]; + + if (!*keycode) { + if (!raw_mode) { +#ifdef KBD_REPORT_UNKN + printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" + " - ignored\n", scancode); +#endif + } + return 0; + } + } else + *keycode = scancode; + + return 1; +} + +/* ----- end of stolen part ------ */ + + +void kbd_reset_setup(void) +{ +} + +void handle_at_scancode(int keyval) +{ + static int brk; + static int esc0; + static int esc1; + int scancode = 0; + + switch (keyval) { + case KBD_BREAK : + /* sets the "release_key" bit when a key is + released. HP keyboard send f0 followed by + the keycode while AT keyboard send the keycode + with this bit set. */ + brk = 0x80; + return; + case KBD_ESCAPEE0 : + /* 2chars sequence, commonly used to differenciate + the two ALT keys and the two ENTER keys and so + on... */ + esc0 = 2; /* e0-xx are 2 chars */ + scancode = keyval; + break; + case KBD_ESCAPEE1 : + /* 3chars sequence, only used by the Pause key. */ + esc1 = 3; /* e1-xx-xx are 3 chars */ + scancode = keyval; + break; +#if 0 + case KBD_RESEND : + /* dunno what to do when it happens. RFC */ + printk(KERN_INFO "keyboard: KBD_RESEND received.\n"); + return; +#endif + case 0x14 : + /* translate e1-14-77-e1-f0-14-f0-77 to + e1-1d-45-e1-9d-c5 (the Pause key) */ + if (esc1==2) scancode = brk | 0x1d; + break; + case 0x77 : + if (esc1==1) scancode = brk | 0x45; + break; + case 0x12 : + /* an extended key is e0-12-e0-xx e0-f0-xx-e0-f0-12 + on HP, while it is e0-2a-e0-xx e0-(xx|80)-f0-aa + on AT. */ + if (esc0==1) scancode = brk | 0x2a; + break; + } + + + /* translates HP scancodes to AT scancodes */ + if (!scancode) scancode = brk | keycode_translate[keyval]; + + + if (!scancode) printk(KERN_INFO "keyboard: unexpected key code %02x\n",keyval); + + /* now behave like an AT keyboard */ + handle_scancode(scancode,!(scancode&0x80)); + + if (esc0) esc0--; + if (esc1) esc1--; + + /* release key bit must be unset for the next key */ + brk = 0; +} + diff --git a/drivers/char/hp_psaux.c b/drivers/char/hp_psaux.c new file mode 100644 index 000000000000..8f004d5a019a --- /dev/null +++ b/drivers/char/hp_psaux.c @@ -0,0 +1,551 @@ +/* + * LASI PS/2 keyboard/psaux driver for HP-PARISC workstations + * + * (c) Copyright 1999 The Puffin Group Inc. + * by Alex deVries + * Copyright 1999, 2000 Philipp Rumpf + * + * 2000/10/26 Debacker Xavier (debackex@esiee.fr) + * Marteau Thomas (marteaut@esiee.fr) + * Djoudi Malek (djoudim@esiee.fr) + * fixed leds control + * implemented the psaux and controlled the mouse scancode based on pc_keyb.c + */ + +#include + +#include +#include +#include + +#include +#include /* interrupt.h wants struct pt_regs defined */ +#include +#include /* for request_irq/free_irq */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* mouse includes */ +#include +#include +#include +#include +#include +#include +#include + +/* HP specific LASI PS/2 keyboard and psaux constants */ +#define AUX_REPLY_ACK 0xFA /* Command byte ACK. */ +#define AUX_RECONNECT 0xAA /* scancode when ps2 device is plugged (back) in */ + +#define LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */ + +#define LASI_ID 0x00 /* ID and reset port offsets */ +#define LASI_RESET 0x00 +#define LASI_RCVDATA 0x04 /* receive and transmit port offsets */ +#define LASI_XMTDATA 0x04 +#define LASI_CONTROL 0x08 /* see: control register bits */ +#define LASI_STATUS 0x0C /* see: status register bits */ + +/* control register bits */ +#define LASI_CTRL_ENBL 0x01 /* enable interface */ +#define LASI_CTRL_LPBXR 0x02 /* loopback operation */ +#define LASI_CTRL_DIAG 0x20 /* directly control clock/data line */ +#define LASI_CTRL_DATDIR 0x40 /* data line direct control */ +#define LASI_CTRL_CLKDIR 0x80 /* clock line direct control */ + +/* status register bits */ +#define LASI_STAT_RBNE 0x01 +#define LASI_STAT_TBNE 0x02 +#define LASI_STAT_TERR 0x04 +#define LASI_STAT_PERR 0x08 +#define LASI_STAT_CMPINTR 0x10 +#define LASI_STAT_DATSHD 0x40 +#define LASI_STAT_CLKSHD 0x80 + +static void *lasikbd_hpa; +static void *lasips2_hpa; + + +static inline u8 read_input(void *hpa) +{ + return gsc_readb(hpa+LASI_RCVDATA); +} + +static inline u8 read_control(void *hpa) +{ + return gsc_readb(hpa+LASI_CONTROL); +} + +static inline void write_control(u8 val, void *hpa) +{ + gsc_writeb(val, hpa+LASI_CONTROL); +} + +static inline u8 read_status(void *hpa) +{ + return gsc_readb(hpa+LASI_STATUS); +} + +static int write_output(u8 val, void *hpa) +{ + int wait = 0; + + while (read_status(hpa) & LASI_STAT_TBNE) { + wait++; + if (wait>10000) { + /* printk(KERN_WARNING "Lasi PS/2 transmit buffer timeout\n"); */ + return 0; + } + } + + if (wait) + printk(KERN_DEBUG "Lasi PS/2 wait %d\n", wait); + + gsc_writeb(val, hpa+LASI_XMTDATA); + + return 1; +} + +/* This function is the PA-RISC adaptation of i386 source */ + +static inline int aux_write_ack(u8 val) +{ + return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET); +} + +static void lasikbd_leds(unsigned char leds) +{ + write_output(KBD_CMD_SET_LEDS, lasikbd_hpa); + write_output(leds, lasikbd_hpa); + write_output(KBD_CMD_ENABLE, lasikbd_hpa); +} + +#if 0 +/* this might become useful again at some point. not now -prumpf */ +int lasi_ps2_test(void *hpa) +{ + u8 control,c; + int i, ret = 0; + + control = read_control(hpa); + write_control(control | LASI_CTRL_LPBXR | LASI_CTRL_ENBL, hpa); + + for (i=0; i<256; i++) { + write_output(i, hpa); + + while (!(read_status(hpa) & LASI_STAT_RBNE)) + /* just wait */; + + c = read_input(hpa); + if (c != i) + ret--; + } + + write_control(control, hpa); + + return ret; +} +#endif + +static int __init lasi_ps2_reset(void *hpa, int id) +{ + u8 control; + int ret = 1; + + /* reset the interface */ + gsc_writeb(0xff, hpa+LASI_RESET); + gsc_writeb(0x0 , hpa+LASI_RESET); + + /* enable it */ + control = read_control(hpa); + write_control(control | LASI_CTRL_ENBL, hpa); + + /* initializes the leds at the default state */ + if (id==0) { + write_output(KBD_CMD_SET_LEDS, hpa); + write_output(0, hpa); + ret = write_output(KBD_CMD_ENABLE, hpa); + } + + return ret; +} + +static int inited; + +static void lasi_ps2_init_hw(void) +{ + ++inited; +} + + +/* Greatly inspired by pc_keyb.c */ + +/* + * Wait for keyboard controller input buffer to drain. + * + * Don't use 'jiffies' so that we don't depend on + * interrupts.. + * + * Quote from PS/2 System Reference Manual: + * + * "Address hex 0060 and address hex 0064 should be written only when + * the input-buffer-full bit and output-buffer-full bit in the + * Controller Status register are set 0." + */ +#ifdef CONFIG_PSMOUSE + +static struct aux_queue *queue; +static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char mouse_reply_expected; +static int aux_count; + +static int fasync_aux(int fd, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(fd, filp, on, &queue->fasync); + if (retval < 0) + return retval; + + return 0; +} + + + +static inline void handle_mouse_scancode(unsigned char scancode) +{ + if (mouse_reply_expected) { + if (scancode == AUX_REPLY_ACK) { + mouse_reply_expected--; + return; + } + mouse_reply_expected = 0; + } + else if (scancode == AUX_RECONNECT) { + queue->head = queue->tail = 0; /* Flush input queue */ + return; + } + + add_mouse_randomness(scancode); + if (aux_count) { + int head = queue->head; + + queue->buf[head] = scancode; + head = (head + 1) & (AUX_BUF_SIZE-1); + + if (head != queue->tail) { + queue->head = head; + kill_fasync(&queue->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&queue->proc_list); + } + } +} + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static unsigned char get_from_queue(void) +{ + unsigned char result; + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + + return result; +} + + +/* + * Write to the aux device. + */ + +static ssize_t write_aux(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + ssize_t retval = 0; + + if (count) { + ssize_t written = 0; + + if (count > 32) + count = 32; /* Limit to 32 bytes. */ + do { + char c; + get_user(c, buffer++); + written++; + } while (--count); + retval = -EIO; + if (written) { + retval = written; + file->f_dentry->d_inode->i_mtime = CURRENT_TIME; + } + } + + return retval; +} + + + +static ssize_t read_aux(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t i = count; + unsigned char c; + + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&queue->proc_list, &wait); + } + while (i > 0 && !queue_empty()) { + c = get_from_queue(); + put_user(c, buffer++); + i--; + } + if (count-i) { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return count-i; + } + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + + +static int open_aux(struct inode * inode, struct file * file) +{ + if (aux_count++) + return 0; + + queue->head = queue->tail = 0; /* Flush input queue */ + aux_count = 1; + aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ + + return 0; +} + + +/* No kernel lock held - fine */ +static unsigned int aux_poll(struct file *file, poll_table * wait) +{ + + poll_wait(file, &queue->proc_list, wait); + if (!queue_empty()) + return POLLIN | POLLRDNORM; + return 0; +} + + +static int release_aux(struct inode * inode, struct file * file) +{ + lock_kernel(); + fasync_aux(-1, file, 0); + if (--aux_count) { + unlock_kernel(); + return 0; + } + unlock_kernel(); + return 0; +} + +static struct file_operations psaux_fops = { + read: read_aux, + write: write_aux, + poll: aux_poll, + open: open_aux, + release: release_aux, + fasync: fasync_aux, +}; + +static struct miscdevice psaux_mouse = { + minor: PSMOUSE_MINOR, + name: "psaux", + fops: &psaux_fops, +}; + +#endif /* CONFIG_PSMOUSE */ + + +/* This function is looking at the PS2 controller and empty the two buffers */ + +static u8 handle_lasikbd_event(void *hpa) +{ + u8 status_keyb,status_mouse,scancode,id; + extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */ + + /* Mask to get the base address of the PS/2 controller */ + id = gsc_readb(hpa+LASI_ID) & 0x0f; + + if (id==1) + hpa -= LASI_PSAUX_OFFSET; + lasikbd_hpa = hpa; + + + status_keyb = read_status(hpa); + status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); + + while ((status_keyb|status_mouse) & LASI_STAT_RBNE){ + + while (status_keyb & LASI_STAT_RBNE) { + + scancode = read_input(hpa); + + /* XXX don't know if this is a valid fix, but filtering + * 0xfa avoids 'unknown scancode' errors on, eg, capslock + * on some keyboards. + */ + if (inited && scancode != 0xfa) + handle_at_scancode(scancode); + + status_keyb =read_status(hpa); + } + +#ifdef CONFIG_PSMOUSE + while (status_mouse & LASI_STAT_RBNE) { + scancode = read_input(hpa+LASI_PSAUX_OFFSET); + handle_mouse_scancode(scancode); + status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); + } + status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); +#endif /* CONFIG_PSMOUSE */ + status_keyb = read_status(hpa); + } + + tasklet_schedule(&keyboard_tasklet); + return (status_keyb|status_mouse); +} + + + + +extern struct pt_regs *kbd_pt_regs; + +static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + lasips2_hpa = dev; /* save "hpa" for lasikbd_leds() */ + kbd_pt_regs = regs; + handle_lasikbd_event(lasips2_hpa); +} + + +extern int pckbd_translate(unsigned char, unsigned char *, char); + +static struct kbd_ops gsc_ps2_kbd_ops = { + translate: pckbd_translate, + init_hw: lasi_ps2_init_hw, + leds: lasikbd_leds, +#ifdef CONFIG_MAGIC_SYSRQ + sysrq_key: 0x54, + sysrq_xlate: hp_ps2kbd_sysrq_xlate, +#endif +}; + +static int __init +lasi_ps2_register(struct hp_device *d, struct pa_iodc_driver *dri) +{ + void *hpa = (void *) d->hpa; + unsigned int irq; + char *name; + int device_found; + u8 id; + + id = gsc_readb(hpa+LASI_ID) & 0x0f; + + switch (id) { + case 0: + name = "keyboard"; + lasikbd_hpa = hpa; + break; + case 1: + name = "psaux"; + break; + default: + printk(KERN_WARNING "%s: Unknown PS/2 port (id=%d) - ignored.\n", + __FUNCTION__, id ); + return 0; + } + + /* reset the PS/2 port */ + device_found = lasi_ps2_reset(hpa,id); + + /* allocate the irq and memory region for that device */ + if (!(irq = busdevice_alloc_irq(d))) + return -ENODEV; + + if (request_irq(irq, lasikbd_interrupt, 0, name, hpa)) + return -ENODEV; + + if (!request_mem_region((unsigned long)hpa, LASI_STATUS + 4, name)) + return -ENODEV; + + switch (id) { + case 0: + register_kbd_ops(&gsc_ps2_kbd_ops); + break; + case 1: +#ifdef CONFIG_PSMOUSE + queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + return -ENOMEM; + + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + init_waitqueue_head(&queue->proc_list); + + misc_register(&psaux_mouse); + + aux_write_ack(AUX_ENABLE_DEV); + /* try it a second time, this will give status if the device is + * available */ + device_found = aux_write_ack(AUX_ENABLE_DEV); + break; +#else + /* return without printing any unnecessary and misleading info */ + return 0; +#endif + } /* of case */ + + printk(KERN_INFO "PS/2 %s controller at 0x%08lx (irq %d) found, " + "%sdevice attached.\n", + name, (unsigned long)hpa, irq, + device_found ? "":"no "); + + return 0; +} + + +static struct pa_iodc_driver lasi_psaux_drivers_for[] __initdata = { + {HPHW_FIO, 0x0, 0,0x00084, 0, 0, + DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION, + "Lasi psaux", "generic", (void *) lasi_ps2_register}, + { 0, } +}; + +static int __init gsc_ps2_init(void) +{ + return pdc_register_driver(lasi_psaux_drivers_for); +} + +module_init(gsc_ps2_init); + diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 04a459068680..bc070a90d3fd 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -60,24 +60,27 @@ #include -static int device_id[] = { 0x2028, - 0x2051, - 0x2052, - 0x2053, - 0x2054, - 0x2055, - 0x2056, - 0x2057, - 0x2058 - }; - -static int isicom_refcount = 0; +static struct pci_device_id isicom_pci_tbl[] = { + { VENDOR_ID, 0x2028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, isicom_pci_tbl); + +static int isicom_refcount; static int prev_card = 3; /* start servicing isi_card[0] */ -static struct isi_board * irq_to_board[16] = { NULL, }; +static struct isi_board * irq_to_board[16]; static struct tty_driver isicom_normal, isicom_callout; -static struct tty_struct * isicom_table[PORT_COUNT] = { NULL, }; -static struct termios * isicom_termios[PORT_COUNT] = { NULL, }; -static struct termios * isicom_termios_locked[PORT_COUNT] = { NULL, }; +static struct tty_struct * isicom_table[PORT_COUNT]; +static struct termios * isicom_termios[PORT_COUNT]; +static struct termios * isicom_termios_locked[PORT_COUNT]; static struct isi_board isi_card[BOARD_COUNT]; static struct isi_port isi_ports[PORT_COUNT]; @@ -997,7 +1000,7 @@ static int block_til_ready(struct tty_struct * tty, struct file * filp, struct i } schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); if (!tty_hung_up_p(filp)) port->count++; @@ -1202,7 +1205,7 @@ static void isicom_close(struct tty_struct * tty, struct file * filp) port->tty = 0; if (port->blocked_open) { if (port->close_delay) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: scheduling until time out.\n"); #endif @@ -1974,7 +1977,7 @@ int init_module(void) for (idx=0; idx < DEVID_COUNT; idx++) { dev = NULL; for (;;){ - if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev))) + if (!(dev = pci_find_device(VENDOR_ID, isicom_pci_tbl[idx].device, dev))) break; if (card >= BOARD_COUNT) break; @@ -1988,7 +1991,7 @@ int init_module(void) * space. */ pciirq = dev->irq; - printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]); + printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", isicom_pci_tbl[idx].device); /* * allot the first empty slot in the array */ @@ -2035,7 +2038,7 @@ int init_module(void) void cleanup_module(void) { re_schedule = 0; - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); remove_bh(ISICOM_BH); diff --git a/drivers/char/joystick/cs461x.c b/drivers/char/joystick/cs461x.c index 26cf10ed2a44..7116b3453c04 100644 --- a/drivers/char/joystick/cs461x.c +++ b/drivers/char/joystick/cs461x.c @@ -158,7 +158,7 @@ static unsigned int cs461x_peekBA0(unsigned long reg) static int cs461x_free(struct pci_dev *pdev) { - struct gameport *port = (struct gameport *)pdev->driver_data; + struct gameport *port = pci_get_drvdata(pdev); if(port){ gameport_unregister_port(port); kfree(port); @@ -284,7 +284,7 @@ static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_dev } memset(port, 0, sizeof(struct gameport)); - pdev->driver_data = port; + pci_set_drvdata(pdev, port); port->open = cs461x_gameport_open; port->read = cs461x_gameport_read; diff --git a/drivers/char/joystick/emu10k1-gp.c b/drivers/char/joystick/emu10k1-gp.c index 671ee9e412b2..2489b11c6020 100644 --- a/drivers/char/joystick/emu10k1-gp.c +++ b/drivers/char/joystick/emu10k1-gp.c @@ -86,7 +86,7 @@ static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id port->gameport.io = ioport; port->size = iolen; port->dev = pdev; - pdev->driver_data = port; + pci_set_drvdata(pdev, port); gameport_register_port(&port->gameport); @@ -98,7 +98,7 @@ static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id static void __devexit emu_remove(struct pci_dev *pdev) { - struct emu *port = (struct emu *)pdev->driver_data; + struct emu *port = pci_get_drvdata(pdev); gameport_unregister_port(&port->gameport); release_region(port->gameport.io, port->size); kfree(port); diff --git a/drivers/char/joystick/pcigame.c b/drivers/char/joystick/pcigame.c index afe63a74b531..04e1bee04f9c 100644 --- a/drivers/char/joystick/pcigame.c +++ b/drivers/char/joystick/pcigame.c @@ -133,7 +133,7 @@ static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_ pcigame->data = pcigame_data + id->driver_data; pcigame->dev = dev; - dev->driver_data = pcigame; + pci_set_drvdata(dev, pcigame); pcigame->gameport.private = pcigame; pcigame->gameport.fuzz = 64; @@ -163,7 +163,7 @@ static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_ static void __devexit pcigame_remove(struct pci_dev *dev) { - struct pcigame *pcigame = dev->driver_data; + struct pcigame *pcigame = pci_get_drvdata(dev); gameport_unregister_port(&pcigame->gameport); iounmap(pcigame->base); kfree(pcigame); diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index c29923de6db1..45aa4efc3a07 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -397,29 +398,32 @@ char pckbd_unexpected_up(unsigned char keycode) return 0200; } -void pckbd_pm_resume(void) +int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data) { #if defined CONFIG_PSMOUSE unsigned long flags; - if (queue) { /* Aux port detected */ - if (aux_count == 0) { /* Mouse not in use */ - spin_lock_irqsave(&kbd_controller_lock, flags); - /* - * Dell Lat. C600 A06 enables mouse after resume. - * When user touches the pad, it posts IRQ 12 - * (which we do not process), thus holding keyboard. - */ - kbd_write_command(KBD_CCMD_MOUSE_DISABLE); - /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MODE); - kb_wait(); - kbd_write_output(AUX_INTS_OFF); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - } + if (rqst == PM_RESUME) { + if (queue) { /* Aux port detected */ + if (aux_count == 0) { /* Mouse not in use */ + spin_lock_irqsave(&kbd_controller_lock, flags); + /* + * Dell Lat. C600 A06 enables mouse after resume. + * When user touches the pad, it posts IRQ 12 + * (which we do not process), thus holding keyboard. + */ + kbd_write_command(KBD_CCMD_MOUSE_DISABLE); + /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MODE); + kb_wait(); + kbd_write_output(AUX_INTS_OFF); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + } + } } -#endif +#endif + return 0; } diff --git a/drivers/char/random.c b/drivers/char/random.c index 50d3aa3e1033..ddd026519100 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -406,10 +406,6 @@ static void sysctl_init_random(struct entropy_store *random_state); * *****************************************************************/ -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - /* * Unfortunately, while the GCC optimizer for the i386 understands how * to optimize a static rotate left of x bits, it doesn't know how to @@ -1360,7 +1356,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void * buf, #endif /* Copy data to destination buffer */ - i = MIN(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2); + i = min(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2); if (flags & EXTRACT_ENTROPY_USER) { i -= copy_to_user(buf, (__u8 const *)tmp, i); if (!i) { @@ -1587,7 +1583,7 @@ random_write(struct file * file, const char * buffer, size_t c = count; while (c > 0) { - bytes = MIN(c, sizeof(buf)); + bytes = min(c, sizeof(buf)); bytes -= copy_from_user(&buf, p, bytes); if (!bytes) { diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 33edd15a7b8f..fd097a69ab17 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -712,8 +712,10 @@ found: uip_watchdog = jiffies; if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) + while (jiffies - uip_watchdog < 2*HZ/100) { barrier(); + cpu_relax(); + } spin_lock_irq(&rtc_lock); year = CMOS_READ(RTC_YEAR); @@ -946,8 +948,10 @@ static void get_rtc_time(struct rtc_time *rtc_tm) */ if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) + while (jiffies - uip_watchdog < 2*HZ/100) { barrier(); + cpu_relax(); + } /* * Only the values that we read from the RTC are set. We leave diff --git a/drivers/char/serial.c b/drivers/char/serial.c index ed092b2fea0b..dff867aae80e 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -85,6 +85,11 @@ static char *serial_revdate = "2001-07-08"; * SERIAL_PARANOIA_CHECK * Check the magic number for the async_structure where * ever possible. + * + * CONFIG_SERIAL_ACPI + * Enable support for serial console port and serial + * debug port as defined by the SPCR and DBGP tables in + * ACPI 2.0. */ #include @@ -113,6 +118,10 @@ static char *serial_revdate = "2001-07-08"; #endif #endif +#ifdef CONFIG_SERIAL_ACPI +#define ENABLE_SERIAL_ACPI +#endif + #if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) #ifndef ENABLE_SERIAL_PNP #define ENABLE_SERIAL_PNP @@ -1766,13 +1775,11 @@ static void change_speed(struct async_struct *info, if (I_IGNPAR(info->tty)) info->ignore_status_mask |= UART_LSR_OE; } -#if 0 /* breaks serial console during boot stage */ /* * !!! ignore all characters if CREAD is not set */ if ((cflag & CREAD) == 0) info->ignore_status_mask |= UART_LSR_DR; -#endif save_flags(flags); cli(); if (uart_config[info->state->type].flags & UART_STARTECH) { serial_outp(info, UART_LCR, 0xBF); @@ -2243,7 +2250,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value) ((CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) > 0) && !info->tty->stopped && !info->tty->hw_stopped)) - result &= TIOCSER_TEMT; + result &= ~TIOCSER_TEMT; if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -2355,7 +2362,7 @@ static int do_autoconfig(struct async_struct * info) autoconfig(info->state); if ((info->state->flags & ASYNC_AUTO_IRQ) && - (info->state->port != 0) && + (info->state->port != 0 || info->state->iomem_base != 0) && (info->state->type != PORT_UNKNOWN)) { irq = detect_uart_irq(info->state); if (irq > 0) @@ -3384,6 +3391,10 @@ static char serial_options[] __initdata = " ISAPNP" #define SERIAL_OPT #endif +#ifdef ENABLE_SERIAL_ACPI + " SERIAL_ACPI" +#define SERIAL_OPT +#endif #ifdef SERIAL_OPT " enabled\n"; #else @@ -5475,13 +5486,22 @@ static int __init rs_init(void) continue; if ( (state->flags & ASYNC_BOOT_AUTOCONF) && (state->flags & ASYNC_AUTO_IRQ) - && (state->port != 0)) + && (state->port != 0 || state->iomem_base != 0)) state->irq = detect_uart_irq(state); - printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n", - state->line + SERIAL_DEV_OFFSET, - (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", - state->port, state->irq, - uart_config[state->type].name); + if (state->io_type == SERIAL_IO_MEM) { + printk(KERN_INFO"ttyS%02d%s at 0x%px (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", + state->iomem_base, state->irq, + uart_config[state->type].name); + } + else { + printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", + state->port, state->irq, + uart_config[state->type].name); + } tty_register_devfs(&serial_driver, 0, serial_driver.minor_start + state->line); tty_register_devfs(&callout_driver, 0, diff --git a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c index 57a030c6b30f..d3601cc5fc6b 100644 --- a/drivers/char/serial_tx3912.c +++ b/drivers/char/serial_tx3912.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index f4b72eb6b9a2..d4e8d6e5d4f4 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -969,7 +969,10 @@ extern inline int sx_setup_board(struct specialix_board * bp) if (bp->flags & SX_BOARD_ACTIVE) return 0; - error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp); + if (bp->flags & SX_BOARD_IS_PCI) + error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT | SA_SHIRQ, "specialix IO8+", bp); + else + error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp); if (error) return error; diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 42b38fd31735..a74df076dd8d 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -257,6 +257,11 @@ #define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000 #endif +static struct pci_device_id sx_pci_tbl[] = { + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, sx_pci_tbl); /* Configurable options: (Don't be too sure that it'll work if you toggle them) */ diff --git a/drivers/hotplug/Config.in b/drivers/hotplug/Config.in new file mode 100644 index 000000000000..c47588c2932a --- /dev/null +++ b/drivers/hotplug/Config.in @@ -0,0 +1,12 @@ +# +# PCI Hotplug support +# +mainmenu_option next_comment +comment 'PCI Hotplug Support' + +dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_DDFS $CONFIG_EXPERIMENTAL + +dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI +dep_mbool ' Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ + +endmenu diff --git a/drivers/hotplug/Makefile b/drivers/hotplug/Makefile new file mode 100644 index 000000000000..63cd2165c076 --- /dev/null +++ b/drivers/hotplug/Makefile @@ -0,0 +1,34 @@ +# +# Makefile for the Linux kernel pci hotplug controller drivers. +# + +O_TARGET := vmlinux-obj.o + +list-multi := cpqphp.o pci_hotplug.o + +export-objs := pci_hotplug_core.o pci_hotplug_util.o + +obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o +obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o + +pci_hotplug-objs := pci_hotplug_core.o \ + pci_hotplug_util.o + +cpqphp-objs := cpqphp_core.o \ + cpqphp_ctrl.o \ + cpqphp_proc.o \ + cpqphp_pci.o + +ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) + cpqphp-objs += cpqphp_nvram.o +endif + + +include $(TOPDIR)/Rules.make + +pci_hotplug.o: $(pci_hotplug-objs) + $(LD) -r -o $@ $(pci_hotplug-objs) + +cpqphp.o: $(cpqphp-objs) + $(LD) -r -o $@ $(cpqphp-objs) + diff --git a/drivers/hotplug/cpqphp.h b/drivers/hotplug/cpqphp.h new file mode 100644 index 000000000000..618bf2c739d2 --- /dev/null +++ b/drivers/hotplug/cpqphp.h @@ -0,0 +1,751 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ +#ifndef _CPQPHP_H +#define _CPQPHP_H + +#include "pci_hotplug.h" +#include /* for read? and write? functions */ + + +#if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE) + #define MY_NAME "cpqphp.o" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + + +struct smbios_system_slot { + u8 type; + u8 length; + u16 handle; + u8 name_string_num; + u8 slot_type; + u8 slot_width; + u8 slot_current_usage; + u8 slot_length; + u16 slot_number; + u8 properties1; + u8 properties2; +} __attribute__ ((packed)); + +/* offsets to the smbios generic type based on the above structure layout */ +enum smbios_system_slot_offsets { + SMBIOS_SLOT_GENERIC_TYPE = offsetof(struct smbios_system_slot, type), + SMBIOS_SLOT_GENERIC_LENGTH = offsetof(struct smbios_system_slot, length), + SMBIOS_SLOT_GENERIC_HANDLE = offsetof(struct smbios_system_slot, handle), + SMBIOS_SLOT_NAME_STRING_NUM = offsetof(struct smbios_system_slot, name_string_num), + SMBIOS_SLOT_TYPE = offsetof(struct smbios_system_slot, slot_type), + SMBIOS_SLOT_WIDTH = offsetof(struct smbios_system_slot, slot_width), + SMBIOS_SLOT_CURRENT_USAGE = offsetof(struct smbios_system_slot, slot_current_usage), + SMBIOS_SLOT_LENGTH = offsetof(struct smbios_system_slot, slot_length), + SMBIOS_SLOT_NUMBER = offsetof(struct smbios_system_slot, slot_number), + SMBIOS_SLOT_PROPERTIES1 = offsetof(struct smbios_system_slot, properties1), + SMBIOS_SLOT_PROPERTIES2 = offsetof(struct smbios_system_slot, properties2), +}; + +struct smbios_generic { + u8 type; + u8 length; + u16 handle; +} __attribute__ ((packed)); + +/* offsets to the smbios generic type based on the above structure layout */ +enum smbios_generic_offsets { + SMBIOS_GENERIC_TYPE = offsetof(struct smbios_generic, type), + SMBIOS_GENERIC_LENGTH = offsetof(struct smbios_generic, length), + SMBIOS_GENERIC_HANDLE = offsetof(struct smbios_generic, handle), +}; + +struct smbios_entry_point { + char anchor[4]; + u8 ep_checksum; + u8 ep_length; + u8 major_version; + u8 minor_version; + u16 max_size_entry; + u8 ep_rev; + u8 reserved[5]; + char int_anchor[5]; + u8 int_checksum; + u16 st_length; + u32 st_address; + u16 number_of_entrys; + u8 bcd_rev; +} __attribute__ ((packed)); + +/* offsets to the smbios entry point based on the above structure layout */ +enum smbios_entry_point_offsets { + ANCHOR = offsetof(struct smbios_entry_point, anchor[0]), + EP_CHECKSUM = offsetof(struct smbios_entry_point, ep_checksum), + EP_LENGTH = offsetof(struct smbios_entry_point, ep_length), + MAJOR_VERSION = offsetof(struct smbios_entry_point, major_version), + MINOR_VERSION = offsetof(struct smbios_entry_point, minor_version), + MAX_SIZE_ENTRY = offsetof(struct smbios_entry_point, max_size_entry), + EP_REV = offsetof(struct smbios_entry_point, ep_rev), + INT_ANCHOR = offsetof(struct smbios_entry_point, int_anchor[0]), + INT_CHECKSUM = offsetof(struct smbios_entry_point, int_checksum), + ST_LENGTH = offsetof(struct smbios_entry_point, st_length), + ST_ADDRESS = offsetof(struct smbios_entry_point, st_address), + NUMBER_OF_ENTRYS = offsetof(struct smbios_entry_point, number_of_entrys), + BCD_REV = offsetof(struct smbios_entry_point, bcd_rev), +}; + +struct ctrl_reg { /* offset */ + u8 slot_RST; /* 0x00 */ + u8 slot_enable; /* 0x01 */ + u16 misc; /* 0x02 */ + u32 led_control; /* 0x04 */ + u32 int_input_clear; /* 0x08 */ + u32 int_mask; /* 0x0a */ + u8 reserved0; /* 0x10 */ + u8 reserved1; /* 0x11 */ + u8 reserved2; /* 0x12 */ + u8 gen_output_AB; /* 0x13 */ + u32 non_int_input; /* 0x14 */ + u32 reserved3; /* 0x18 */ + u32 reserved4; /* 0x1a */ + u32 reserved5; /* 0x20 */ + u8 reserved6; /* 0x24 */ + u8 reserved7; /* 0x25 */ + u16 reserved8; /* 0x26 */ + u8 slot_mask; /* 0x28 */ + u8 reserved9; /* 0x29 */ + u8 reserved10; /* 0x2a */ + u8 reserved11; /* 0x2b */ + u8 slot_SERR; /* 0x2c */ + u8 slot_power; /* 0x2d */ +} __attribute__ ((packed)); + +/* offsets to the controller registers based on the above structure layout */ +enum ctrl_offsets { + SLOT_RST = offsetof(struct ctrl_reg, slot_RST), + SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), + MISC = offsetof(struct ctrl_reg, misc), + LED_CONTROL = offsetof(struct ctrl_reg, led_control), + INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), + INT_MASK = offsetof(struct ctrl_reg, int_mask), + CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), + CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), + CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), + GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), + NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), + CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), + CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), + CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), + CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), + CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), + CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), + SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), + CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), + CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), + CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), + SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), + SLOT_POWER = offsetof(struct ctrl_reg, slot_power), +}; + +struct hrt { + char sig0; + char sig1; + char sig2; + char sig3; + u16 unused_IRQ; + u16 PCIIRQ; + u8 number_of_entries; + u8 revision; + u16 reserved1; + u32 reserved2; +} __attribute__ ((packed)); + +/* offsets to the hotplug resource table registers based on the above structure layout */ +enum hrt_offsets { + SIG0 = offsetof(struct hrt, sig0), + SIG1 = offsetof(struct hrt, sig1), + SIG2 = offsetof(struct hrt, sig2), + SIG3 = offsetof(struct hrt, sig3), + UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), + PCIIRQ = offsetof(struct hrt, PCIIRQ), + NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), + REVISION = offsetof(struct hrt, revision), + HRT_RESERVED1 = offsetof(struct hrt, reserved1), + HRT_RESERVED2 = offsetof(struct hrt, reserved2), +}; + +struct slot_rt { + u8 dev_func; + u8 primary_bus; + u8 secondary_bus; + u8 max_bus; + u16 io_base; + u16 io_length; + u16 mem_base; + u16 mem_length; + u16 pre_mem_base; + u16 pre_mem_length; +} __attribute__ ((packed)); + +/* offsets to the hotplug slot resource table registers based on the above structure layout */ +enum slot_rt_offsets { + DEV_FUNC = offsetof(struct slot_rt, dev_func), + PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), + SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), + MAX_BUS = offsetof(struct slot_rt, max_bus), + IO_BASE = offsetof(struct slot_rt, io_base), + IO_LENGTH = offsetof(struct slot_rt, io_length), + MEM_BASE = offsetof(struct slot_rt, mem_base), + MEM_LENGTH = offsetof(struct slot_rt, mem_length), + PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), + PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), +}; + +struct pci_func { + struct pci_func *next; + u8 bus; + u8 device; + u8 function; + u8 is_a_board; + u16 status; + u8 configured; + u8 switch_save; + u8 presence_save; + u32 base_length[0x06]; + u8 base_type[0x06]; + u16 reserved2; + u32 config_space[0x20]; + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct timer_list *p_task_event; + struct pci_dev* pci_dev; +}; + +#define SLOT_MAGIC 0x67267321 +struct slot { + u32 magic; + struct slot *next; + u8 bus; + u8 device; + u8 number; + u8 is_a_board; + u8 configured; + u8 state; + u8 switch_save; + u8 presence_save; + u32 capabilities; + u16 reserved2; + struct timer_list task_event; + u8 hp_slot; + struct controller *ctrl; + void *p_sm_slot; + struct hotplug_slot *hotplug_slot; +}; + +struct pci_resource { + struct pci_resource * next; + u32 base; + u32 length; +}; + +struct event_info { + u32 event_type; + u8 hp_slot; +}; + +struct controller { + struct controller *next; + u32 ctrl_int_comp; + struct semaphore crit_sect; /* critical section semaphore */ + void *hpc_reg; /* cookie for our pci controller location */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct pci_dev *pci_dev; + struct pci_ops *pci_ops; + struct proc_dir_entry* proc_entry; + struct proc_dir_entry* proc_entry2; + struct event_info event_queue[10]; + struct slot *slot; + u8 next_event; + u8 interrupt; + u8 bus; + u8 device; + u8 function; + u8 rev; + u8 slot_device_offset; + u8 first_slot; + u8 add_support; + u8 push_flag; + u8 speed; /* 0 = 33MHz, 1 = 66MHz */ + u8 speed_capability; /* 0 = 33MHz, 1 = 66MHz */ + u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ + u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ + u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ + u8 alternate_base_address; /* 0 = not supported, 1 = supported */ + u8 pci_config_space; /* Index/data access to working registers 0 = not supported, 1 = supported */ + u8 pcix_speed_capability; /* PCI-X */ + u8 pcix_support; /* PCI-X */ + u16 vendor_id; + char proc_name[20]; + char proc_name2[20]; + struct tq_struct int_task_event; + wait_queue_head_t queue; /* sleep & wake process */ +}; + +#define CTRL_SPEED_33MHz 0 +#define CTRL_SPEED_66MHz 1 + +struct irq_mapping { + u8 barber_pole; + u8 valid_INT; + u8 interrupt[4]; +}; + +struct resource_lists { + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct irq_mapping *irqs; +}; + +#define ROM_PHY_ADDR 0x0F0000 +#define ROM_PHY_LEN 0x00ffff + +#define PCI_HPC_ID 0xA0F7 +#define PCI_SUB_HPC_ID 0xA2F7 +#define PCI_SUB_HPC_ID2 0xA2F8 +#define PCI_SUB_HPC_ID3 0xA2F9 +#define PCI_SUB_HPC_ID_INTC 0xA2FA + +#define INT_BUTTON_IGNORE 0 +#define INT_PRESENCE_ON 1 +#define INT_PRESENCE_OFF 2 +#define INT_SWITCH_CLOSE 3 +#define INT_SWITCH_OPEN 4 +#define INT_POWER_FAULT 5 +#define INT_POWER_FAULT_CLEAR 6 +#define INT_BUTTON_PRESS 7 +#define INT_BUTTON_RELEASE 8 +#define INT_BUTTON_CANCEL 9 + +#define STATIC_STATE 0 +#define BLINKINGON_STATE 1 +#define BLINKINGOFF_STATE 2 +#define POWERON_STATE 3 +#define POWEROFF_STATE 4 + +#define PCISLOT_INTERLOCK_CLOSED 0x00000001 +#define PCISLOT_ADAPTER_PRESENT 0x00000002 +#define PCISLOT_POWERED 0x00000004 +#define PCISLOT_66_MHZ_OPERATION 0x00000008 +#define PCISLOT_64_BIT_OPERATION 0x00000010 +#define PCISLOT_REPLACE_SUPPORTED 0x00000020 +#define PCISLOT_ADD_SUPPORTED 0x00000040 +#define PCISLOT_INTERLOCK_SUPPORTED 0x00000080 +#define PCISLOT_66_MHZ_SUPPORTED 0x00000100 +#define PCISLOT_64_BIT_SUPPORTED 0x00000200 + + + +#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 + + +#define INTERLOCK_OPEN 0x00000002 +#define ADD_NOT_SUPPORTED 0x00000003 +#define CARD_FUNCTIONING 0x00000005 +#define ADAPTER_NOT_SAME 0x00000006 +#define NO_ADAPTER_PRESENT 0x00000009 +#define NOT_ENOUGH_RESOURCES 0x0000000B +#define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C +#define POWER_FAILURE 0x0000000E + +#define REMOVE_NOT_SUPPORTED 0x00000003 + + +/* + * error Messages + */ +#define msg_initialization_err "Initialization failure, error=%d\n" +#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" +#define msg_HPC_non_compaq_or_intel "The PCI hot plug controller is not supported by this driver.\n" +#define msg_HPC_not_supported "this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n" +#define msg_unable_to_save "unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" +#define msg_button_on "PCI slot #%d - powering on due to button press.\n" +#define msg_button_off "PCI slot #%d - powering off due to button press.\n" +#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" +#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" + + +/* Proc functions for the hotplug controller info */ +#ifdef CONFIG_PROC_FS +extern int cpqhp_proc_init_ctrl (void); +extern int cpqhp_proc_destroy_ctrl (void); +extern int cpqhp_proc_create_ctrl (struct controller *ctrl); +extern int cpqhp_proc_remove_ctrl (struct controller *ctrl); +#else +static inline int cpqhp_proc_init_ctrl (void) +{ + return 0; +} +static inline int cpqhp_proc_destroy_ctrl (void) +{ + return 0; +} +static inline int cpqhp_proc_create_ctrl (struct controller *ctrl) +{ + return 0; +} +static inline int cpqhp_proc_remove_ctrl (struct controller *ctrl) +{ + return 0; +} +#endif + + +/* controller functions */ +extern void cpqhp_pushbutton_thread (unsigned long event_pointer); +extern void cpqhp_ctrl_intr (int IRQ, struct controller *ctrl_input, struct pt_regs *regs); +extern int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start); +extern int cpqhp_event_start_thread (void); +extern void cpqhp_event_stop_thread (void); +extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); +extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); +extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); +extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); +extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); + +/* resource functions */ +extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); + +/* pci functions */ +extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); +extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); +extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); +extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); +extern void cpqhp_destroy_board_resources (struct pci_func * func); +extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); +extern void cpqhp_destroy_resource_list (struct resource_lists * resources); +extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); +extern int cpqhp_unconfigure_device (struct pci_func* func); + + +/* Global variables */ +extern int cpqhp_debug; +extern struct controller *cpqhp_ctrl_list; +extern struct pci_func *cpqhp_slot_list[256]; + +/* these can be gotten rid of, but for debugging they are purty */ +extern u8 cpqhp_nic_irq; +extern u8 cpqhp_disk_irq; + + + +/* inline functions */ + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + +/* + * return_resource + * + * Puts node back in the resource list pointed to by head + * + */ +static inline void return_resource (struct pci_resource **head, struct pci_resource *node) +{ + if (!node || !head) + return; + node->next = *head; + *head = node; +} + +static inline void set_SOGO (struct controller *ctrl) +{ + u16 misc; + + misc = readw(ctrl->hpc_reg + MISC); + misc = (misc | 0x0001) & 0xFFFB; + writew(misc, ctrl->hpc_reg + MISC); +} + + +static inline void amber_LED_on (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= (0x01010000L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void amber_LED_off (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x01010000L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline int read_amber_LED (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= (0x01010000L << slot); + + return led_control ? 1 : 0; +} + + +static inline void green_LED_on (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= 0x0101L << slot; + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + +static inline void green_LED_off (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x0101L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void green_LED_blink (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= (0x0001L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void slot_disable (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable &= ~(0x01 << slot); + writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline void slot_enable (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable |= (0x01 << slot); + writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline u8 is_slot_enabled (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable &= (0x01 << slot); + return slot_enable ? 1 : 0; +} + + +static inline u8 read_slot_enable (struct controller *ctrl) +{ + return readb(ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline u8 get_controller_speed (struct controller *ctrl) +{ + u16 misc; + + misc = readw(ctrl->hpc_reg + MISC); + return (misc & 0x0800) ? 1 : 0; +} + + +static inline void enable_slot_power (struct controller *ctrl, u8 slot) +{ + u8 slot_power; + + slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + slot_power |= (0x01 << slot); + writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); +} + +static inline void disable_slot_power (struct controller *ctrl, u8 slot) +{ + u8 slot_power; + + slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + slot_power &= ~(0x01 << slot); + writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); +} + + +static inline int cpq_get_attention_status (struct controller *ctrl, struct slot *slot) +{ + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + + return read_amber_LED (ctrl, hp_slot); +} + + +static inline int get_slot_enabled (struct controller *ctrl, struct slot *slot) +{ + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + + return is_slot_enabled (ctrl, hp_slot); +} + + +static inline int cpq_get_latch_status (struct controller *ctrl, struct slot *slot) +{ + u32 status; + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + dbg(__FUNCTION__": slot->device = %d, ctrl->slot_device_offset = %d \n", slot->device, ctrl->slot_device_offset); + + status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); + + return(status == 0) ? 1 : 0; +} + + +static inline int get_presence_status (struct controller *ctrl, struct slot *slot) +{ + int presence_save = 0; + u8 hp_slot; + u32 tempdword; + + if (slot == NULL) + return 0; + + hp_slot = slot->device - ctrl->slot_device_offset; + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; + + return presence_save; +} + +#define SLOT_NAME_SIZE 10 + +static inline void make_slot_name (char *buffer, int buffer_size, struct slot *slot) +{ + snprintf (buffer, buffer_size, "%d", slot->number); +} + + +static inline int wait_for_ctrl_irq (struct controller *ctrl) +{ + DECLARE_WAITQUEUE(wait, current); + int retval = 0; + + dbg(__FUNCTION__" - start\n"); + add_wait_queue(&ctrl->queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + /* Sleep for up to 1 second to wait for the LED to change. */ + schedule_timeout(1*HZ); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctrl->queue, &wait); + if (signal_pending(current)) + retval = -EINTR; + + dbg(__FUNCTION__" - end\n"); + return retval; +} + +#endif + diff --git a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c new file mode 100644 index 000000000000..5b4861915c72 --- /dev/null +++ b/drivers/hotplug/cpqphp_core.c @@ -0,0 +1,1439 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpqphp.h" +#include "cpqphp_nvram.h" +#include "../../arch/i386/kernel/pci-i386.h" /* horrible hack showing how processor dependant we are... */ + + +/* Global variables */ +int cpqhp_debug; +struct controller *cpqhp_ctrl_list; /* = NULL */ +struct pci_func *cpqhp_slot_list[256]; + +/* local variables */ +static void *smbios_table; +static void *smbios_start; +static void *cpqhp_rom_start; +static u8 power_mode; +static int debug; + +#define DRIVER_VERSION "0.9.6" +#define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman " +#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_PARM(power_mode, "b"); +MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +#define CPQHPC_MODULE_MINOR 208 + +static int one_time_init (void); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int process_SI (struct hotplug_slot *slot); +static int process_SS (struct hotplug_slot *slot); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { + owner: THIS_MODULE, + set_attention_status: set_attention_status, + enable_slot: process_SI, + disable_slot: process_SS, + hardware_test: hardware_test, + get_power_status: get_power_status, + get_attention_status: get_attention_status, + get_latch_status: get_latch_status, + get_adapter_status: get_adapter_status, +}; + + +static inline int is_slot64bit (struct slot *slot) +{ + if (!slot || !slot->p_sm_slot) + return 0; + + if (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) + return 1; + + return 0; +} + +static inline int is_slot66mhz (struct slot *slot) +{ + if (!slot || !slot->p_sm_slot) + return 0; + + if (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) + return 1; + + return 0; +} + +/** + * detect_SMBIOS_pointer - find the system Management BIOS Table in the specified region of memory. + * + * @begin: begin pointer for region to be scanned. + * @end: end pointer for region to be scanned. + * + * Returns pointer to the head of the SMBIOS tables (or NULL) + * + */ +static void * detect_SMBIOS_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(u32) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp); + temp2 = readb(fp+1); + temp3 = readb(fp+2); + temp4 = readb(fp+3); + if (temp1 == '_' && + temp2 == 'S' && + temp3 == 'M' && + temp4 == '_') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered SMBIOS Entry point at %p\n", fp); + + return fp; +} + +/** + * init_SERR - Initializes the per slot SERR generation. + * + * For unexpected switch opens + * + */ +static int init_SERR(struct controller * ctrl) +{ + u32 tempdword; + u32 number_of_slots; + u8 physical_slot; + + if (!ctrl) + return 1; + + tempdword = ctrl->first_slot; + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + // Loop through slots + while (number_of_slots) { + physical_slot = tempdword; + writeb(0, ctrl->hpc_reg + SLOT_SERR); + tempdword++; + number_of_slots--; + } + + return 0; +} + + +/* nice debugging output */ +static int pci_print_IRQ_route (void) +{ + struct irq_routing_table *routing_table; + int len; + int loop; + + u8 tbus, tdevice, tslot; + + routing_table = pcibios_get_irq_routing_table(); + if (routing_table == NULL) { + err("No BIOS Routing Table??? Not good\n"); + return -ENOMEM; + } + + len = (routing_table->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + kfree(routing_table); + return -1; + } + + dbg("bus dev func slot\n"); + + for (loop = 0; loop < len; ++loop) { + tbus = routing_table->slots[loop].bus; + tdevice = routing_table->slots[loop].devfn; + tslot = routing_table->slots[loop].slot; + dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); + + } + kfree(routing_table); + return 0; +} + + +/* + * get_subsequent_smbios_entry + * + * Gets the first entry if previous == NULL + * Otherwise, returns the next entry + * Uses global SMBIOS Table pointer + * + * @curr: %NULL or pointer to previously returned structure + * + * returns a pointer to an SMBIOS structure or NULL if none found + */ +static void * get_subsequent_smbios_entry(void *smbios_start, void *smbios_table, void *curr) +{ + u8 bail = 0; + u8 previous_byte = 1; + void *p_temp; + void *p_max; + + if (!smbios_table || !curr) + return(NULL); + + // set p_max to the end of the table + p_max = smbios_start + readw(smbios_table + ST_LENGTH); + + p_temp = curr; + p_temp += readb(curr + SMBIOS_GENERIC_LENGTH); + + while ((p_temp < p_max) && !bail) { + // Look for the double NULL terminator + // The first condition is the previous byte and the second is the curr + if (!previous_byte && !(readb(p_temp))) { + bail = 1; + } + + previous_byte = readb(p_temp); + p_temp++; + } + + if (p_temp < p_max) { + return p_temp; + } else { + return NULL; + } +} + + +/** + * get_SMBIOS_entry + * + * @type:SMBIOS structure type to be returned + * @previous: %NULL or pointer to previously returned structure + * + * Gets the first entry of the specified type if previous == NULL + * Otherwise, returns the next entry of the given type. + * Uses global SMBIOS Table pointer + * Uses get_subsequent_smbios_entry + * + * returns a pointer to an SMBIOS structure or %NULL if none found + */ +static void *get_SMBIOS_entry (void *smbios_start, void *smbios_table, u8 type, void * previous) +{ + if (!smbios_table) + return NULL; + + if (!previous) { + previous = smbios_start; + } else { + previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); + } + + while (previous) { + if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { + previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); + } else { + break; + } + } + + return previous; +} + + +static int ctrl_slot_setup (struct controller * ctrl, void *smbios_start, void *smbios_table) +{ + struct slot *new_slot; + u8 number_of_slots; + u8 slot_device; + u8 slot_number; + u8 ctrl_slot; + u32 tempdword; + void *slot_entry= NULL; + int result; + + dbg(__FUNCTION__"\n"); + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); + if (!new_slot) + return -ENOMEM; + + memset(new_slot, 0, sizeof(struct slot)); + new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!new_slot->hotplug_slot) { + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + + new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!new_slot->hotplug_slot->info) { + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!new_slot->hotplug_slot->name) { + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + + new_slot->magic = SLOT_MAGIC; + new_slot->ctrl = ctrl; + new_slot->bus = ctrl->bus; + new_slot->device = slot_device; + new_slot->number = slot_number; + dbg("slot->number = %d\n",new_slot->number); + + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); + + while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) { + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); + } + + new_slot->p_sm_slot = slot_entry; + + init_timer(&new_slot->task_event); + new_slot->task_event.expires = jiffies + 5 * HZ; + new_slot->task_event.function = cpqhp_pushbutton_thread; + + //FIXME: these capabilities aren't used but if they are + // they need to be correctly implemented + new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; + new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; + + if (is_slot64bit(new_slot)) + new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; + if (is_slot66mhz(new_slot)) + new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; + if (ctrl->speed == 1) + new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; + + ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); + + // Check presence + new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; + // Check the switch state + new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; + // Check the slot enable + new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; + + /* register this slot with the hotplug pci core */ + new_slot->hotplug_slot->private = new_slot; + make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); + new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops; + + new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot); + new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot); + new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot); + new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot); + + dbg ("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", + new_slot->bus, new_slot->device, new_slot->number, ctrl->slot_device_offset, slot_number); + result = pci_hp_register (new_slot->hotplug_slot); + if (result) { + err ("pci_hp_register failed with error %d\n", result); + return result; + } + + new_slot->next = ctrl->slot; + ctrl->slot = new_slot; + + number_of_slots--; + slot_device++; + slot_number++; + } + + return(0); +} + + +static int ctrl_slot_cleanup (struct controller * ctrl) +{ + struct slot *old_slot, *next_slot; + + old_slot = ctrl->slot; + ctrl->slot = NULL; + + while (old_slot) { + next_slot = old_slot->next; + pci_hp_deregister (old_slot->hotplug_slot); + kfree(old_slot->hotplug_slot); + kfree(old_slot); + old_slot = next_slot; + } + + //Free IRQ associated with hot plug device + free_irq(ctrl->interrupt, ctrl); + //Unmap the memory + iounmap(ctrl->hpc_reg); + //Finally reclaim PCI mem + release_mem_region(pci_resource_start(ctrl->pci_dev, 0), + pci_resource_len(ctrl->pci_dev, 0)); + + return(0); +} + + +//============================================================================ +// function: get_slot_mapping +// +// Description: Attempts to determine a logical slot mapping for a PCI +// device. Won't work for more than one PCI-PCI bridge +// in a slot. +// +// Input: u8 bus_num - bus number of PCI device +// u8 dev_num - device number of PCI device +// u8 *slot - Pointer to u8 where slot number will +// be returned +// +// Output: SUCCESS or FAILURE +//============================================================================= +static int get_slot_mapping (struct pci_ops *ops, u8 bus_num, u8 dev_num, u8 *slot) +{ + struct irq_routing_table *PCIIRQRoutingInfoLength; + u32 work; + long len; + long loop; + + u8 tbus, tdevice, tslot, bridgeSlot; + + dbg(__FUNCTION__" %p, %d, %d, %p\n", ops, bus_num, dev_num, slot); + + bridgeSlot = 0xFF; + + PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); + + len = (PCIIRQRoutingInfoLength->size - + sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return -1; + } + + + for (loop = 0; loop < len; ++loop) { + tbus = PCIIRQRoutingInfoLength->slots[loop].bus; + tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; + tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + + if ((tbus == bus_num) && (tdevice == dev_num)) { + *slot = tslot; + + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return 0; + } else { + // Didn't get a match on the target PCI device. Check if the + // current IRQ table entry is a PCI-to-PCI bridge device. If so, + // and it's secondary bus matches the bus number for the target + // device, I need to save the bridge's slot number. If I can't + // find an entry for the target device, I will have to assume it's + // on the other side of the bridge, and assign it the bridge's slot. + pci_read_config_dword_nodev (ops, tbus, tdevice, 0, PCI_REVISION_ID, &work); + + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_read_config_dword_nodev (ops, tbus, tdevice, 0, PCI_PRIMARY_BUS, &work); + // See if bridge's secondary bus matches target bus. + if (((work >> 8) & 0x000000FF) == (long) bus_num) { + bridgeSlot = tslot; + } + } + } + + } + + + // If we got here, we didn't find an entry in the IRQ mapping table + // for the target PCI device. If we did determine that the target + // device is on the other side of a PCI-to-PCI bridge, return the + // slot number for the bridge. + if (bridgeSlot != 0xFF) { + *slot = bridgeSlot; + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return 0; + } + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + // Couldn't find an entry in the routing table for this PCI device + return -1; +} + + +/** + * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off + * + */ +static int cpqhp_set_attention_status (struct controller *ctrl, struct pci_func *func, u32 status) +{ + u8 hp_slot; + + hp_slot = func->device - ctrl->slot_device_offset; + + if (func == NULL) + return(1); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + if (status == 1) { + amber_LED_on (ctrl, hp_slot); + } else if (status == 0) { + amber_LED_off (ctrl, hp_slot); + } else { + // Done with exclusive hardware access + up(&ctrl->crit_sect); + return(1); + } + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(0); +} + + +/** + * set_attention_status - Turns the Amber LED for a slot on or off + * + */ +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + return cpqhp_set_attention_status(ctrl, slot_func, status); +} + + +static int process_SI (struct hotplug_slot *hotplug_slot) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + slot_func->bus = bus; + slot_func->device = device; + slot_func->function = function; + slot_func->configured = 0; + dbg("board_added(%p, %p)\n", slot_func, ctrl); + return cpqhp_process_SI(ctrl, slot_func); +} + + +static int process_SS (struct hotplug_slot *hotplug_slot) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + dbg("In power_down_board, slot_func = %p, ctrl = %p\n", slot_func, ctrl); + return cpqhp_process_SS(ctrl, slot_func); +} + + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + dbg(__FUNCTION__"\n"); + + if (slot == NULL) + return -ENODEV; + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + return cpqhp_hardware_test (ctrl, value); +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = get_slot_enabled(ctrl, slot); + return 0; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = cpq_get_attention_status(ctrl, slot); + return 0; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = cpq_get_latch_status (ctrl, slot); + + return 0; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = get_presence_status (ctrl, slot); + + return 0; +} + +static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + u8 num_of_slots = 0; + u8 hp_slot = 0; + u8 device; + u8 rev; + u16 temp_word; + u16 vendor_id; + u16 subsystem_vid; + u16 subsystem_deviceid; + u32 rc; + struct controller *ctrl; + struct pci_func *func; + + // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery + rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); + if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { + err(msg_HPC_non_compaq_or_intel); + return -ENODEV; + } + dbg("Vendor ID: %x\n", vendor_id); + + rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + dbg("revision: %d\n", rev); + if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { + err(msg_HPC_rev_error); + return -ENODEV; + } + + /* Check for the proper subsytem ID's + * Intel uses a different SSID programming model than Compaq. + * For Intel, each SSID bit identifies a PHP capability. + * Also Intel HPC's may have RID=0. + */ + if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { + // TODO: This code can be made to support non-Compaq or Intel subsystem IDs + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); + if (rc) { + err(__FUNCTION__" : pci_read_config_word failed\n"); + return rc; + } + dbg("Subsystem Vendor ID: %x\n", subsystem_vid); + if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { + err(msg_HPC_non_compaq_or_intel); + return -ENODEV; + } + + ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err(__FUNCTION__" : out of memory\n"); + return -ENOMEM; + } + memset(ctrl, 0, sizeof(struct controller)); + + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); + if (rc) { + err(__FUNCTION__" : pci_read_config_word failed\n"); + goto err_free_ctrl; + } + + info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); + + /* Set Vendor ID, so it can be accessed later from other functions */ + ctrl->vendor_id = vendor_id; + + switch (subsystem_vid) { + case PCI_VENDOR_ID_COMPAQ: + switch (subsystem_deviceid) { + case PCI_SUB_HPC_ID: + /* Original 6500/7000 implementation */ + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->push_button = 0; // No pushbutton + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID2: + /* First Pushbutton implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID_INTC: + /* Third party (6500/7000) */ + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->push_button = 0; // No pushbutton + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID3: + /* First 66 Mhz implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = CTRL_SPEED_66MHz; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + default: + // TODO: Add SSIDs for CPQ systems that support PCI-X + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + break; + + case PCI_VENDOR_ID_INTEL: + /* Check for speed capability (0=33, 1=66) */ + if (subsystem_deviceid & 0x0001) { + ctrl->speed_capability = CTRL_SPEED_66MHz; + } else { + ctrl->speed_capability = CTRL_SPEED_33MHz; + } + + /* Check for push button */ + if (subsystem_deviceid & 0x0002) { + /* no push button */ + ctrl->push_button = 0; + } else { + /* push button supported */ + ctrl->push_button = 1; + } + + /* Check for slot switch type (0=mechanical, 1=not mechanical) */ + if (subsystem_deviceid & 0x0004) { + /* no switch */ + ctrl->slot_switch_type = 0; + } else { + /* switch */ + ctrl->slot_switch_type = 1; + } + + /* PHP Status (0=De-feature PHP, 1=Normal operation) */ + if (subsystem_deviceid & 0x0008) { + ctrl->defeature_PHP = 1; // PHP supported + } else { + ctrl->defeature_PHP = 0; // PHP not supported + } + + /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0010) { + ctrl->alternate_base_address = 1; // supported + } else { + ctrl->alternate_base_address = 0; // not supported + } + + /* PCI Config Space Index (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0020) { + ctrl->pci_config_space = 1; // supported + } else { + ctrl->pci_config_space = 0; // not supported + } + + /* PCI-X support */ + if (subsystem_deviceid & 0x0080) { + /* PCI-X capable */ + ctrl->pcix_support = 1; + /* Frequency of operation in PCI-X mode */ + if (subsystem_deviceid & 0x0040) { + /* 133MHz PCI-X if bit 7 is 1 */ + ctrl->pcix_speed_capability = 1; + } else { + /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ + /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ + ctrl->pcix_speed_capability = 0; + } + } else { + /* Conventional PCI */ + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + } + break; + + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + + } else { + err(msg_HPC_not_supported); + return -ENODEV; + } + + // Tell the user that we found one. + info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); + + dbg ("Hotplug controller capabilities:\n"); + dbg (" speed_capability %s\n", ctrl->speed_capability == CTRL_SPEED_33MHz ? "33MHz" : "66Mhz"); + dbg (" slot_switch_type %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present"); + dbg (" defeature_PHP %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported"); + dbg (" alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported"); + dbg (" pci_config_space %s\n", ctrl->pci_config_space == 0 ? "not supported" : "supported"); + dbg (" pcix_speed_capability %s\n", ctrl->pcix_speed_capability == 0 ? "not supported" : "supported"); + dbg (" pcix_support %s\n", ctrl->pcix_support == 0 ? "not supported" : "supported"); + + ctrl->pci_dev = pdev; + ctrl->pci_ops = pdev->bus->ops; + ctrl->bus = pdev->bus->number; + ctrl->device = PCI_SLOT(pdev->devfn); + ctrl->function = PCI_FUNC(pdev->devfn); + ctrl->rev = rev; + dbg("bus device function rev: %d %d %d %d\n", ctrl->bus, ctrl->device, ctrl->function, ctrl->rev); + + init_MUTEX(&ctrl->crit_sect); + init_waitqueue_head(&ctrl->queue); + + /* initialize our threads if they haven't already been started up */ + rc = one_time_init(); + if (rc) { + goto err_free_ctrl; + } + + dbg("pdev = %p\n", pdev); + dbg("pci resource start %lx\n", pci_resource_start(pdev, 0)); + dbg("pci resource len %lx\n", pci_resource_len(pdev, 0)); + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), MY_NAME)) { + err("cannot reserve MMIO region\n"); + rc = -ENOMEM; + goto err_free_ctrl; + } + + ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!ctrl->hpc_reg) { + err("cannot remap MMIO region %lx @ %lx\n", pci_resource_len(pdev, 0), pci_resource_start(pdev, 0)); + rc = -ENODEV; + goto err_free_mem_region; + } + + // Check for 66Mhz operation + // TODO: Add PCI-X support + ctrl->speed = get_controller_speed(ctrl); + + + //************************************************** + // + // Save configuration headers for this and + // subordinate PCI buses + // + //************************************************** + + // find the physical slot number of the first hot plug slot + + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of a slot. + // CS: this is leveraging the PCIIRQ routing code from the kernel (pci-pc.c: get_irq_routing_table) + rc = get_slot_mapping(ctrl->pci_ops, pdev->bus->number, (readb(ctrl->hpc_reg + SLOT_MASK) >> 4), &(ctrl->first_slot)); + dbg("get_slot_mapping: first_slot = %d, returned = %d\n", ctrl->first_slot, rc); + if (rc) { + err(msg_initialization_err, rc); + goto err_iounmap; + } + + // Store PCI Config Space for all devices on this bus + rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); + if (rc) { + err(__FUNCTION__": unable to save PCI configuration data, error %d\n", rc); + goto err_iounmap; + } + + /* + * Get IO, memory, and IRQ resources for new devices + */ + rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start); + ctrl->add_support = !rc; + if (rc) { + dbg("cpqhp_find_available_resources = 0x%x\n", rc); + err("unable to locate PCI configuration resources for hot plug add.\n"); + goto err_iounmap; + } + + /* + * Finish setting up the hot plug ctrl device + */ + ctrl->slot_device_offset = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + dbg("NumSlots %d \n", ctrl->slot_device_offset); + + ctrl->next_event = 0; + + /* Setup the slot information structures */ + rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table); + if (rc) { + err(msg_initialization_err, 6); + err(__FUNCTION__": unable to save PCI configuration data, error %d\n", rc); + goto err_iounmap; + } + + /* Mask all general input interrupts */ + writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); + + /* set up the interrupt */ + ctrl->interrupt = pdev->irq; + dbg("HPC interrupt = %d \n", ctrl->interrupt); + if (request_irq(ctrl->interrupt, + (void (*)(int, void *, struct pt_regs *)) &cpqhp_ctrl_intr, + SA_SHIRQ, MY_NAME, ctrl)) { + err("Can't get irq %d for the hotplug pci controller\n", ctrl->interrupt); + rc = -ENODEV; + goto err_iounmap; + } + + /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ + temp_word = readw(ctrl->hpc_reg + MISC); + temp_word |= 0x4006; + writew(temp_word, ctrl->hpc_reg + MISC); + + // Changed 05/05/97 to clear all interrupts at start + writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); + + ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + writel(0x0L, ctrl->hpc_reg + INT_MASK); + + if (!cpqhp_ctrl_list) { + cpqhp_ctrl_list = ctrl; + ctrl->next = NULL; + } else { + ctrl->next = cpqhp_ctrl_list; + cpqhp_ctrl_list = ctrl; + } + + // turn off empty slots here unless command line option "ON" set + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + + // find first device number for the ctrl + device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + + while (num_of_slots) { + dbg("num_of_slots: %d\n", num_of_slots); + func = cpqhp_slot_find(ctrl->bus, device, 0); + if (!func) + break; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("hp_slot: %d\n", hp_slot); + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + + if (!power_mode) { + if (!func->is_a_board) { + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + } + } + + device++; + num_of_slots--; + } + + if (!power_mode) { + set_SOGO(ctrl); + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + + rc = init_SERR(ctrl); + if (rc) { + err("init_SERR failed\n"); + up(&ctrl->crit_sect); + goto err_free_irq; + } + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + rc = cpqhp_proc_create_ctrl (ctrl); + if (rc) { + err("cpqhp_proc_create_ctrl failed\n"); + goto err_free_irq; + } + + return 0; + +err_free_irq: + free_irq(ctrl->interrupt, ctrl); +err_iounmap: + iounmap(ctrl->hpc_reg); +err_free_mem_region: + release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +err_free_ctrl: + kfree(ctrl); + return rc; +} + + +static int one_time_init(void) +{ + int loop; + int retval = 0; + static int initialized = 0; + + if (initialized) + return 0; + + power_mode = 0; + + retval = pci_print_IRQ_route(); + if (retval) + goto error; + + dbg("Initialize + Start the notification mechanism \n"); + + retval = cpqhp_event_start_thread(); + if (retval) + goto error; + + dbg("Initialize slot lists\n"); + for (loop = 0; loop < 256; loop++) { + cpqhp_slot_list[loop] = NULL; + } + + // FIXME: We also need to hook the NMI handler eventually. + // this also needs to be worked with Christoph + // register_NMI_handler(); + + // Map rom address + cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); + if (!cpqhp_rom_start) { + err ("Could not ioremap memory region for ROM\n"); + retval = -EIO;; + goto error; + } + + /* Now, map the int15 entry point if we are on compaq specific hardware */ + compaq_nvram_init(cpqhp_rom_start); + + /* Map smbios table entry point structure */ + smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN); + if (!smbios_table) { + err ("Could not find the SMBIOS pointer in memory\n"); + retval = -EIO;; + goto error; + } + + smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), readw(smbios_table + ST_LENGTH)); + if (!smbios_start) { + err ("Could not ioremap memory region taken from SMBIOS values\n"); + retval = -EIO;; + goto error; + } + + retval = cpqhp_proc_init_ctrl(); + if (retval) + goto error; + + initialized = 1; + + return retval; + +error: + if (cpqhp_rom_start) + iounmap(cpqhp_rom_start); + if (smbios_start) + iounmap(smbios_start); + + return retval; +} + + +static void unload_cpqphpd(void) +{ + struct pci_func *next; + struct pci_func *TempSlot; + int loop; + u32 rc; + struct controller *ctrl; + struct controller *tctrl; + struct pci_resource *res; + struct pci_resource *tres; + + rc = compaq_nvram_store(cpqhp_rom_start); + + ctrl = cpqhp_ctrl_list; + + while (ctrl) { + cpqhp_proc_remove_ctrl (ctrl); + + if (ctrl->hpc_reg) { + u16 misc; + rc = read_slot_enable (ctrl); + + writeb(0, ctrl->hpc_reg + SLOT_SERR); + writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); + + misc = readw(ctrl->hpc_reg + MISC); + misc &= 0xFFFD; + writew(misc, ctrl->hpc_reg + MISC); + } + + ctrl_slot_cleanup(ctrl); + + res = ctrl->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + tctrl = ctrl; + ctrl = ctrl->next; + kfree(tctrl); + } + + for (loop = 0; loop < 256; loop++) { + next = cpqhp_slot_list[loop]; + while (next != NULL) { + res = next->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + TempSlot = next; + next = next->next; + kfree(TempSlot); + } + } + + remove_proc_entry("hpc", 0); + + // Stop the notification mechanism + cpqhp_event_stop_thread(); + + //unmap the rom address + if (cpqhp_rom_start) + iounmap(cpqhp_rom_start); + if (smbios_start) + iounmap(smbios_start); +} + + + +static struct pci_device_id hpcd_pci_tbl[] __devinitdata = { + { + /* handle any PCI Hotplug controller */ + class: ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), + class_mask: ~0, + + /* no matter who makes it */ + vendor: PCI_ANY_ID, + device: PCI_ANY_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + + }, { /* end: all zeroes */ } +}; + +MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); + + + +static struct pci_driver cpqhpc_driver = { + name: "pci_hotplug", + id_table: hpcd_pci_tbl, + probe: cpqhpc_probe, + /* remove: cpqhpc_remove_one, */ +}; + + + +static int __init cpqhpc_init(void) +{ + int result; + + cpqhp_debug = debug; + + result = pci_module_init(&cpqhpc_driver); + dbg("pci_module_init = %d\n", result); + if (result) + return result; + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + return 0; +} + + +static void __exit cpqhpc_cleanup(void) +{ + dbg("cleaning up proc entries\n"); + cpqhp_proc_destroy_ctrl(); + + dbg("unload_cpqphpd()\n"); + unload_cpqphpd(); + + dbg("pci_unregister_driver\n"); + pci_unregister_driver(&cpqhpc_driver); +} + + +module_init(cpqhpc_init); +module_exit(cpqhpc_cleanup); + + diff --git a/drivers/hotplug/cpqphp_ctrl.c b/drivers/hotplug/cpqphp_ctrl.c new file mode 100644 index 000000000000..5fc061324884 --- /dev/null +++ b/drivers/hotplug/cpqphp_ctrl.c @@ -0,0 +1,3047 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpqphp.h" + +static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); +static int configure_new_function(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); +static void interrupt_event_handler(struct controller *ctrl); + +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ +static int event_finished; +static unsigned long pushbutton_pending; /* = 0 */ + +/* things needed for the long_delay function */ +static struct semaphore delay_sem; +static wait_queue_head_t delay_wait; + +/* delay is in jiffies to wait for */ +static void long_delay (int delay) +{ + DECLARE_WAITQUEUE(wait, current); + + /* only allow 1 customer into the delay queue at once + * yes this makes some people wait even longer, but who really cares? + * this is for _huge_ delays to make the hardware happy as the + * signals bounce around + */ + down (&delay_sem); + + init_waitqueue_head (&delay_wait); + + add_wait_queue(&delay_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(delay); + remove_wait_queue(&delay_wait, &wait); + set_current_state(TASK_RUNNING); + + up (&delay_sem); +} + + +//FIXME: The following line needs to be somewhere else... +#define WRONG_BUS_FREQUENCY 0x07 +static u8 handle_switch_change(u8 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + u16 temp_word; + struct pci_func *func; + struct event_info *taskInfo; + + if (!change) + return 0; + + // Switch Change + dbg("cpqsbd: Switch interrupt received.\n"); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x1L << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + //this is the structure that tells the worker thread + //what to do + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + //********************************* + // Switch opened + //********************************* + + func->switch_save = 0; + + taskInfo->event_type = INT_SWITCH_OPEN; + } else { + //********************************* + // Switch closed + //********************************* + + func->switch_save = 0x10; + + taskInfo->event_type = INT_SWITCH_CLOSE; + } + } + } + + return rc; +} + + +/* + * find_slot + */ +static inline struct slot *find_slot (struct controller * ctrl, u8 device) +{ + struct slot *slot; + + if (!ctrl) + return NULL; + + slot = ctrl->slot; + + while (slot && (slot->device != device)) { + slot = slot->next; + } + + return slot; +} + + +static u8 handle_presence_change(u16 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + u8 temp_byte; + u16 temp_word; + struct pci_func *func; + struct event_info *taskInfo; + struct slot *p_slot; + + if (!change) + return 0; + + //********************************* + // Presence Change + //********************************* + dbg("cpqsbd: Presence/Notify input change.\n"); + dbg(" Changed bits are 0x%4.4x\n", change ); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x0101 << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + p_slot = find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4)); + + // If the switch closed, must be a button + // If not in button mode, nevermind + if (func->switch_save && (ctrl->push_button == 1)) { + temp_word = ctrl->ctrl_int_comp >> 16; + temp_byte = (temp_word >> hp_slot) & 0x01; + temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (temp_byte != func->presence_save) { + //********************************* + // button Pressed (doesn't do anything) + //********************************* + dbg("hp_slot %d button pressed\n", hp_slot); + taskInfo->event_type = INT_BUTTON_PRESS; + } else { + //********************************* + // button Released - TAKE ACTION!!!! + //********************************* + dbg("hp_slot %d button released\n", hp_slot); + taskInfo->event_type = INT_BUTTON_RELEASE; + + // Cancel if we are still blinking + if ((p_slot->state == BLINKINGON_STATE) + || (p_slot->state == BLINKINGOFF_STATE)) { + taskInfo->event_type = INT_BUTTON_CANCEL; + dbg("hp_slot %d button cancel\n", hp_slot); + } else if ((p_slot->state == POWERON_STATE) + || (p_slot->state == POWEROFF_STATE)) { + //info(msg_button_ignore, p_slot->number); + taskInfo->event_type = INT_BUTTON_IGNORE; + dbg("hp_slot %d button ignore\n", hp_slot); + } + } + } else { + // Switch is open, assume a presence change + // Save the presence state + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if ((!(ctrl->ctrl_int_comp & (0x010000 << hp_slot))) || + (!(ctrl->ctrl_int_comp & (0x01000000 << hp_slot)))) { + //********************************* + // Present + //********************************* + taskInfo->event_type = INT_PRESENCE_ON; + } else { + //********************************* + // Not Present + //********************************* + taskInfo->event_type = INT_PRESENCE_OFF; + } + } + } + } + + return rc; +} + + +static u8 handle_power_fault(u8 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + struct pci_func *func; + struct event_info *taskInfo; + + if (!change) + return 0; + + //********************************* + // power fault + //********************************* + + info("power fault interrupt\n"); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x01 << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { + //********************************* + // power fault Cleared + //********************************* + func->status = 0x00; + + taskInfo->event_type = INT_POWER_FAULT_CLEAR; + } else { + //********************************* + // power fault + //********************************* + taskInfo->event_type = INT_POWER_FAULT; + + if (ctrl->rev < 4) { + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + set_SOGO (ctrl); + + // this is a fatal condition, we want to crash the + // machine to protect from data corruption + // simulated_NMI shouldn't ever return + //FIXME + //simulated_NMI(hp_slot, ctrl); + + //The following code causes a software crash just in + //case simulated_NMI did return + //FIXME + //panic(msg_power_fault); + } else { + // set power fault status for this board + func->status = 0xFF; + info("power fault bit %x set\n", hp_slot); + } + } + } + } + + return rc; +} + + +/* + * sort_by_size + * + * Sorts nodes on the list by their length. + * Smallest first. + * + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * sort_by_max_size + * + * Sorts nodes on the list by their length. + * Largest first. + * + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * do_pre_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + struct pci_resource *split_node; + u32 rc; + u32 temp_dword; + dbg("do_pre_bridge_resource_split\n"); + + if (!(*head) || !(*orig_head)) + return(NULL); + + rc = cpqhp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + if ((*head)->base != (*orig_head)->base) + return(NULL); + + if ((*head)->length == (*orig_head)->length) + return(NULL); + + + // If we got here, there the bridge requires some of the resource, but + // we may be able to split some off of the front + + node = *head; + + if (node->length & (alignment -1)) { + // this one isn't an aligned length, so we'll make a new entry + // and split it up. + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + temp_dword = (node->length | (alignment-1)) + 1 - alignment; + + split_node->base = node->base; + split_node->length = temp_dword; + + node->length -= temp_dword; + node->base += split_node->length; + + // Put it in the list + *head = split_node; + split_node->next = node; + } + + if (node->length < alignment) { + return(NULL); + } + + // Now unlink it + if (*head == node) { + *head = node->next; + node->next = NULL; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + node->next = NULL; + } + + return(node); +} + + +/* + * do_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + u32 rc; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + rc = cpqhp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + node = *head; + + while (node->next) { + prevnode = node; + node = node->next; + kfree(prevnode); + } + + if (node->length < alignment) { + kfree(node); + return(NULL); + } + + if (node->base & (alignment - 1)) { + // Short circuit if adjusted size is too small + temp_dword = (node->base | (alignment-1)) + 1; + if ((node->length - (temp_dword - node->base)) < alignment) { + kfree(node); + return(NULL); + } + + node->length -= (temp_dword - node->base); + node->base = temp_dword; + } + + if (node->length & (alignment - 1)) { + // There's stuff in use after this node + kfree(node); + return(NULL); + } + + return(node); +} + + +/* + * get_io_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( cpqhp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + // For IO make sure it's not in the ISA aliasing space + if (node->base & 0x300L) + continue; + + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + + return(node); +} + + +/* + * get_max_resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if (cpqhp_resource_sort_and_combine(head)) + return(NULL); + + if (sort_by_max_size(head)) + return(NULL); + + for (max = *head;max; max = max->next) { + + // If not big enough we could probably just bail, + // instead we'll continue to the next. + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (max->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((max->length - (temp_dword - max->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = max->base; + split_node->length = temp_dword - max->base; + max->base = temp_dword; + max->length -= split_node->length; + + // Put it next in the list + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + // this one isn't end aligned properly at the top + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + temp_dword = ((max->base + max->length) & ~(size - 1)); + split_node->base = temp_dword; + split_node->length = max->length + max->base + - split_node->base; + max->length -= split_node->length; + + // Put it in the list + split_node->next = max->next; + max->next = split_node; + } + + // Make sure it didn't shrink too much when we aligned it + if (max->length < size) + continue; + + // Now take it out of the list + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return(max); + } + + // If we get here, we couldn't find one + return(NULL); +} + + +/* + * get_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( cpqhp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg(__FUNCTION__": req_size =%x node=%p, base=%x, length=%x\n", + size, node, node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg(__FUNCTION__": not aligned\n"); + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + dbg(__FUNCTION__": too big\n"); + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + dbg(__FUNCTION__": got one!!!\n"); + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + return(node); +} + + +/* + * cpqhp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int cpqhp_resource_sort_and_combine(struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + dbg(__FUNCTION__": head = %p, *head = %p\n", head, *head); + + if (!(*head)) + return(1); + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return(0); /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(*head)->base); + dbg("*head->next->base = 0x%x\n",(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } // End of out_of_order loop + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + // Combine + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return(0); +} + + +void cpqhp_ctrl_intr(int IRQ, struct controller * ctrl, struct pt_regs *regs) +{ + u8 schedule_flag = 0; + u16 misc; + u32 Diff; + u32 temp_dword; + + + misc = readw(ctrl->hpc_reg + MISC); + //********************************* + // Check to see if it was our interrupt + //********************************* + if (!(misc & 0x000C)) { + return; + } + + if (misc & 0x0004) { + //********************************* + // Serial Output interrupt Pending + //********************************* + + // Clear the interrupt + misc |= 0x0004; + writew(misc, ctrl->hpc_reg + MISC); + + // Read to clear posted writes + misc = readw(ctrl->hpc_reg + MISC); + + dbg (__FUNCTION__" - waking up\n"); + wake_up_interruptible(&ctrl->queue); + } + + if (misc & 0x0008) { + // General-interrupt-input interrupt Pending + Diff = readl(ctrl->hpc_reg + INT_INPUT_CLEAR) ^ ctrl->ctrl_int_comp; + + ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + // Clear the interrupt + writel(Diff, ctrl->hpc_reg + INT_INPUT_CLEAR); + + // Read it back to clear any posted writes + temp_dword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + if (!Diff) { + // Clear all interrupts + writel(0xFFFFFFFF, ctrl->hpc_reg + INT_INPUT_CLEAR); + } + + schedule_flag += handle_switch_change((u8)(Diff & 0xFFL), ctrl); + schedule_flag += handle_presence_change((u16)((Diff & 0xFFFF0000L) >> 16), ctrl); + schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl); + } + + if (schedule_flag) { + up(&event_semaphore); + dbg("Signal event_semaphore\n"); + mark_bh(IMMEDIATE_BH); + } + +} + + +/** + * cpqhp_slot_create - Creates a node and adds it to the proper bus. + * @busnumber - bus where new node is to be located + * + * Returns pointer to the new node or NULL if unsuccessful + */ +struct pci_func *cpqhp_slot_create(u8 busnumber) +{ + struct pci_func *new_slot; + struct pci_func *next; + + new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL); + + if (new_slot == NULL) { + // I'm not dead yet! + // You will be. + return(new_slot); + } + + memset(new_slot, 0, sizeof(struct pci_func)); + + new_slot->next = NULL; + new_slot->configured = 1; + + if (cpqhp_slot_list[busnumber] == NULL) { + cpqhp_slot_list[busnumber] = new_slot; + } else { + next = cpqhp_slot_list[busnumber]; + while (next->next != NULL) + next = next->next; + next->next = new_slot; + } + return(new_slot); +} + + +/* + * slot_remove - Removes a node from the linked list of slots. + * @old_slot: slot to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int slot_remove(struct pci_func * old_slot) +{ + struct pci_func *next; + + if (old_slot == NULL) + return(1); + + next = cpqhp_slot_list[old_slot->bus]; + + if (next == NULL) { + return(1); + } + + if (next == old_slot) { + cpqhp_slot_list[old_slot->bus] = old_slot->next; + cpqhp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } + + while ((next->next != old_slot) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == old_slot) { + next->next = old_slot->next; + cpqhp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } else + return(2); +} + + +/** + * bridge_slot_remove - Removes a node from the linked list of slots. + * @bridge: bridge to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int bridge_slot_remove(struct pci_func *bridge) +{ + u8 subordinateBus, secondaryBus; + u8 tempBus; + struct pci_func *next; + + if (bridge == NULL) + return(1); + + secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; + subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; + + for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { + next = cpqhp_slot_list[tempBus]; + + while (!slot_remove(next)) { + next = cpqhp_slot_list[tempBus]; + } + } + + next = cpqhp_slot_list[bridge->bus]; + + if (next == NULL) { + return(1); + } + + if (next == bridge) { + cpqhp_slot_list[bridge->bus] = bridge->next; + kfree(bridge); + return(0); + } + + while ((next->next != bridge) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == bridge) { + next->next = bridge->next; + kfree(bridge); + return(0); + } else + return(2); +} + + +/** + * cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed + * @bus: bus to find + * @device: device to find + * @index: is 0 for first function found, 1 for the second... + * + * Returns pointer to the node if successful, %NULL otherwise. + */ +struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index) +{ + int found = -1; + struct pci_func *func; + + func = cpqhp_slot_list[bus]; + + if ((func == NULL) || ((func->device == device) && (index == 0))) + return(func); + + if (func->device == device) + found++; + + while (func->next != NULL) { + func = func->next; + + if (func->device == device) + found++; + + if (found == index) + return(func); + } + + return(NULL); +} + + +// DJZ: I don't think is_bridge will work as is. +//FIXME +static int is_bridge(struct pci_func * func) +{ + // Check the header type + if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) + return 1; + else + return 0; +} + + +/* the following routines constitute the bulk of the + hotplug controller logic + */ + + +/** + * board_replaced - Called after a board has been replaced in the system. + * + * This is only used if we don't have resources for hot add + * Turns power on for the board + * Checks to see if board is the same + * If board is same, reconfigures it + * If board isn't same, turns it back off. + * + */ +static u32 board_replaced(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + u8 temp_byte; + u32 index; + u32 rc = 0; + u32 src = 8; + + hp_slot = func->device - ctrl->slot_device_offset; + + if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { + //********************************* + // The switch is open. + //********************************* + rc = INTERLOCK_OPEN; + } else if (is_slot_enabled (ctrl, hp_slot)) { + //********************************* + // The board is already on + //********************************* + rc = CARD_FUNCTIONING; + } else { + if (ctrl->speed == 1) { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) { + rc = WRONG_BUS_FREQUENCY; + } + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + } + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + slot_enable (ctrl, hp_slot); + green_LED_blink (ctrl, hp_slot); + + amber_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + // Wait for ~1 second because of hot plug spec + long_delay(1*HZ); + + // Check for a power fault + if (func->status == 0xFF) { + // power fault occurred, but it was benign + rc = POWER_FAILURE; + func->status = 0; + } else + rc = cpqhp_valid_replace(ctrl, func); + + if (!rc) { + // It must be the same board + + rc = cpqhp_configure_board(ctrl, func); + + if (rc || src) { + // If configuration fails, turn it off + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + else + return(1); + } + + func->status = 0; + func->switch_save = 0x10; + + index = 1; + while (((func = cpqhp_slot_find(func->bus, func->device, index)) != NULL) && !rc) { + rc |= cpqhp_configure_board(ctrl, func); + index++; + } + + if (rc) { + // If configuration fails, turn it off + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(rc); + } + // Done configuring so turn LED on full time + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + rc = 0; + } else { + // Something is wrong + + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } + + } + return(rc); + +} + + +/** + * board_added - Called after a board has been added to the system. + * + * Turns power on for the board + * Configures board + * + */ +static u32 board_added(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + u8 temp_byte; + int index; + u32 temp_register = 0xFFFFFFFF; + u32 rc = 0; + struct pci_func *new_slot = NULL; + struct slot *p_slot; + struct resource_lists res_lists; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg(__FUNCTION__": func->device, slot_offset, hp_slot = %d, %d ,%d\n", + func->device, ctrl->slot_device_offset, hp_slot); + + if (ctrl->speed == 1) { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) { + rc = WRONG_BUS_FREQUENCY; + } + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + } + p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + // turn on board and blink green LED + + // Wait for exclusive access to hardware + dbg(__FUNCTION__": before down\n"); + down(&ctrl->crit_sect); + dbg(__FUNCTION__": after down\n"); + + dbg(__FUNCTION__": before slot_enable\n"); + slot_enable (ctrl, hp_slot); + + dbg(__FUNCTION__": before green_LED_blink\n"); + green_LED_blink (ctrl, hp_slot); + + dbg(__FUNCTION__": before amber_LED_blink\n"); + amber_LED_off (ctrl, hp_slot); + + dbg(__FUNCTION__": before set_SOGO\n"); + set_SOGO(ctrl); + + // Wait for SOBS to be unset + dbg(__FUNCTION__": before wait_for_ctrl_irq\n"); + wait_for_ctrl_irq (ctrl); + dbg(__FUNCTION__": after wait_for_ctrl_irq\n"); + + // Done with exclusive hardware access + dbg(__FUNCTION__": before up\n"); + up(&ctrl->crit_sect); + dbg(__FUNCTION__": after up\n"); + + // Wait for ~1 second because of hot plug spec + dbg(__FUNCTION__": before long_delay\n"); + long_delay(1*HZ); + dbg(__FUNCTION__": after long_delay\n"); + + dbg(__FUNCTION__": func status = %x\n", func->status); + // Check for a power fault + if (func->status == 0xFF) { + // power fault occurred, but it was benign + temp_register = 0xFFFFFFFF; + dbg(__FUNCTION__": temp register set to %x by power fault\n", temp_register); + rc = POWER_FAILURE; + func->status = 0; + } else { + // Get vendor/device ID u32 + rc = pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_VENDOR_ID, &temp_register); + dbg(__FUNCTION__": pci_read_config_dword returns %d\n", rc); + dbg(__FUNCTION__": temp_register is %x\n", temp_register); + + if (rc != 0) { + // Something's wrong here + temp_register = 0xFFFFFFFF; + dbg(__FUNCTION__": temp register set to %x by error\n", temp_register); + } + // Preset return code. It will be changed later if things go okay. + rc = NO_ADAPTER_PRESENT; + } + + // All F's is an empty slot or an invalid board + if (temp_register != 0xFFFFFFFF) { // Check for a board in the slot + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + res_lists.irqs = NULL; + + rc = configure_new_device(ctrl, func, 0, &res_lists); + + dbg(__FUNCTION__": back from configure_new_device\n"); + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + return(rc); + } else { + cpqhp_save_slot_config(ctrl, func); + } + + + func->status = 0; + func->switch_save = 0x10; + func->is_a_board = 0x01; + + //next, we will instantiate the linux pci_dev structures (with appropriate driver notification, if already present) + dbg(__FUNCTION__": configure linux pci_dev structure\n"); + index = 0; + do { + new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); + if (new_slot && !new_slot->pci_dev) { + cpqhp_configure_device(ctrl, new_slot); + } + } while (new_slot); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } else { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(rc); + } + return 0; +} + + +/** + * remove_board - Turns off slot and LED's + * + */ +static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl) +{ + int index; + u8 skip = 0; + u8 device; + u8 hp_slot; + u8 temp_byte; + u32 rc; + struct resource_lists res_lists; + struct pci_func *temp_func; + + if (func == NULL) + return(1); + + if (cpqhp_unconfigure_device(func)) + return(1); + + device = func->device; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("In "__FUNCTION__", hp_slot = %d\n", hp_slot); + + // When we get here, it is safe to change base Address Registers. + // We will attempt to save the base Address Register Lengths + if (replace_flag || !ctrl->add_support) + rc = cpqhp_save_base_addr_length(ctrl, func); + else if (!func->bus_head && !func->mem_head && + !func->p_mem_head && !func->io_head) { + // Here we check to see if we've saved any of the board's + // resources already. If so, we'll skip the attempt to + // determine what's being used. + index = 0; + temp_func = cpqhp_slot_find(func->bus, func->device, index++); + while (temp_func) { + if (temp_func->bus_head || temp_func->mem_head + || temp_func->p_mem_head || temp_func->io_head) { + skip = 1; + break; + } + temp_func = cpqhp_slot_find(temp_func->bus, temp_func->device, index++); + } + + if (!skip) + rc = cpqhp_save_used_resources(ctrl, func); + } + // Change status to shutdown + if (func->is_a_board) + func->status = 0x01; + func->configured = 0; + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // turn off SERR for slot + temp_byte = readb(ctrl->hpc_reg + SLOT_SERR); + temp_byte &= ~(0x01 << hp_slot); + writeb(temp_byte, ctrl->hpc_reg + SLOT_SERR); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (!replace_flag && ctrl->add_support) { + while (func) { + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + + cpqhp_return_board_resources(func, &res_lists); + + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (is_bridge(func)) { + bridge_slot_remove(func); + } else + slot_remove(func); + + func = cpqhp_slot_find(ctrl->bus, device, 0); + } + + // Setup slot structure with entry for empty slot + func = cpqhp_slot_create(ctrl->bus); + + if (func == NULL) { + // Out of memory + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->switch_save = 0x10; + func->is_a_board = 0; + func->p_task_event = NULL; + } + + return 0; +} + + +static void pushbutton_helper_thread (unsigned long data) +{ + pushbutton_pending = data; + up(&event_semaphore); +} + + +// this is the main worker thread +static int event_thread(void* data) +{ + struct controller *ctrl; + lock_kernel(); + daemonize(); + + // New name + strcpy(current->comm, "phpd_event"); + + unlock_kernel(); + + while (1) { + dbg("!!!!event_thread sleeping\n"); + down_interruptible (&event_semaphore); + dbg("event_thread woken finished = %d\n", event_finished); + if (event_finished) break; + /* Do stuff here */ + if (pushbutton_pending) + cpqhp_pushbutton_thread(pushbutton_pending); + else + for (ctrl = cpqhp_ctrl_list; ctrl; ctrl=ctrl->next) + interrupt_event_handler(ctrl); + } + dbg("event_thread signals exit\n"); + up(&event_exit); + return 0; +} + + +int cpqhp_event_start_thread (void) +{ + int pid; + + /* initialize our semaphores */ + init_MUTEX(&delay_sem); + init_MUTEX_LOCKED(&event_semaphore); + init_MUTEX_LOCKED(&event_exit); + event_finished=0; + + pid = kernel_thread(event_thread, 0, 0); + if (pid < 0) { + err ("Can't start up our event thread\n"); + return -1; + } + dbg("Our event thread pid = %d\n", pid); + return 0; +} + + +void cpqhp_event_stop_thread (void) +{ + event_finished = 1; + dbg("event_thread finish command given\n"); + up(&event_semaphore); + dbg("wait for event_thread to exit\n"); + down(&event_exit); +} + + +static int update_slot_info (struct controller *ctrl, struct slot *slot) +{ + struct hotplug_slot_info *info; + char buffer[SLOT_NAME_SIZE]; + int result; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); + info->power_status = get_slot_enabled(ctrl, slot); + info->attention_status = cpq_get_attention_status(ctrl, slot); + info->latch_status = cpq_get_latch_status(ctrl, slot); + info->adapter_status = get_presence_status(ctrl, slot); + result = pci_hp_change_slot_info(buffer, info); + kfree (info); + return result; +} + +static void interrupt_event_handler(struct controller *ctrl) +{ + int loop = 0; + int change = 1; + struct pci_func *func; + u8 hp_slot; + struct slot *p_slot; + + while (change) { + change = 0; + + for (loop = 0; loop < 10; loop++) { + //dbg("loop %d\n", loop); + if (ctrl->event_queue[loop].event_type != 0) { + hp_slot = ctrl->event_queue[loop].hp_slot; + + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + dbg("hp_slot %d, func %p, p_slot %p\n", + hp_slot, func, p_slot); + + if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { + dbg("button pressed\n"); + } else if (ctrl->event_queue[loop].event_type == + INT_BUTTON_CANCEL) { + dbg("button cancel\n"); + del_timer(&p_slot->task_event); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + if (p_slot->state == BLINKINGOFF_STATE) { + // slot is on + // turn on green LED + dbg("turn on green LED\n"); + green_LED_on (ctrl, hp_slot); + } else if (p_slot->state == BLINKINGON_STATE) { + // slot is off + // turn off green LED + dbg("turn off green LED\n"); + green_LED_off (ctrl, hp_slot); + } + + info(msg_button_cancel, p_slot->number); + + p_slot->state = STATIC_STATE; + + amber_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } + // ***********button Released (No action on press...) + else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) { + dbg("button release\n"); + + if (is_slot_enabled (ctrl, hp_slot)) { + // slot is on + dbg("slot is on\n"); + p_slot->state = BLINKINGOFF_STATE; + info(msg_button_off, p_slot->number); + } else { + // slot is off + dbg("slot is off\n"); + p_slot->state = BLINKINGON_STATE; + info(msg_button_on, p_slot->number); + } + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + dbg("blink green LED and turn off amber\n"); + amber_LED_off (ctrl, hp_slot); + green_LED_blink (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + init_timer(&p_slot->task_event); + p_slot->hp_slot = hp_slot; + p_slot->ctrl = ctrl; +// p_slot->physical_slot = physical_slot; + p_slot->task_event.expires = jiffies + 5 * HZ; // 5 second delay + p_slot->task_event.function = pushbutton_helper_thread; + p_slot->task_event.data = (u32) p_slot; + + dbg("add_timer p_slot = %p\n", p_slot); + add_timer(&p_slot->task_event); + } + // ***********POWER FAULT + else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { + dbg("power fault\n"); + } else { + /* refresh notification */ + if (p_slot) + update_slot_info(ctrl, p_slot); + } + + ctrl->event_queue[loop].event_type = 0; + + change = 1; + } + } // End of FOR loop + } + + return; +} + + +/** + * cpqhp_pushbutton_thread + * + * Scheduled procedure to handle blocking stuff for the pushbuttons + * Handles all pending events and exits. + * + */ +void cpqhp_pushbutton_thread (unsigned long slot) +{ + u8 hp_slot; + u8 device; + struct pci_func *func; + struct slot *p_slot = (struct slot *) slot; + struct controller *ctrl = (struct controller *) p_slot->ctrl; + + pushbutton_pending = 0; + hp_slot = p_slot->hp_slot; + + device = p_slot->device; + + if (is_slot_enabled (ctrl, hp_slot)) { + p_slot->state = POWEROFF_STATE; + // power Down board + func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); + dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl); + if (!func) { + dbg("Error! func NULL in "__FUNCTION__"\n"); + return ; + } + + if (func != NULL && ctrl != NULL) { + if (cpqhp_process_SS(ctrl, func) != 0) { + amber_LED_on (ctrl, hp_slot); + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + } + + p_slot->state = STATIC_STATE; + } else { + p_slot->state = POWERON_STATE; + // slot is off + + func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); + dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl); + if (!func) { + dbg("Error! func NULL in "__FUNCTION__"\n"); + return ; + } + + if (func != NULL && ctrl != NULL) { + if (cpqhp_process_SI(ctrl, func) != 0) { + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + } + + p_slot->state = STATIC_STATE; + } + + return; +} + + +int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func) +{ + u8 device, hp_slot; + u16 temp_word; + u32 tempdword; + int rc; + struct slot* p_slot; + int physical_slot = 0; + + if (!ctrl) + return(1); + + tempdword = 0; + + device = func->device; + hp_slot = device - ctrl->slot_device_offset; + p_slot = find_slot(ctrl, device); + if (p_slot) { + physical_slot = p_slot->number; + } + + // Check to see if the interlock is closed + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + if (tempdword & (0x01 << hp_slot)) { + return(1); + } + + if (func->is_a_board) { + rc = board_replaced(func, ctrl); + } else { + // add board + slot_remove(func); + + func = cpqhp_slot_create(ctrl->bus); + if (func == NULL) { + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->is_a_board = 1; + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + + rc = board_added(func, ctrl); + if (rc) { + if (is_bridge(func)) { + bridge_slot_remove(func); + } else + slot_remove(func); + + // Setup slot structure with entry for empty slot + func = cpqhp_slot_create(ctrl->bus); + + if (func == NULL) { + // Out of memory + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->is_a_board = 0; + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= + (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + } + } + + if (rc) { + dbg(__FUNCTION__": rc = %d\n", rc); + } + + if (p_slot) + update_slot_info(ctrl, p_slot); + + return rc; +} + + +int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func) +{ + u8 device, class_code, header_type, BCR; + u8 index = 0; + u8 replace_flag; + u32 rc = 0; + struct slot* p_slot; + int physical_slot=0; + + device = func->device; + func = cpqhp_slot_find(ctrl->bus, device, index++); + p_slot = find_slot(ctrl, device); + if (p_slot) { + physical_slot = p_slot->number; + } + + // Make sure there are no video controllers here + while (func && !rc) { + // Check the Class Code + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code); + if (rc) + return rc; + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + /* Display/Video adapter (not supported) */ + rc = REMOVE_NOT_SUPPORTED; + } else { + // See if it's a bridge + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + // If it's a bridge, check the VGA Enable bit + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, &BCR); + if (rc) + return rc; + + // If the VGA Enable bit is set, remove isn't supported + if (BCR & PCI_BRIDGE_CTL_VGA) { + rc = REMOVE_NOT_SUPPORTED; + } + } + } + + func = cpqhp_slot_find(ctrl->bus, device, index++); + } + + func = cpqhp_slot_find(ctrl->bus, device, 0); + if ((func != NULL) && !rc) { + //FIXME: Replace flag should be passed into process_SS + replace_flag = !(ctrl->add_support); + rc = remove_board(func, replace_flag, ctrl); + } else if (!rc) { + rc = 1; + } + + if (p_slot) + update_slot_info(ctrl, p_slot); + + return(rc); +} + + + +/** + * hardware_test - runs hardware tests + * + * For hot plug ctrl folks to play with. + * test_num is the number entered in the GUI + * + */ +int cpqhp_hardware_test(struct controller *ctrl, int test_num) +{ + u32 save_LED; + u32 work_LED; + int loop; + int num_of_slots; + + num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; + + switch (test_num) { + case 1: + // Do stuff here! + + // Do that funky LED thing + save_LED = readl(ctrl->hpc_reg + LED_CONTROL); // so we can restore them later + work_LED = 0x01010101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + work_LED = 0x00000101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((3*HZ)/10); + work_LED = work_LED >> 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((3*HZ)/10); + work_LED = work_LED << 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + } + + writel (save_LED, ctrl->hpc_reg + LED_CONTROL); // put it back the way it was + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + break; + case 2: + // Do other stuff here! + break; + case 3: + // and more... + break; + } + return 0; +} + + +/** + * configure_new_device - Configures the PCI header information of one board. + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Returns 0 if success + * + */ +static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources) +{ + u8 temp_byte, function, max_functions, stop_it; + int rc; + u32 ID; + struct pci_func *new_slot; + int index; + + new_slot = func; + + dbg(__FUNCTION__"\n"); + // Check for Multi-function device + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0E, &temp_byte); + if (rc) { + dbg(__FUNCTION__": rc = %d\n", rc); + return rc; + } + + if (temp_byte & 0x80) // Multi-function device + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + rc = configure_new_function(ctrl, new_slot, behind_bridge, resources); + + if (rc) { + dbg("configure_new_function failed %d\n",rc); + index = 0; + + while (new_slot) { + new_slot = cpqhp_slot_find(new_slot->bus, new_slot->device, index++); + + if (new_slot) + cpqhp_return_board_resources(new_slot, resources); + } + + return(rc); + } + + function++; + + stop_it = 0; + + // The following loop skips to the next present function + // and creates a board structure + + while ((function < max_functions) && (!stop_it)) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, function, 0x00, &ID); + + if (ID == 0xFFFFFFFF) { // There's nothing there. + function++; + } else { // There's something there + // Setup slot structure. + new_slot = cpqhp_slot_create(func->bus); + + if (new_slot == NULL) { + // Out of memory + return(1); + } + + new_slot->bus = func->bus; + new_slot->device = func->device; + new_slot->function = function; + new_slot->is_a_board = 1; + new_slot->status = 0; + + stop_it++; + } + } + + } while (function < max_functions); + dbg("returning from configure_new_device\n"); + + return 0; +} + + +/* + Configuration logic that involves the hotplug data structures and + their bookkeeping + */ + + +/** + * configure_new_function - Configures the PCI header information of one device + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Calls itself recursively for bridged devices. + * Returns 0 if success + * + */ +static int configure_new_function (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources) +{ + int cloop; + u8 IRQ; + u8 temp_byte; + u8 device; + u8 class_code; + u16 command; + u16 temp_word; + u32 temp_dword; + u32 rc; + u32 temp_register; + u32 base; + u32 ID; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_resource *hold_mem_node; + struct pci_resource *hold_p_mem_node; + struct pci_resource *hold_IO_node; + struct pci_resource *hold_bus_node; + struct irq_mapping irqs; + struct pci_func *new_slot; + struct resource_lists temp_resources; + + // Check for Bridge + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &temp_byte); + if (rc) + return rc; + + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // set Primary bus + dbg("set Primary bus = %d\n", func->bus); + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PRIMARY_BUS, func->bus); + if (rc) + return rc; + + // find range of busses to use + dbg("find ranges of buses to use\n"); + bus_node = get_max_resource(&resources->bus_head, 1); + + // If we don't have any busses to allocate, we can't continue + if (!bus_node) + return -ENOMEM; + + // set Secondary bus + temp_byte = bus_node->base; + dbg("set Secondary bus = %d\n", bus_node->base); + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, temp_byte); + if (rc) + return rc; + + // set subordinate bus + temp_byte = bus_node->base + bus_node->length - 1; + dbg("set subordinate bus = %d\n", bus_node->base + bus_node->length - 1); + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, temp_byte); + if (rc) + return rc; + + // set subordinate Latency Timer and base Latency Timer + temp_byte = 0x40; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SEC_LATENCY_TIMER, temp_byte); + if (rc) + return rc; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_LATENCY_TIMER, temp_byte); + if (rc) + return rc; + + // set Cache Line size + temp_byte = 0x08; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_CACHE_LINE_SIZE, temp_byte); + if (rc) + return rc; + + // Setup the IO, memory, and prefetchable windows + + io_node = get_max_resource(&(resources->io_head), 0x1000); + mem_node = get_max_resource(&(resources->mem_head), 0x100000); + p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000); + dbg("Setup the IO, memory, and prefetchable windows\n"); + dbg("io_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); + dbg("mem_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); + dbg("p_mem_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); + + // set up the IRQ info + if (!resources->irqs) { + irqs.barber_pole = 0; + irqs.interrupt[0] = 0; + irqs.interrupt[1] = 0; + irqs.interrupt[2] = 0; + irqs.interrupt[3] = 0; + irqs.valid_INT = 0; + } else { + irqs.barber_pole = resources->irqs->barber_pole; + irqs.interrupt[0] = resources->irqs->interrupt[0]; + irqs.interrupt[1] = resources->irqs->interrupt[1]; + irqs.interrupt[2] = resources->irqs->interrupt[2]; + irqs.interrupt[3] = resources->irqs->interrupt[3]; + irqs.valid_INT = resources->irqs->valid_INT; + } + + // set up resource lists that are now aligned on top and bottom + // for anything behind the bridge. + temp_resources.bus_head = bus_node; + temp_resources.io_head = io_node; + temp_resources.mem_head = mem_node; + temp_resources.p_mem_head = p_mem_node; + temp_resources.irqs = &irqs; + + // Make copies of the nodes we are going to pass down so that + // if there is a problem,we can just use these to free resources + hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { + if (hold_bus_node) + kfree(hold_bus_node); + if (hold_IO_node) + kfree(hold_IO_node); + if (hold_mem_node) + kfree(hold_mem_node); + if (hold_p_mem_node) + kfree(hold_p_mem_node); + + return(1); + } + + memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); + + bus_node->base += 1; + bus_node->length -= 1; + bus_node->next = NULL; + + // If we have IO resources copy them and fill in the bridge's + // IO range registers + if (io_node) { + memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); + io_node->next = NULL; + + // set IO base and Limit registers + temp_byte = io_node->base >> 8; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, temp_byte); + + temp_byte = (io_node->base + io_node->length - 1) >> 8; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_byte); + } else { + kfree(hold_IO_node); + hold_IO_node = NULL; + } + + // If we have memory resources copy them and fill in the bridge's + // memory range registers. Otherwise, fill in the range + // registers with values that disable them. + if (mem_node) { + memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); + mem_node->next = NULL; + + // set Mem base and Limit registers + temp_word = mem_node->base >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word); + + temp_word = (mem_node->base + mem_node->length - 1) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word); + + kfree(hold_mem_node); + hold_mem_node = NULL; + } + + // If we have prefetchable memory resources copy them and + // fill in the bridge's memory range registers. Otherwise, + // fill in the range registers with values that disable them. + if (p_mem_node) { + memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); + p_mem_node->next = NULL; + + // set Pre Mem base and Limit registers + temp_word = p_mem_node->base >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word); + + kfree(hold_p_mem_node); + hold_p_mem_node = NULL; + } + + // Adjust this to compensate for extra adjustment in first loop + irqs.barber_pole--; + + rc = 0; + + // Here we actually find the devices and configure them + for (device = 0; (device <= 0x1F) && !rc; device++) { + irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; + + ID = 0xFFFFFFFF; + pci_read_config_dword_nodev (ctrl->pci_ops, hold_bus_node->base, device, 0, 0x00, &ID); + + if (ID != 0xFFFFFFFF) { // device Present + // Setup slot structure. + new_slot = cpqhp_slot_create(hold_bus_node->base); + + if (new_slot == NULL) { + // Out of memory + rc = -ENOMEM; + continue; + } + + new_slot->bus = hold_bus_node->base; + new_slot->device = device; + new_slot->function = 0; + new_slot->is_a_board = 1; + new_slot->status = 0; + + rc = configure_new_device(ctrl, new_slot, 1, &temp_resources); + dbg("configure_new_device rc=0x%x\n",rc); + } // End of IF (device in slot?) + } // End of FOR loop + + if (rc) { + cpqhp_destroy_resource_list(&temp_resources); + + return_resource(&(resources->bus_head), hold_bus_node); + return_resource(&(resources->io_head), hold_IO_node); + return_resource(&(resources->mem_head), hold_mem_node); + return_resource(&(resources->p_mem_head), hold_p_mem_node); + return(rc); + } + // save the interrupt routing information + if (resources->irqs) { + resources->irqs->interrupt[0] = irqs.interrupt[0]; + resources->irqs->interrupt[1] = irqs.interrupt[1]; + resources->irqs->interrupt[2] = irqs.interrupt[2]; + resources->irqs->interrupt[3] = irqs.interrupt[3]; + resources->irqs->valid_INT = irqs.valid_INT; + } else if (!behind_bridge) { + // We need to hook up the interrupts here + for (cloop = 0; cloop < 4; cloop++) { + if (irqs.valid_INT & (0x01 << cloop)) { + rc = cpqhp_set_irq(func->bus, func->device, + 0x0A + cloop, irqs.interrupt[cloop]); + if (rc) { + cpqhp_destroy_resource_list (&temp_resources); + + return_resource(&(resources-> bus_head), hold_bus_node); + return_resource(&(resources-> io_head), hold_IO_node); + return_resource(&(resources-> mem_head), hold_mem_node); + return_resource(&(resources-> p_mem_head), hold_p_mem_node); + return rc; + } + } + } // end of for loop + } + // Return unused bus resources + // First use the temporary node to store information for the board + if (hold_bus_node && bus_node && temp_resources.bus_head) { + hold_bus_node->length = bus_node->base - hold_bus_node->base; + + hold_bus_node->next = func->bus_head; + func->bus_head = hold_bus_node; + + temp_byte = temp_resources.bus_head->base - 1; + + // set subordinate bus + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, temp_byte); + + if (temp_resources.bus_head->length == 0) { + kfree(temp_resources.bus_head); + temp_resources.bus_head = NULL; + } else { + return_resource(&(resources->bus_head), temp_resources.bus_head); + } + } + + // If we have IO space available and there is some left, + // return the unused portion + if (hold_IO_node && temp_resources.io_head) { + io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), + &hold_IO_node, 0x1000); + + // Check if we were able to split something off + if (io_node) { + hold_IO_node->base = io_node->base + io_node->length; + + temp_byte = (hold_IO_node->base) >> 8; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, temp_byte); + + return_resource(&(resources->io_head), io_node); + } + + io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); + + // Check if we were able to split something off + if (io_node) { + // First use the temporary node to store information for the board + hold_IO_node->length = io_node->base - hold_IO_node->base; + + // If we used any, add it to the board's list + if (hold_IO_node->length) { + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + + temp_byte = (io_node->base - 1) >> 8; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_byte); + + return_resource(&(resources->io_head), io_node); + } else { + // it doesn't need any IO + temp_word = 0x0000; + pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_word); + + return_resource(&(resources->io_head), io_node); + kfree(hold_IO_node); + } + } else { + // it used most of the range + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + } else if (hold_IO_node) { + // it used the whole range + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + // If we have memory space available and there is some left, + // return the unused portion + if (hold_mem_node && temp_resources.mem_head) { + mem_node = do_pre_bridge_resource_split(&(temp_resources. mem_head), + &hold_mem_node, 0x100000); + + // Check if we were able to split something off + if (mem_node) { + hold_mem_node->base = mem_node->base + mem_node->length; + + temp_word = (hold_mem_node->base) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word); + + return_resource(&(resources->mem_head), mem_node); + } + + mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000); + + // Check if we were able to split something off + if (mem_node) { + // First use the temporary node to store information for the board + hold_mem_node->length = mem_node->base - hold_mem_node->base; + + if (hold_mem_node->length) { + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + + // configure end address + temp_word = (mem_node->base - 1) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word); + + // Return unused resources to the pool + return_resource(&(resources->mem_head), mem_node); + } else { + // it doesn't need any Mem + temp_word = 0x0000; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->mem_head), mem_node); + kfree(hold_mem_node); + } + } else { + // it used most of the range + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + } else if (hold_mem_node) { + // it used the whole range + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + // If we have prefetchable memory space available and there is some + // left at the end, return the unused portion + if (hold_p_mem_node && temp_resources.p_mem_head) { + p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), + &hold_p_mem_node, 0x100000); + + // Check if we were able to split something off + if (p_mem_node) { + hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; + + temp_word = (hold_p_mem_node->base) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } + + p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000); + + // Check if we were able to split something off + if (p_mem_node) { + // First use the temporary node to store information for the board + hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; + + // If we used any, add it to the board's list + if (hold_p_mem_node->length) { + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + + temp_word = (p_mem_node->base - 1) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } else { + // it doesn't need any PMem + temp_word = 0x0000; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + kfree(hold_p_mem_node); + } + } else { + // it used the most of the range + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + } else if (hold_p_mem_node) { + // it used the whole range + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + // We should be configuring an IRQ and the bridge's base address + // registers if it needs them. Although we have never seen such + // a device + + // enable card + command = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, command); + + // set Bridge Control Register + command = 0x07; // = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, command); + } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + // Standard device + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + // Display (video) adapter (not supported) + return(DEVICE_TYPE_NOT_SUPPORTED); + } + // Figure out IO and memory needs + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + + dbg("CND: bus=%d, device=%d, func=%d, offset=%d\n", func->bus, func->device, func->function, cloop); + rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + + rc = pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &temp_register); + dbg("CND: base = 0x%x\n", temp_register); + + if (temp_register) { // If this register is implemented + if ((temp_register & 0x03L) == 0x01) { + // Map IO + + // set base = amount of IO space + base = temp_register & 0xFFFFFFFC; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + io_node = get_io_resource(&(resources->io_head), base); + dbg("Got io_node start = %8.8x, length = %8.8x next (%p)\n", + io_node->base, io_node->length, io_node->next); + dbg("func (%p) io_head (%p)\n", func, func->io_head); + + // allocate the resource to the board + if (io_node) { + base = io_node->base; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x08) { + // Map prefetchable memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + p_mem_node = get_resource(&(resources->p_mem_head), base); + + // allocate the resource to the board + if (p_mem_node) { + base = p_mem_node->base; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x00) { + // Map memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + mem_node = get_resource(&(resources->mem_head), base); + + // allocate the resource to the board + if (mem_node) { + base = mem_node->base; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x04) { + // Map memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + mem_node = get_resource(&(resources->mem_head), base); + + // allocate the resource to the board + if (mem_node) { + base = mem_node->base; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x06) { + // Those bits are reserved, we can't handle this + return(1); + } else { + // Requesting space below 1M + return(NOT_ENOUGH_RESOURCES); + } + + rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, base); + + // Check for 64-bit base + if ((temp_register & 0x07L) == 0x04) { + cloop += 4; + + // Upper 32 bits of address always zero on today's systems + // FIXME this is probably not true on Alpha and ia64??? + base = 0; + rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, base); + } + } + } // End of base register loop + + // Figure out which interrupt pin this function uses + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_INTERRUPT_PIN, &temp_byte); + + // If this function needs an interrupt and we are behind a bridge + // and the pin is tied to something that's alread mapped, + // set this one the same + if (temp_byte && resources->irqs && + (resources->irqs->valid_INT & + (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { + // We have to share with something already set up + IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; + } else { + // Program IRQ based on card type + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_STORAGE) { + IRQ = cpqhp_disk_irq; + } else { + IRQ = cpqhp_nic_irq; + } + } + + // IRQ Line + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_INTERRUPT_LINE, IRQ); + + if (!behind_bridge) { + rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); + if (rc) + return(1); + } else { + //TBD - this code may also belong in the other clause of this If statement + resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; + resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; + } + + // Latency Timer + temp_byte = 0x40; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_LATENCY_TIMER, temp_byte); + + // Cache Line size + temp_byte = 0x08; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_CACHE_LINE_SIZE, temp_byte); + + // disable ROM base Address + temp_dword = 0x00L; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_ROM_ADDRESS, temp_dword); + + // enable card + temp_word = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, temp_word); + } // End of Not-A-Bridge else + else { + // It's some strange type of PCI adapter (Cardbus?) + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + func->configured = 1; + + return 0; +} + diff --git a/drivers/hotplug/cpqphp_nvram.c b/drivers/hotplug/cpqphp_nvram.c new file mode 100644 index 000000000000..13a67d7b6487 --- /dev/null +++ b/drivers/hotplug/cpqphp_nvram.c @@ -0,0 +1,652 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpqphp.h" +#include "cpqphp_nvram.h" + + +#define ROM_INT15_PHY_ADDR 0x0FF859 +#define READ_EV 0xD8A4 +#define WRITE_EV 0xD8A5 + +struct register_foo { + union { + unsigned long lword; /* eax */ + unsigned short word; /* ax */ + + struct { + unsigned char low; /* al */ + unsigned char high; /* ah */ + } byte; + } data; + + unsigned char opcode; /* see below */ + unsigned long length; /* if the reg. is a pointer, how much data */ +} __attribute__ ((packed)); + +struct all_reg { + struct register_foo eax_reg; + struct register_foo ebx_reg; + struct register_foo ecx_reg; + struct register_foo edx_reg; + struct register_foo edi_reg; + struct register_foo esi_reg; + struct register_foo eflags_reg; +} __attribute__ ((packed)); + + +struct ev_hrt_header { + u8 Version; + u8 num_of_ctrl; + u8 next; +}; + +struct ev_hrt_ctrl { + u8 bus; + u8 device; + u8 function; + u8 mem_avail; + u8 p_mem_avail; + u8 io_avail; + u8 bus_avail; + u8 next; +}; + + +static u8 evbuffer_init; +static u8 evbuffer_length; +static u8 evbuffer[1024]; + +static void *compaq_int15_entry_point; + +static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ + + +/* This is a series of function that deals with + setting & getting the hotplug resource table in some environment variable. +*/ + +/* + * We really shouldn't be doing this unless there is a _very_ good reason to!!! + * greg k-h + */ + + +static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) +{ + u8 **tByte; + + if ((*used + 1) > *avail) + return(1); + + *((u8*)*p_buffer) = value; + tByte = (u8**)p_buffer; + (*tByte)++; + *used+=1; + return(0); +} + + +static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail) +{ + if ((*used + 4) > *avail) + return(1); + + **p_buffer = value; + (*p_buffer)++; + *used+=4; + return(0); +} + + +/* + * check_for_compaq_ROM + * + * this routine verifies that the ROM OEM string is 'COMPAQ' + * + * returns 0 for non-Compaq ROM, 1 for Compaq ROM + */ +static int check_for_compaq_ROM (void *rom_start) +{ + u8 temp1, temp2, temp3, temp4, temp5, temp6; + int result = 0; + + temp1 = readb(rom_start + 0xffea + 0); + temp2 = readb(rom_start + 0xffea + 1); + temp3 = readb(rom_start + 0xffea + 2); + temp4 = readb(rom_start + 0xffea + 3); + temp5 = readb(rom_start + 0xffea + 4); + temp6 = readb(rom_start + 0xffea + 5); + if ((temp1 == 'C') && + (temp2 == 'O') && + (temp3 == 'M') && + (temp4 == 'P') && + (temp5 == 'A') && + (temp6 == 'Q')) { + result = 1; + } + dbg (__FUNCTION__" - returned %d\n", result); + return result; +} + + +static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) +{ + unsigned long flags; + int op = operation; + int ret_val; + + if (!compaq_int15_entry_point) + return -ENODEV; + + spin_lock_irqsave(&int15_lock, flags); + __asm__ ( + "xorl %%ebx,%%ebx + xorl %%edx,%%edx + pushf + push %%cs + cli + call *%6" + : "=c" (*buf_size), "=a" (ret_val) + : "a" (op), "c" (*buf_size), "S" (ev_name), + "D" (buffer), "m" (compaq_int15_entry_point) + : "%ebx", "%edx"); + spin_unlock_irqrestore(&int15_lock, flags); + + return((ret_val & 0xFF00) >> 8); +} + + +/* + * load_HRT + * + * Read the hot plug Resource Table from NVRAM + */ +static int load_HRT (void *rom_start) +{ + u32 available; + u32 temp_dword; + u8 temp_byte = 0xFF; + u32 rc; + + if (!check_for_compaq_ROM(rom_start)) { + return -ENODEV; + } + + available = 1024; + + // Now load the EV + temp_dword = available; + + rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); + + evbuffer_length = temp_dword; + + // We're maintaining the resource lists so write FF to invalidate old info + temp_dword = 1; + + rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); + + return rc; +} + + +/* + * store_HRT + * + * Save the hot plug Resource Table in NVRAM + */ +static u32 store_HRT (void *rom_start) +{ + u32 *buffer; + u32 *pFill; + u32 usedbytes; + u32 available; + u32 temp_dword; + u32 rc; + u8 loop; + u8 numCtrl = 0; + struct controller *ctrl; + struct pci_resource *resNode; + struct ev_hrt_header *p_EV_header; + struct ev_hrt_ctrl *p_ev_ctrl; + + available = 1024; + + if (!check_for_compaq_ROM(rom_start)) { + return(1); + } + + buffer = (u32*) evbuffer; + + if (!buffer) + return(1); + + pFill = buffer; + usedbytes = 0; + + p_EV_header = (struct ev_hrt_header *) pFill; + + ctrl = cpqhp_ctrl_list; + + // The revision of this structure + rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); + if (rc) + return(rc); + + // The number of controllers + rc = add_byte( &pFill, 1, &usedbytes, &available); + if (rc) + return(rc); + + while (ctrl) { + p_ev_ctrl = (struct ev_hrt_ctrl *) pFill; + + numCtrl++; + + // The bus number + rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); + if (rc) + return(rc); + + // The device Number + rc = add_byte( &pFill, ctrl->device, &usedbytes, &available); + if (rc) + return(rc); + + // The function Number + rc = add_byte( &pFill, ctrl->function, &usedbytes, &available); + if (rc) + return(rc); + + // Skip the number of available entries + rc = add_dword( &pFill, 0, &usedbytes, &available); + if (rc) + return(rc); + + // Figure out memory Available + + resNode = ctrl->mem_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->mem_avail = loop; + + // Figure out prefetchable memory Available + + resNode = ctrl->p_mem_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->p_mem_avail = loop; + + // Figure out IO Available + + resNode = ctrl->io_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->io_avail = loop; + + // Figure out bus Available + + resNode = ctrl->bus_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->bus_avail = loop; + + ctrl = ctrl->next; + } + + p_EV_header->num_of_ctrl = numCtrl; + + // Now store the EV + + temp_dword = usedbytes; + + rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword); + + dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword); + + evbuffer_length = temp_dword; + + if (rc) { + err(msg_unable_to_save); + return(1); + } + + return(0); +} + + +void compaq_nvram_init (void *rom_start) +{ + if (rom_start) { + compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); + } + dbg("int15 entry = %p\n", compaq_int15_entry_point); + + /* initialize our int15 lock */ + spin_lock_init(&int15_lock); +} + + +int compaq_nvram_load (void *rom_start, struct controller *ctrl) +{ + u8 bus, device, function; + u8 nummem, numpmem, numio, numbus; + u32 rc; + u8 *p_byte; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct ev_hrt_ctrl *p_ev_ctrl; + struct ev_hrt_header *p_EV_header; + + if (!evbuffer_init) { + // Read the resource list information in from NVRAM + if (load_HRT(rom_start)) + memset (evbuffer, 0, 1024); + + evbuffer_init = 1; + } + + // If we saved information in NVRAM, use it now + p_EV_header = (struct ev_hrt_header *) evbuffer; + + // The following code is for systems where version 1.0 of this + // driver has been loaded, but doesn't support the hardware. + // In that case, the driver would incorrectly store something + // in NVRAM. + if ((p_EV_header->Version == 2) || + ((p_EV_header->Version == 1) && !ctrl->push_flag)) { + p_byte = &(p_EV_header->next); + + p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next); + + p_byte += 3; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + bus = p_ev_ctrl->bus; + device = p_ev_ctrl->device; + function = p_ev_ctrl->function; + + while ((bus != ctrl->bus) || (device != ctrl->device) + || (function != ctrl->function)) { + nummem = p_ev_ctrl->mem_avail; + numpmem = p_ev_ctrl->p_mem_avail; + numio = p_ev_ctrl->io_avail; + numbus = p_ev_ctrl->bus_avail; + + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + // Skip forward to the next entry + p_byte += (nummem + numpmem + numio + numbus) * 8; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte; + + p_byte += 3; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + bus = p_ev_ctrl->bus; + device = p_ev_ctrl->device; + function = p_ev_ctrl->function; + } + + nummem = p_ev_ctrl->mem_avail; + numpmem = p_ev_ctrl->p_mem_avail; + numio = p_ev_ctrl->io_avail; + numbus = p_ev_ctrl->bus_avail; + + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + while (nummem--) { + mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!mem_node) + break; + + mem_node->base = *(u32*)p_byte; + dbg("mem base = %8.8x\n",mem_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + mem_node->length = *(u32*)p_byte; + dbg("mem length = %8.8x\n",mem_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } + + while (numpmem--) { + p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!p_mem_node) + break; + + p_mem_node->base = *(u32*)p_byte; + dbg("pre-mem base = %8.8x\n",p_mem_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + p_mem_node->length = *(u32*)p_byte; + dbg("pre-mem length = %8.8x\n",p_mem_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } + + while (numio--) { + io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!io_node) + break; + + io_node->base = *(u32*)p_byte; + dbg("io base = %8.8x\n",io_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + io_node->length = *(u32*)p_byte; + dbg("io length = %8.8x\n",io_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } + + while (numbus--) { + bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!bus_node) + break; + + bus_node->base = *(u32*)p_byte; + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + bus_node->length = *(u32*)p_byte; + p_byte += 4; + + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } + + // If all of the following fail, we don't have any resources for + // hot plug add + rc = 1; + rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) { + return(rc); + } + } else { + if ((evbuffer[0] != 0) && (!ctrl->push_flag)) { + return(1); + } + } + + return 0; +} + + +int compaq_nvram_store (void *rom_start) +{ + int rc = 1; + + if (rom_start == NULL) + return -ENODEV; + + if (evbuffer_init) { + rc = store_HRT(rom_start); + if (rc) { + err(msg_unable_to_save); + } + } + return rc; +} + diff --git a/drivers/hotplug/cpqphp_nvram.h b/drivers/hotplug/cpqphp_nvram.h new file mode 100644 index 000000000000..64b793bcf74e --- /dev/null +++ b/drivers/hotplug/cpqphp_nvram.h @@ -0,0 +1,57 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#ifndef _CPQPHP_NVRAM_H +#define _CPQPHP_NVRAM_H + +#ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM + +static inline void compaq_nvram_init (void *rom_start) +{ + return; +} + +static inline int compaq_nvram_load (void *rom_start, struct controller *ctrl) +{ + return 0; +} + +static inline int compaq_nvram_store (void *rom_start) +{ + return 0; +} + +#else + +extern void compaq_nvram_init (void *rom_start); +extern int compaq_nvram_load (void *rom_start, struct controller *ctrl); +extern int compaq_nvram_store (void *rom_start); + +#endif + +#endif + diff --git a/drivers/hotplug/cpqphp_pci.c b/drivers/hotplug/cpqphp_pci.c new file mode 100644 index 000000000000..7fb2401c7727 --- /dev/null +++ b/drivers/hotplug/cpqphp_pci.c @@ -0,0 +1,1726 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cpqphp.h" +#include "cpqphp_nvram.h" +#include "../../arch/i386/kernel/pci-i386.h" /* horrible hack showing how processor dependant we are... */ + + +u8 cpqhp_nic_irq; +u8 cpqhp_disk_irq; + +static u16 unused_IRQ; + + +static int is_pci_dev_in_use(struct pci_dev* dev) +{ + /* + * dev->driver will be set if the device is in use by a new-style + * driver -- otherwise, check the device's regions to see if any + * driver has claimed them + */ + + int i, inuse=0; + + if (dev->driver) return 1; //assume driver feels responsible + + for (i = 0; !dev->driver && !inuse && (i < 6); i++) { + if (!pci_resource_start(dev, i)) + continue; + + if (pci_resource_flags(dev, i) & IORESOURCE_IO) + inuse = check_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) + inuse = check_mem_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + } + + return inuse; + +} + + +static int pci_hp_remove_device(struct pci_dev *dev) +{ + if (is_pci_dev_in_use(dev)) { + err("***Cannot safely power down device -- " + "it appears to be in use***\n"); + return -EBUSY; + } + pci_remove_device(dev); + return 0; +} + + +/* + * detect_HRT_floating_pointer + * + * find the Hot Plug Resource Table in the specified region of memory. + * + */ +static void *detect_HRT_floating_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(struct hrt) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp + SIG0); + temp2 = readb(fp + SIG1); + temp3 = readb(fp + SIG2); + temp4 = readb(fp + SIG3); + if (temp1 == '$' && + temp2 == 'H' && + temp3 == 'R' && + temp4 == 'T') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered Hotplug Resource Table at %p\n", fp); + return fp; +} + +static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_bus* bus = wrapped_bus->bus; + struct pci_dev* dev = wrapped_dev->dev; + struct pci_func *temp_func; + int i=0; + + //We need to fix up the hotplug function representation with the linux representation + do { + temp_func = cpqhp_slot_find(dev->bus->number, dev->devfn >> 3, i++); + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + if (temp_func) { + temp_func->pci_dev = dev; + } else { + //We did not even find a hotplug rep of the function, create it + //This code might be taken out if we can guarantee the creation of functions + //in parallel (hotplug and Linux at the same time). + dbg("@@@@@@@@@@@ cpqhp_slot_create in "__FUNCTION__"\n"); + temp_func = cpqhp_slot_create(bus->number); + if (temp_func == NULL) + return -ENOMEM; + temp_func->pci_dev = dev; + } + + //Create /proc/bus/pci proc entry for this device and bus device is on + //Notify the drivers of the change + if (temp_func->pci_dev) { + pci_proc_attach_device(temp_func->pci_dev); + pci_announce_device_to_drivers(temp_func->pci_dev); + } + + return 0; +} + + +static int unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + + struct pci_func *temp_func; + int i=0; + + //We need to remove the hotplug function representation with the linux representation + do { + temp_func = cpqhp_slot_find(dev->bus->number, dev->devfn >> 3, i++); + if (temp_func) { + dbg("temp_func->function = %d\n", temp_func->function); + } + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + //Now, remove the Linux Representation + if (dev) { + if (pci_hp_remove_device(dev) == 0) { + kfree(dev); //Now, remove + } else { + return -1; // problems while freeing, abort visitation + } + } + + if (temp_func) { + temp_func->pci_dev = NULL; + } else { + dbg("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn); + } + + return 0; +} + + +static int unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) +{ + struct pci_bus* bus = wrapped_bus->bus; + + //The cleanup code for proc entries regarding buses should be in the kernel... + if (bus->procdir) + dbg("detach_pci_bus %s\n", bus->procdir->name); + pci_proc_detach_bus(bus); + // The cleanup code should live in the kernel... + bus->self->subordinate = NULL; + // unlink from parent bus + list_del(&bus->node); + + // Now, remove + if (bus) + kfree(bus); + + return 0; +} + + +static int unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + + dbg("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + //Now, remove the Linux Driver Representation + if (dev->driver) { + if (dev->driver->remove) { + dev->driver->remove(dev); + dbg("driver was properly removed\n"); + } + dev->driver = NULL; + } + + return is_pci_dev_in_use(dev); +} + + +static struct pci_visit configure_functions = { + visit_pci_dev: configure_visit_pci_dev, +}; + + +static struct pci_visit unconfigure_functions_phase1 = { + post_visit_pci_dev: unconfigure_visit_pci_dev_phase1 +}; + +static struct pci_visit unconfigure_functions_phase2 = { + post_visit_pci_bus: unconfigure_visit_pci_bus_phase2, + post_visit_pci_dev: unconfigure_visit_pci_dev_phase2 +}; + + +int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) +{ + unsigned char bus; + struct pci_dev dev0; + struct pci_bus *child; + struct pci_dev* temp; + int rc = 0; + + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + + memset(&dev0, 0, sizeof(struct pci_dev)); + + if (func->pci_dev == NULL) + func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7)); + + //Still NULL ? Well then scan for it ! + if (func->pci_dev == NULL) { + dbg("INFO: pci_dev still null\n"); + dev0.bus = ctrl->pci_dev->bus; + dev0.devfn = (func->device << 3) + (func->function & 0x7); + dev0.sysdata = ctrl->pci_dev->sysdata; + + //this will generate pci_dev structures for all functions, but we will only call this case when lookup fails + func->pci_dev = pci_scan_slot(&dev0); + if (func->pci_dev == NULL) { + dbg("ERROR: pci_dev still null\n"); + return 0; + } + } + + if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); + pci_do_scan_bus(child); + + } + + temp = func->pci_dev; + + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); + } + return rc; +} + + +int cpqhp_unconfigure_device(struct pci_func* func) +{ + int rc = 0; + int j; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + + dbg(__FUNCTION__": bus/dev/func = %x/%x/%x\n",func->bus, func->device, func->function); + + for (j=0; j<8 ; j++) { + struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j); + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus); + if (rc) + break; + + rc = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus); + if (rc) + break; + } + } + return rc; +} + +static int PCI_RefinedAccessConfig(struct pci_ops *ops, u8 bus, u8 device, u8 function, u8 offset, u32 *value) +{ + u32 vendID = 0; + + if (pci_read_config_dword_nodev (ops, bus, device, function, PCI_VENDOR_ID, &vendID) == -1) + return -1; + if (vendID == 0xffffffff) + return -1; + return pci_read_config_dword_nodev (ops, bus, device, function, offset, value); +} + + +/* + * cpqhp_set_irq + * + * @bus_num: bus number of PCI device + * @dev_num: device number of PCI device + * @slot: pointer to u8 where slot number will be returned + */ +int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) +{ + int rc; + u16 temp_word; + struct pci_dev fakedev; + struct pci_bus fakebus; + + fakedev.devfn = dev_num << 3; + fakedev.bus = &fakebus; + fakebus.number = bus_num; + dbg(__FUNCTION__": dev %d, bus %d, pin %d, num %d\n", + dev_num, bus_num, int_pin, irq_num); + rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); + dbg(__FUNCTION__":rc %d\n", rc); + if (rc) + return rc; + + // set the Edge Level Control Register (ELCR) + temp_word = inb(0x4d0); + temp_word |= inb(0x4d1) << 8; + + temp_word |= 0x01 << irq_num; + + // This should only be for x86 as it sets the Edge Level Control Register + outb((u8) (temp_word & 0xFF), 0x4d0); + outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); + + return 0; +} + + +/* + * WTF??? This function isn't in the code, yet a function calls it, but the + * compiler optimizes it away? strange. Here as a placeholder to keep the + * compiler happy. + */ +static int PCI_ScanBusNonBridge (u8 bus, u8 device) +{ + return 0; +} + +static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) +{ + u8 tdevice; + u32 work; + u8 tbus; + + for (tdevice = 0; tdevice < 0x100; tdevice++) { + //Scan for access first + if (PCI_RefinedAccessConfig(ctrl->pci_ops, bus_num, tdevice >> 3, tdevice & 0x7, 0x08, &work) == -1) + continue; + dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); + //Yep we got one. Not a bridge ? + if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { + *dev_num = tdevice; + dbg("found it !\n"); + return 0; + } + } + for (tdevice = 0; tdevice < 0x100; tdevice++) { + //Scan for access first + if (PCI_RefinedAccessConfig(ctrl->pci_ops, bus_num, tdevice >> 3, tdevice & 0x7, 0x08, &work) == -1) + continue; + dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); + //Yep we got one. bridge ? + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_read_config_byte_nodev (ctrl->pci_ops, tbus, tdevice, 0, PCI_SECONDARY_BUS, &tbus); + dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); + if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) + return 0; + } + } + + return -1; +} + + +static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) +{ + struct irq_routing_table *PCIIRQRoutingInfoLength; + long len; + long loop; + u32 work; + + u8 tbus, tdevice, tslot; + + PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); + + len = (PCIIRQRoutingInfoLength->size - + sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return -1; + } + + for (loop = 0; loop < len; ++loop) { + tbus = PCIIRQRoutingInfoLength->slots[loop].bus; + tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; + tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + + if (tslot == slot) { + *bus_num = tbus; + *dev_num = tdevice; + pci_read_config_dword_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_VENDOR_ID, &work); + if (!nobridge || (work == 0xffffffff)) { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + + dbg("bus_num %d dev_num %d func_num %d\n", *bus_num, *dev_num >> 3, *dev_num & 0x7); + pci_read_config_dword_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_CLASS_REVISION, &work); + dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS); + + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_read_config_byte_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_SECONDARY_BUS, &tbus); + dbg("Scan bus for Non Bridge: bus %d\n", tbus); + if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { + *bus_num = tbus; + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + } else { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + + } + } + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return -1; +} + + +int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) +{ + return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) +} + + +/* More PCI configuration routines; this time centered around hotplug controller */ + + +/* + * cpqhp_save_config + * + * Reads configuration for all slots in a PCI bus and saves info. + * + * Note: For non-hot plug busses, the slot # saved is the device # + * + * returns 0 if success + */ +int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) +{ + long rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + struct pci_func *new_slot; + int sub_bus; + int FirstSupported; + int LastSupported; + int max_functions; + int function; + u8 DevError; + int device = 0; + int cloop = 0; + int stop_it; + int index; + + // Decide which slots are supported + + if (is_hot_plug) { + //********************************* + // is_hot_plug is the slot mask + //********************************* + FirstSupported = is_hot_plug >> 4; + LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; + } else { + FirstSupported = 0; + LastSupported = 0x1F; + } + + // Save PCI configuration space for all devices in supported slots + + for (device = FirstSupported; device <= LastSupported; device++) { + ID = 0xFFFFFFFF; + rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, 0, PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { // device in slot + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, 0, 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, 0, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + // If multi-function device, set max_functions to 8 + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + DevError = 0; + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge + // Recurse the subordinate bus + // get the subordinate bus number + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + // Save secondary bus cfg spc + // with this recursive call. + rc = cpqhp_save_config(ctrl, sub_bus, 0); + + if (rc) + return rc; + } + } + + index = 0; + new_slot = cpqhp_slot_find(busnumber, device, index++); + while (new_slot && + (new_slot->function != (u8) function)) + new_slot = cpqhp_slot_find(busnumber, device, index++); + + if (!new_slot) { + // Setup slot structure. + new_slot = cpqhp_slot_create(busnumber); + + if (new_slot == NULL) + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + // In case of unsupported board + new_slot->status = DevError; + new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, function, cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + if (rc) + return rc; + } + + function++; + + stop_it = 0; + + // this loop skips to the next present function + // reading in Class Code and Header type. + + while ((function < max_functions)&&(!stop_it)) { + rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, function, PCI_VENDOR_ID, &ID); + if (ID == 0xFFFFFFFF) { // nothing there. + function++; + } else { // Something there + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + stop_it++; + } + } + + } while (function < max_functions); + } // End of IF (device in slot?) + else if (is_hot_plug) { + // Setup slot structure with entry for empty slot + new_slot = cpqhp_slot_create(busnumber); + + if (new_slot == NULL) { + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + } // End of FOR loop + + return(0); +} + + +/* + * cpqhp_save_slot_config + * + * Saves configuration info for all PCI devices in a given slot + * including subordinate busses. + * + * returns 0 if success + */ +int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) +{ + long rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + int sub_bus; + int max_functions; + int function; + int cloop = 0; + int stop_it; + + ID = 0xFFFFFFFF; + + pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { // device in slot + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, 0x0B, &class_code); + + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, PCI_HEADER_TYPE, &header_type); + + if (header_type & 0x80) // Multi-function device + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // Recurse the subordinate bus + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + // Save the config headers for the secondary bus. + rc = cpqhp_save_config(ctrl, sub_bus, 0); + + if (rc) + return(rc); + + } // End of IF + + new_slot->status = 0; + + for (cloop = 0; cloop < 0x20; cloop++) { + pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + } + + function++; + + stop_it = 0; + + // this loop skips to the next present function + // reading in the Class Code and the Header type. + + while ((function < max_functions) && (!stop_it)) { + pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { // nothing there. + function++; + } else { // Something there + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, 0x0B, &class_code); + + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_HEADER_TYPE, &header_type); + + stop_it++; + } + } + + } while (function < max_functions); + } // End of IF (device in slot?) + else { + return(2); + } + + return(0); +} + + +/* + * cpqhp_save_base_addr_length + * + * Saves the length of all base address registers for the + * specified slot. this is for hot plug REPLACE + * + * returns 0 if success + */ +int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 type; + int sub_bus; + u32 temp_register; + u32 base; + u32 rc; + struct pci_func *next; + int index = 0; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + + // Check for Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + // PCI-PCI Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + next = cpqhp_slot_list[sub_bus]; + + while (next != NULL) { + rc = cpqhp_save_base_addr_length(ctrl, next); + + if (rc) + return(rc); + + next = next->next; + } + + //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x14; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // set base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Save information in slot structure + func->base_length[(cloop - 0x10) >> 2] = + base; + func->base_type[(cloop - 0x10) >> 2] = type; + + } // End of base register loop + + + } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + // base = amount of memory space requested + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Save information in slot structure + func->base_length[(cloop - 0x10) >> 2] = base; + func->base_type[(cloop - 0x10) >> 2] = type; + + } // End of base register loop + + } else { // Some other unknown header type + } + + // find the next device in this slot + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * cpqhp_save_used_resources + * + * Stores used resource information for existing boards. this is + * for boards that were in the system when this driver was loaded. + * this function is for hot plug ADD + * + * returns 0 if success + */ +int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 temp_byte; + u8 b_base; + u8 b_length; + u16 command; + u16 save_command; + u16 w_base; + u16 w_length; + u32 temp_register; + u32 save_base; + u32 base; + int index = 0; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while ((func != NULL) && func->is_a_board) { + // Save the command register + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, &save_command); + + // disable card + command = 0x00; + pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, command); + + // Check for Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // Clear Bridge Control Register + command = 0x00; + pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, command); + + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus); + + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, &temp_byte); + + bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = secondary_bus; + bus_node->length = temp_byte - secondary_bus + 1; + + bus_node->next = func->bus_head; + func->bus_head = bus_node; + + // Save IO base and Limit registers + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, &b_base); + + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, &b_length); + + if ((b_base <= b_length) && (save_command & 0x01)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (b_base & 0xF0) << 8; + io_node->length = (b_length - b_base + 0x10) << 8; + + io_node->next = func->io_head; + func->io_head = io_node; + } + // Save memory base and Limit registers + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, &w_base); + + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (save_command & 0x02)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = w_base << 16; + mem_node->length = (w_length - w_base + 0x10) << 16; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + // Save prefetchable memory base and Limit registers + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, &w_base); + + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (save_command & 0x02)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = w_base << 16; + p_mem_node->length = (w_length - w_base + 0x10) << 16; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x14; cloop += 4) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + temp_register = base; + + if (base) { // If this register is implemented + if (((base & 0x03L) == 0x01) + && (save_command & 0x01)) { + // IO base + // set temp_register = amount of IO space requested + temp_register = base & 0xFFFFFFFE; + temp_register = (~temp_register) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = + save_base & (~0x03L); + io_node->length = temp_register; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + if (((base & 0x0BL) == 0x08) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = save_base & (~0x0FL); + p_mem_node->length = temp_register; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + if (((base & 0x0BL) == 0x00) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = save_base & (~0x0FL); + mem_node->length = temp_register; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return(1); + } + } // End of base register loop + } else if ((header_type & 0x7F) == 0x00) { // Standard header + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + temp_register = base; + + if (base) { // If this register is implemented + if (((base & 0x03L) == 0x01) + && (save_command & 0x01)) { + // IO base + // set temp_register = amount of IO space requested + temp_register = base & 0xFFFFFFFE; + temp_register = (~temp_register) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = save_base & (~0x01L); + io_node->length = temp_register; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + if (((base & 0x0BL) == 0x08) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = save_base & (~0x0FL); + p_mem_node->length = temp_register; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + if (((base & 0x0BL) == 0x00) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = save_base & (~0x0FL); + mem_node->length = temp_register; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return(1); + } + } // End of base register loop + } else { // Some other unknown header type + } + + // find the next device in this slot + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * cpqhp_configure_board + * + * Copies saved configuration information to one slot. + * this is called recursively for bridge devices. + * this is for hot plug REPLACE! + * + * returns 0 if success + */ +int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) +{ + int cloop; + u8 header_type; + u8 secondary_bus; + int sub_bus; + struct pci_func *next; + u32 temp; + u32 rc; + int index = 0; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + // Start at the top of config space so that the control + // registers are programmed last + for (cloop = 0x3C; cloop > 0; cloop -= 4) { + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, func->config_space[cloop >> 2]); + } + + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + + // If this is a bridge device, restore subordinate devices + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + next = cpqhp_slot_list[sub_bus]; + + while (next != NULL) { + rc = cpqhp_configure_board(ctrl, next); + + if (rc) + return rc; + + next = next->next; + } + } else { + + // Check all the base Address Registers to make sure + // they are the same. If not, the board is different. + + for (cloop = 16; cloop < 40; cloop += 4) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &temp); + + if (temp != func->config_space[cloop >> 2]) { + dbg("Config space compare failure!!! offset = %x\n", cloop); + dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function); + dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop]); + return 1; + } + } + } + + func->configured = 1; + + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return 0; +} + + +/* + * cpqhp_valid_replace + * + * this function checks to see if a board is the same as the + * one it is replacing. this check will detect if the device's + * vendor or device id's are the same + * + * returns 0 if the board is the same nonzero otherwise + */ +int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 type; + u32 temp_register = 0; + u32 base; + u32 rc; + struct pci_func *next; + int index = 0; + + if (!func->is_a_board) + return(ADD_NOT_SUPPORTED); + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_VENDOR_ID, &temp_register); + + // No adapter present + if (temp_register == 0xFFFFFFFF) + return(NO_ADAPTER_PRESENT); + + if (temp_register != func->config_space[0]) + return(ADAPTER_NOT_SAME); + + // Check for same revision number and class code + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_CLASS_REVISION, &temp_register); + + // Adapter not the same + if (temp_register != func->config_space[0x08 >> 2]) + return(ADAPTER_NOT_SAME); + + // Check for Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // In order to continue checking, we must program the + // bus registers in the bridge to respond to accesses + // for it's subordinate bus(es) + + temp_register = func->config_space[0x18 >> 2]; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PRIMARY_BUS, temp_register); + + secondary_bus = (temp_register >> 8) & 0xFF; + + next = cpqhp_slot_list[secondary_bus]; + + while (next != NULL) { + rc = cpqhp_valid_replace(ctrl, next); + + if (rc) + return(rc); + + next = next->next; + } + + } + // Check to see if it is a standard config header + else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + // Check subsystem vendor and ID + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); + + if (temp_register != func->config_space[0x2C >> 2]) { + // If it's a SMART-2 and the register isn't filled + // in, ignore the difference because + // they just have an old rev of the firmware + + if (!((func->config_space[0] == 0xAE100E11) + && (temp_register == 0x00L))) + return(ADAPTER_NOT_SAME); + } + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // set base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Check information in slot structure + if (func->base_length[(cloop - 0x10) >> 2] != base) + return(ADAPTER_NOT_SAME); + + if (func->base_type[(cloop - 0x10) >> 2] != type) + return(ADAPTER_NOT_SAME); + + } // End of base register loop + + } // End of (type 0 config space) else + else { + // this is not a type 0 or 1 config space header so + // we don't know how to do it + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + // Get the next function + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + + return(0); +} + + +/* + * cpqhp_find_available_resources + * + * Finds available memory, IO, and IRQ resources for programming + * devices which may be added to the system + * this function is for hot plug ADD! + * + * returns 0 if success + */ +int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start) +{ + u8 temp; + u8 populated_slot; + u8 bridged_slot; + void *one_slot; + struct pci_func *func = NULL; + int i = 10, index; + u32 temp_dword, rc; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + void *rom_resource_table; + + rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); + dbg("rom_resource_table = %p\n", rom_resource_table); + + if (rom_resource_table == NULL) { + return -ENODEV; + } + // Sum all resources and setup resource maps + unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); + dbg("unused_IRQ = %x\n", unused_IRQ); + + temp = 0; + while (unused_IRQ) { + if (unused_IRQ & 1) { + cpqhp_disk_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq); + unused_IRQ = unused_IRQ >> 1; + temp++; + + while (unused_IRQ) { + if (unused_IRQ & 1) { + cpqhp_nic_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq); + unused_IRQ = readl(rom_resource_table + PCIIRQ); + + temp = 0; + + if (!cpqhp_nic_irq) { + cpqhp_nic_irq = ctrl->interrupt; + } + + if (!cpqhp_disk_irq) { + cpqhp_disk_irq = ctrl->interrupt; + } + + dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); + + rc = compaq_nvram_load(rom_start, ctrl); + if (rc) + return rc; + + one_slot = rom_resource_table + sizeof (struct hrt); + + i = readb(rom_resource_table + NUMBER_OF_ENTRIES); + dbg("number_of_entries = %d\n", i); + + if (!readb(one_slot + SECONDARY_BUS)) { + return(1); + } + + dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n"); + + while (i && readb(one_slot + SECONDARY_BUS)) { + u8 dev_func = readb(one_slot + DEV_FUNC); + u8 primary_bus = readb(one_slot + PRIMARY_BUS); + u8 secondary_bus = readb(one_slot + SECONDARY_BUS); + u8 max_bus = readb(one_slot + MAX_BUS); + u16 io_base = readw(one_slot + IO_BASE); + u16 io_length = readw(one_slot + IO_LENGTH); + u16 mem_base = readw(one_slot + MEM_BASE); + u16 mem_length = readw(one_slot + MEM_LENGTH); + u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); + u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); + + dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", + dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, + primary_bus, secondary_bus, max_bus); + + // If this entry isn't for our controller's bus, ignore it + if (primary_bus != ctrl->bus) { + i--; + one_slot += sizeof (struct slot_rt); + continue; + } + // find out if this entry is for an occupied slot + pci_read_config_dword_nodev (ctrl->pci_ops, primary_bus, dev_func >> 3, dev_func & 0x07, PCI_VENDOR_ID, &temp_dword); + + dbg("temp_D_word = %x\n", temp_dword); + + if (temp_dword != 0xFFFFFFFF) { + index = 0; + func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0); + + while (func && (func->function != (dev_func & 0x07))) { + dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index); + func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); + } + + // If we can't find a match, skip this table entry + if (!func) { + i--; + one_slot += sizeof (struct slot_rt); + continue; + } + // this may not work and shouldn't be used + if (secondary_bus != primary_bus) + bridged_slot = 1; + else + bridged_slot = 0; + + populated_slot = 1; + } else { + populated_slot = 0; + bridged_slot = 0; + } + + + // If we've got a valid IO base, use it + + temp_dword = io_base + io_length; + + if ((io_base) && (temp_dword < 0x10000)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = io_base; + io_node->length = io_length; + + dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } else { + io_node->next = func->io_head; + func->io_head = io_node; + } + } + + // If we've got a valid memory base, use it + temp_dword = mem_base + mem_length; + if ((mem_base) && (temp_dword < 0x10000)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = mem_base << 16; + + mem_node->length = mem_length << 16; + + dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } else { + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + } + + // If we've got a valid prefetchable memory base, and + // the base + length isn't greater than 0xFFFF + temp_dword = pre_mem_base + pre_mem_length; + if ((pre_mem_base) && (temp_dword < 0x10000)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = pre_mem_base << 16; + + p_mem_node->length = pre_mem_length << 16; + dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); + dbg("populated slot =%d \n", populated_slot); + + if (!populated_slot) { + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } else { + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + } + + // If we've got a valid bus number, use it + // The second condition is to ignore bus numbers on + // populated slots that don't have PCI-PCI bridges + if (secondary_bus && (secondary_bus != primary_bus)) { + bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = secondary_bus; + bus_node->length = max_bus - secondary_bus + 1; + dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } else { + bus_node->next = func->bus_head; + func->bus_head = bus_node; + } + } + + i--; + one_slot += sizeof (struct slot_rt); + } + + // If all of the following fail, we don't have any resources for + // hot plug add + rc = 1; + rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + return(rc); +} + + +/* + * cpqhp_return_board_resources + * + * this routine returns all resources allocated to a board to + * the available pool. + * + * returns 0 if success + */ +int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) +{ + int rc = 0; + struct pci_resource *node; + struct pci_resource *t_node; + dbg(__FUNCTION__"\n"); + + if (!func) + return(1); + + node = func->io_head; + func->io_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->io_head), node); + node = t_node; + } + + node = func->mem_head; + func->mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->mem_head), node); + node = t_node; + } + + node = func->p_mem_head; + func->p_mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->p_mem_head), node); + node = t_node; + } + + node = func->bus_head; + func->bus_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->bus_head), node); + node = t_node; + } + + rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->io_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head)); + + return(rc); +} + + +/* + * cpqhp_destroy_resource_list + * + * Puts node back in the resource list pointed to by head + */ +void cpqhp_destroy_resource_list (struct resource_lists * resources) +{ + struct pci_resource *res, *tres; + + res = resources->io_head; + resources->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->mem_head; + resources->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->p_mem_head; + resources->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->bus_head; + resources->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + + +/* + * cpqhp_destroy_board_resources + * + * Puts node back in the resource list pointed to by head + */ +void cpqhp_destroy_board_resources (struct pci_func * func) +{ + struct pci_resource *res, *tres; + + res = func->io_head; + func->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->mem_head; + func->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->p_mem_head; + func->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->bus_head; + func->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + diff --git a/drivers/hotplug/cpqphp_proc.c b/drivers/hotplug/cpqphp_proc.c new file mode 100644 index 000000000000..6f260803d456 --- /dev/null +++ b/drivers/hotplug/cpqphp_proc.c @@ -0,0 +1,192 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include "cpqphp.h" + + + +static struct proc_dir_entry *ctrl_proc_root; + +/* A few routines that create proc entries for the hot plug controller */ + +static int read_ctrl (char *buf, char **start, off_t offset, int len, int *eof, void *data) +{ + struct controller *ctrl = (struct controller *)data; + char * out = buf; + int index; + struct pci_resource *res; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + + out += sprintf(out, "hot plug ctrl Info Page\n"); + out += sprintf(out, "bus = %d, device = %d, function = %d\n",ctrl->bus, + ctrl->device, ctrl->function); + out += sprintf(out, "Free resources: memory\n"); + index = 11; + res = ctrl->mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: prefetchable memory\n"); + index = 11; + res = ctrl->p_mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: IO\n"); + index = 11; + res = ctrl->io_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: bus numbers\n"); + index = 11; + res = ctrl->bus_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + + *start = buf; + len = out-buf; + + return len; +} + +static int read_dev (char *buf, char **start, off_t offset, int len, int *eof, void *data) +{ + struct controller *ctrl = (struct controller *)data; + char * out = buf; + int index; + struct pci_resource *res; + struct pci_func *new_slot; + struct slot *slot; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + + out += sprintf(out, "hot plug ctrl Info Page\n"); + out += sprintf(out, "bus = %d, device = %d, function = %d\n",ctrl->bus, + ctrl->device, ctrl->function); + + slot=ctrl->slot; + + while (slot) { + new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); + out += sprintf(out, "assigned resources: memory\n"); + index = 11; + res = new_slot->mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: prefetchable memory\n"); + index = 11; + res = new_slot->p_mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: IO\n"); + index = 11; + res = new_slot->io_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: bus numbers\n"); + index = 11; + res = new_slot->bus_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + slot=slot->next; + } + + *start = buf; + len = out-buf; + + return len; +} + +int cpqhp_proc_create_ctrl (struct controller *ctrl) +{ + strcpy(ctrl->proc_name, "hpca"); + ctrl->proc_name[3] = 'a' + ctrl->bus; + + ctrl->proc_entry = create_proc_entry(ctrl->proc_name, S_IFREG | S_IRUGO, ctrl_proc_root); + ctrl->proc_entry->data = ctrl; + ctrl->proc_entry->read_proc = &read_ctrl; + + strcpy(ctrl->proc_name2, "slot_a"); + ctrl->proc_name2[5] = 'a' + ctrl->bus; + ctrl->proc_entry2 = create_proc_entry(ctrl->proc_name2, S_IFREG | S_IRUGO, ctrl_proc_root); + ctrl->proc_entry2->data = ctrl; + ctrl->proc_entry2->read_proc = &read_dev; + + return 0; +} + +int cpqhp_proc_remove_ctrl (struct controller *ctrl) +{ + if (ctrl->proc_entry) + remove_proc_entry(ctrl->proc_name, ctrl_proc_root); + if (ctrl->proc_entry2) + remove_proc_entry(ctrl->proc_name2, ctrl_proc_root); + + return 0; +} + +int cpqhp_proc_init_ctrl (void) +{ + ctrl_proc_root = proc_mkdir("driver/hpc", NULL); + if (!ctrl_proc_root) + return -ENOMEM; + ctrl_proc_root->owner = THIS_MODULE; + return 0; +} + +int cpqhp_proc_destroy_ctrl (void) +{ + remove_proc_entry("hpc", proc_root_driver); + return 0; +} + diff --git a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h new file mode 100644 index 000000000000..4ca357f6590a --- /dev/null +++ b/drivers/hotplug/pci_hotplug.h @@ -0,0 +1,160 @@ +/* + * PCI HotPlug Core Functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ +#ifndef _PCI_HOTPLUG_H +#define _PCI_HOTPLUG_H + + +struct hotplug_slot; +struct hotplug_slot_core; + +/** + * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use + * @owner: The module owner of this structure + * @enable_slot: Called when the user wants to enable a specific pci slot + * @disable_slot: Called when the user wants to disable a specific pci slot + * @set_attention_status: Called to set the specific slot's attention LED to + * the specified value + * @hardware_test: Called to run a specified hardware test on the specified + * slot. + * @get_power_status: Called to get the current power status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_attention_status: Called to get the current attention status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_latch_status: Called to get the current latch status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_adapter_present: Called to get see if an adapter is present in the slot or not. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * + * The table of function pointers that is passed to the hotplug pci core by a + * hotplug pci driver. These functions are called by the hotplug pci core when + * the user wants to do something to a specific slot (query it for information, + * set an LED, enable / disable power, etc.) + */ +struct hotplug_slot_ops { + struct module *owner; + int (*enable_slot) (struct hotplug_slot *slot); + int (*disable_slot) (struct hotplug_slot *slot); + int (*set_attention_status) (struct hotplug_slot *slot, u8 value); + int (*hardware_test) (struct hotplug_slot *slot, u32 value); + int (*get_power_status) (struct hotplug_slot *slot, u8 *value); + int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); + int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); + int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); +}; + +/** + * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot + * @power: if power is enabled or not (1/0) + * @attention_status: if the attention light is enabled or not (1/0) + * @latch_status: if the latch (if any) is open or closed (1/0) + * @adapter_present: if there is a pci board present in the slot or not (1/0) + * + * Used to notify the hotplug pci core of the status of a specific slot. + */ +struct hotplug_slot_info { + u8 power_status; + u8 attention_status; + u8 latch_status; + u8 adapter_status; +}; + +/** + * struct hotplug_slot - used to register a physical slot with the hotplug pci core + * @name: the name of the slot being registered. This string must + * be unique amoung slots registered on this system. + * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot + * @info: pointer to the &struct hotplug_slot_info for the inital values for + * this slot. + * @private: used by the hotplug pci controller driver to store whatever it + * needs. + */ +struct hotplug_slot { + char *name; + struct hotplug_slot_ops *ops; + struct hotplug_slot_info *info; + void *private; + + /* Variables below this are for use only by the hotplug pci core. */ + struct list_head slot_list; + struct hotplug_slot_core *core_priv; +}; + +extern int pci_hp_register (struct hotplug_slot *slot); +extern int pci_hp_deregister (struct hotplug_slot *slot); +extern int pci_hp_change_slot_info (const char *name, + struct hotplug_slot_info *info); + +struct pci_dev_wrapped { + struct pci_dev *dev; + void *data; +}; + +struct pci_bus_wrapped { + struct pci_bus *bus; + void *data; +}; + +struct pci_visit { + int (* pre_visit_pci_bus) (struct pci_bus_wrapped *, + struct pci_dev_wrapped *); + int (* post_visit_pci_bus) (struct pci_bus_wrapped *, + struct pci_dev_wrapped *); + + int (* pre_visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); + int (* visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); + int (* post_visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); +}; + +extern int pci_visit_dev (struct pci_visit *fn, + struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_parent); + +extern int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u8 *val); +extern int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u16 *val); +extern int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u32 *val); + +extern int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u8 val); +extern int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u16 val); +extern int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u32 val); + + +#endif + diff --git a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c new file mode 100644 index 000000000000..0b851a24c374 --- /dev/null +++ b/drivers/hotplug/pci_hotplug_core.c @@ -0,0 +1,1132 @@ +/* + * PCI HotPlug Controller Core + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pci_hotplug.h" + + +#if !defined(CONFIG_HOTPLUG_PCI_MODULE) + #define MY_NAME "pci_hotplug" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* local variables */ +static int debug; + +#define DRIVER_VERSION "0.3" +#define DRIVER_AUTHOR "Greg Kroah-Hartman " +#define DRIVER_DESC "PCI Hot Plug PCI Core" + + +////////////////////////////////////////////////////////////////// + +/* Random magic number */ +#define PCIHPFS_MAGIC 0x52454541 + +struct hotplug_slot_core { + struct dentry *dir_dentry; + struct dentry *power_dentry; + struct dentry *attention_dentry; + struct dentry *latch_dentry; + struct dentry *adapter_dentry; + struct dentry *test_dentry; +}; + +static struct super_operations pcihpfs_ops; +static struct address_space_operations pcihpfs_aops; +static struct file_operations pcihpfs_dir_operations; +static struct file_operations default_file_operations; +static struct inode_operations pcihpfs_dir_inode_operations; +static struct vfsmount *pcihpfs_mount; /* one of the mounts of our fs for reference counting */ +static int pcihpfs_mount_count; /* times we have mounted our fs */ +static spinlock_t mount_lock; /* protects our mount_count */ +static spinlock_t list_lock; + +LIST_HEAD(pci_hotplug_slot_list); + + +static int pcihpfs_statfs (struct super_block *sb, struct statfs *buf) +{ + buf->f_type = PCIHPFS_MAGIC; + buf->f_bsize = PAGE_CACHE_SIZE; + buf->f_namelen = 255; + return 0; +} + +static struct dentry *pcihpfs_lookup (struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} + +static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, int dev) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_mapping->a_ops = &pcihpfs_aops; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &default_file_operations; + break; + case S_IFDIR: + inode->i_op = &pcihpfs_dir_inode_operations; + inode->i_fop = &pcihpfs_dir_operations; + break; + } + } + return inode; +} + +static int pcihpfs_mknod (struct inode *dir, struct dentry *dentry, int mode, int dev) +{ + struct inode *inode = pcihpfs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; +} + +static int pcihpfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) +{ + return pcihpfs_mknod (dir, dentry, mode | S_IFDIR, 0); +} + +static int pcihpfs_create (struct inode *dir, struct dentry *dentry, int mode) +{ + return pcihpfs_mknod (dir, dentry, mode | S_IFREG, 0); +} + +static int pcihpfs_link (struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + + if(S_ISDIR(inode->i_mode)) + return -EPERM; + + inode->i_nlink++; + atomic_inc(&inode->i_count); + dget(dentry); + d_instantiate(dentry, inode); + return 0; +} + +static inline int pcihpfs_positive (struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} + +static int pcihpfs_empty (struct dentry *dentry) +{ + struct list_head *list; + + spin_lock(&dcache_lock); + + list_for_each(list, &dentry->d_subdirs) { + struct dentry *de = list_entry(list, struct dentry, d_child); + if (pcihpfs_positive(de)) { + spin_unlock(&dcache_lock); + return 0; + } + } + + spin_unlock(&dcache_lock); + return 1; +} + +static int pcihpfs_unlink (struct inode *dir, struct dentry *dentry) +{ + int error = -ENOTEMPTY; + + if (pcihpfs_empty(dentry)) { + struct inode *inode = dentry->d_inode; + + inode->i_nlink--; + dput(dentry); + error = 0; + } + return error; +} + +static int pcihpfs_rename (struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + int error = -ENOTEMPTY; + + if (pcihpfs_empty(new_dentry)) { + struct inode *inode = new_dentry->d_inode; + if (inode) { + inode->i_nlink--; + dput(new_dentry); + } + error = 0; + } + return error; +} + +#define pcihpfs_rmdir pcihpfs_unlink + +/* default file operations */ +static ssize_t default_read_file (struct file *file, char *buf, size_t count, loff_t *ppos) +{ + dbg ("\n"); + return 0; +} + +static ssize_t default_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + dbg ("\n"); + return count; +} + +static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) +{ + loff_t retval = -EINVAL; + + switch(orig) { + case 0: + if (offset > 0) { + file->f_pos = offset; + retval = file->f_pos; + } + break; + case 1: + if ((offset + file->f_pos) > 0) { + file->f_pos += offset; + retval = file->f_pos; + } + break; + default: + break; + } + return retval; +} + +static int default_open (struct inode *inode, struct file *filp) +{ + if (inode->u.generic_ip) + filp->private_data = inode->u.generic_ip; + + return 0; +} + +static int default_sync_file (struct file *file, struct dentry *dentry, int datasync) +{ + return 0; +} + +static struct address_space_operations pcihpfs_aops = { +}; + +static struct file_operations pcihpfs_dir_operations = { + read: generic_read_dir, + readdir: dcache_readdir, + fsync: default_sync_file, +}; + +static struct file_operations default_file_operations = { + read: default_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "power" files */ +static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static ssize_t power_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos); +static struct file_operations power_file_operations = { + read: power_read_file, + write: power_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "attention" files */ +static ssize_t attention_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static ssize_t attention_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos); +static struct file_operations attention_file_operations = { + read: attention_read_file, + write: attention_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "latch" files */ +static ssize_t latch_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static struct file_operations latch_file_operations = { + read: latch_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "presence" files */ +static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static struct file_operations presence_file_operations = { + read: presence_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "test" files */ +static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos); +static struct file_operations test_file_operations = { + read: default_read_file, + write: test_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +static struct inode_operations pcihpfs_dir_inode_operations = { + create: pcihpfs_create, + lookup: pcihpfs_lookup, + link: pcihpfs_link, + unlink: pcihpfs_unlink, + mkdir: pcihpfs_mkdir, + rmdir: pcihpfs_rmdir, + mknod: pcihpfs_mknod, + rename: pcihpfs_rename, +}; + +static struct super_operations pcihpfs_ops = { + statfs: pcihpfs_statfs, + put_inode: force_delete, +}; + +static struct super_block *pcihpfs_read_super (struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + struct dentry *root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = PCIHPFS_MAGIC; + sb->s_op = &pcihpfs_ops; + inode = pcihpfs_get_inode(sb, S_IFDIR | 0755, 0); + + if (!inode) { + dbg("%s: could not get inode!\n",__FUNCTION__); + return NULL; + } + + root = d_alloc_root(inode); + if (!root) { + dbg("%s: could not get root dentry!\n",__FUNCTION__); + iput(inode); + return NULL; + } + sb->s_root = root; + return sb; +} + +static DECLARE_FSTYPE(pcihpfs_fs_type, "pcihpfs", pcihpfs_read_super, FS_SINGLE | FS_LITTER); + +static int get_mount (void) +{ + struct vfsmount *mnt; + + spin_lock (&mount_lock); + if (pcihpfs_mount) { + mntget(pcihpfs_mount); + ++pcihpfs_mount_count; + spin_unlock (&mount_lock); + goto go_ahead; + } + + spin_unlock (&mount_lock); + mnt = kern_mount (&pcihpfs_fs_type); + if (IS_ERR(mnt)) { + err ("could not mount the fs...erroring out!\n"); + return -ENODEV; + } + spin_lock (&mount_lock); + if (!pcihpfs_mount) { + pcihpfs_mount = mnt; + ++pcihpfs_mount_count; + spin_unlock (&mount_lock); + goto go_ahead; + } + mntget(pcihpfs_mount); + ++pcihpfs_mount_count; + spin_unlock (&mount_lock); + mntput(mnt); + +go_ahead: + dbg("pcihpfs_mount_count = %d\n", pcihpfs_mount_count); + return 0; +} + +static void remove_mount (void) +{ + struct vfsmount *mnt; + + spin_lock (&mount_lock); + mnt = pcihpfs_mount; + --pcihpfs_mount_count; + if (!pcihpfs_mount_count) + pcihpfs_mount = NULL; + + spin_unlock (&mount_lock); + mntput(mnt); + dbg("pcihpfs_mount_count = %d\n", pcihpfs_mount_count); +} + + +/** + * pcihpfs_create_by_name - create a file, given a name + * @name: name of file + * @mode: type of file + * @parent: dentry of directory to create it in + * @dentry: resulting dentry of file + * + * There is a bit of overhead in creating a file - basically, we + * have to hash the name of the file, then look it up. This will + * prevent files of the same name. + * We then call the proper vfs_ function to take care of all the + * file creation details. + * This function handles both regular files and directories. + */ +static int pcihpfs_create_by_name (const char *name, mode_t mode, + struct dentry *parent, struct dentry **dentry) +{ + struct dentry *d = NULL; + struct qstr qstr; + int error; + + /* If the parent is not specified, we create it in the root. + * We need the root dentry to do this, which is in the super + * block. A pointer to that is in the struct vfsmount that we + * have around. + */ + if (!parent ) { + if (pcihpfs_mount && pcihpfs_mount->mnt_sb) { + parent = pcihpfs_mount->mnt_sb->s_root; + } + } + + if (!parent) { + dbg("Ah! can not find a parent!\n"); + return -EFAULT; + } + + *dentry = NULL; + qstr.name = name; + qstr.len = strlen(name); + qstr.hash = full_name_hash(name,qstr.len); + + parent = dget(parent); + + down(&parent->d_inode->i_sem); + + d = lookup_hash(&qstr,parent); + + error = PTR_ERR(d); + if (!IS_ERR(d)) { + switch(mode & S_IFMT) { + case 0: + case S_IFREG: + error = vfs_create(parent->d_inode,d,mode); + break; + case S_IFDIR: + error = vfs_mkdir(parent->d_inode,d,mode); + break; + default: + err("cannot create special files\n"); + } + *dentry = d; + } + up(&parent->d_inode->i_sem); + + dput(parent); + return error; +} + +static struct dentry *fs_create_file (const char *name, mode_t mode, + struct dentry *parent, void *data, + struct file_operations *fops) +{ + struct dentry *dentry; + int error; + + dbg("creating file '%s'\n",name); + + error = pcihpfs_create_by_name(name,mode,parent,&dentry); + if (error) { + dentry = NULL; + } else { + if (dentry->d_inode) { + if (data) + dentry->d_inode->u.generic_ip = data; + if (fops) + dentry->d_inode->i_fop = fops; + } + } + + return dentry; +} + +static void fs_remove_file (struct dentry *dentry) +{ + struct dentry *parent = dentry->d_parent; + + if (!parent || !parent->d_inode) + return; + + down(&parent->d_inode->i_sem); + if (pcihpfs_positive(dentry)) { + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) + vfs_rmdir(parent->d_inode,dentry); + else + vfs_unlink(parent->d_inode,dentry); + } + + dput(dentry); + } + up(&parent->d_inode->i_sem); +} + +#define GET_STATUS(name) \ +static int get_##name##_status (struct hotplug_slot *slot, u8 *value) \ +{ \ + struct hotplug_slot_ops *ops = slot->ops; \ + int retval = 0; \ + if (ops->owner) \ + __MOD_INC_USE_COUNT(ops->owner); \ + if (ops->get_##name##_status) \ + retval = ops->get_##name##_status (slot, value); \ + else \ + *value = slot->info->name##_status; \ + if (ops->owner) \ + __MOD_DEC_USE_COUNT(ops->owner); \ + return retval; \ +} + +GET_STATUS(power) +GET_STATUS(attention) +GET_STATUS(latch) +GET_STATUS(adapter) + +static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u8 value; + + dbg(" count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_power_status (slot, &value); + if (retval) + goto exit; + len = sprintf (page, "%d\n", value); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t power_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + const char *buff; + unsigned long lpower; + u8 power; + int retval = 0; + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + buff = kmalloc (count, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + if (copy_from_user ((void *)buff, (void *)ubuff, count)) { + retval = -EFAULT; + goto exit; + } + + lpower = simple_strtoul (buff, NULL, 10); + power = (u8)(lpower & 0xff); + dbg ("power = %d\n", power); + + switch (power) { + case 0: + if (!slot->ops->disable_slot) + break; + if (slot->ops->owner) + __MOD_INC_USE_COUNT(slot->ops->owner); + retval = slot->ops->disable_slot(slot); + if (slot->ops->owner) + __MOD_DEC_USE_COUNT(slot->ops->owner); + break; + + case 1: + if (!slot->ops->enable_slot) + break; + if (slot->ops->owner) + __MOD_INC_USE_COUNT(slot->ops->owner); + retval = slot->ops->enable_slot(slot); + if (slot->ops->owner) + __MOD_DEC_USE_COUNT(slot->ops->owner); + break; + + default: + err ("Illegal value specified for power\n"); + retval = -EFAULT; + } + +exit: + kfree (buff); + + if (retval) + return retval; + return count; +} + +static ssize_t attention_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u8 value; + + dbg("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_attention_status (slot, &value); + if (retval) + goto exit; + len = sprintf (page, "%d\n", value); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t attention_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + const char *buff; + unsigned long lattention; + u8 attention; + int retval = 0; + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + buff = kmalloc (count, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + if (copy_from_user ((void *)buff, (void *)ubuff, count)) { + retval = -EFAULT; + goto exit; + } + + lattention = simple_strtoul (buff, NULL, 10); + attention = (u8)(lattention & 0xff); + dbg (" - attention = %d\n", attention); + + if (slot->ops->set_attention_status) { + if (slot->ops->owner) + __MOD_INC_USE_COUNT(slot->ops->owner); + retval = slot->ops->set_attention_status(slot, attention); + if (slot->ops->owner) + __MOD_DEC_USE_COUNT(slot->ops->owner); + } + +exit: + kfree (buff); + + if (retval) + return retval; + return count; +} + +static ssize_t latch_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u8 value; + + dbg("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_latch_status (slot, &value); + if (retval) + goto exit; + len = sprintf (page, "%d\n", value); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + + +static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u8 value; + + dbg("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_adapter_status (slot, &value); + if (retval) + goto exit; + len = sprintf (page, "%d\n", value); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + const char *buff; + unsigned long ltest; + u32 test; + int retval = 0; + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + buff = kmalloc (count, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + if (copy_from_user ((void *)buff, (void *)ubuff, count)) { + retval = -EFAULT; + goto exit; + } + + ltest = simple_strtoul (buff, NULL, 10); + test = (u32)(ltest & 0xffffffff); + dbg ("test = %d\n", test); + + if (slot->ops->hardware_test) { + if (slot->ops->owner) + __MOD_INC_USE_COUNT(slot->ops->owner); + retval = slot->ops->hardware_test(slot, test); + if (slot->ops->owner) + __MOD_DEC_USE_COUNT(slot->ops->owner); + } + +exit: + kfree (buff); + + if (retval) + return retval; + return count; +} + +static int fs_add_slot (struct hotplug_slot *slot) +{ + struct hotplug_slot_core *core = slot->core_priv; + int result; + + result = get_mount(); + if (result) + return result; + + core->dir_dentry = fs_create_file (slot->name, + S_IFDIR | S_IXUGO | S_IRUGO, + NULL, NULL, NULL); + if (core->dir_dentry != NULL) { + core->power_dentry = fs_create_file ("power", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &power_file_operations); + + core->attention_dentry = fs_create_file ("attention", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &attention_file_operations); + + core->latch_dentry = fs_create_file ("latch", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &latch_file_operations); + + core->adapter_dentry = fs_create_file ("adapter", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &presence_file_operations); + + core->test_dentry = fs_create_file ("test", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &test_file_operations); + } + return 0; +} + +static void fs_remove_slot (struct hotplug_slot *slot) +{ + struct hotplug_slot_core *core = slot->core_priv; + + if (core->dir_dentry) { + if (core->power_dentry) + fs_remove_file (core->power_dentry); + if (core->attention_dentry) + fs_remove_file (core->attention_dentry); + if (core->latch_dentry) + fs_remove_file (core->latch_dentry); + if (core->adapter_dentry) + fs_remove_file (core->adapter_dentry); + if (core->test_dentry) + fs_remove_file (core->test_dentry); + fs_remove_file (core->dir_dentry); + } + + remove_mount(); +} + +static struct hotplug_slot *get_slot_from_name (const char *name) +{ + struct hotplug_slot *slot; + struct list_head *tmp; + + list_for_each (tmp, &pci_hotplug_slot_list) { + slot = list_entry (tmp, struct hotplug_slot, slot_list); + if (strcmp(slot->name, name) == 0) + return slot; + } + return NULL; +} + +/** + * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem + * @slot: pointer to the &struct hotplug_slot to register + * + * Registers a hotplug slot with the pci hotplug subsystem, which will allow + * userspace interaction to the slot. + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_register (struct hotplug_slot *slot) +{ + struct hotplug_slot_core *core; + int result; + + if (slot == NULL) + return -ENODEV; + if ((slot->info == NULL) || (slot->ops == NULL)) + return -EFAULT; + + core = kmalloc (sizeof (struct hotplug_slot_core), GFP_KERNEL); + if (!core) + return -ENOMEM; + + /* make sure we have not already registered this slot */ + spin_lock (&list_lock); + if (get_slot_from_name (slot->name) != NULL) { + spin_unlock (&list_lock); + kfree (core); + return -EFAULT; + } + + slot->core_priv = core; + + list_add (&slot->slot_list, &pci_hotplug_slot_list); + spin_unlock (&list_lock); + + result = fs_add_slot (slot); + dbg ("Added slot %s to the list\n", slot->name); + return result; +} + +/** + * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem + * @slot: pointer to the &struct hotplug_slot to deregister + * + * The @slot must have been registered with the pci hotplug subsystem + * previously with a call to pci_hp_register(). + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_deregister (struct hotplug_slot *slot) +{ + struct hotplug_slot *temp; + + if (slot == NULL) + return -ENODEV; + + /* make sure we have this slot in our list before trying to delete it */ + spin_lock (&list_lock); + temp = get_slot_from_name (slot->name); + if (temp != slot) { + spin_unlock (&list_lock); + return -ENODEV; + } + + list_del (&slot->slot_list); + spin_unlock (&list_lock); + + fs_remove_slot (slot); + kfree(slot->core_priv); + dbg ("Removed slot %s from the list\n", slot->name); + return 0; +} + +/** + * pci_hp_change_slot_info - changes the slot's information structure in the core + * @name: the name of the slot whose info has changed + * @info: pointer to the info copy into the slot's info structure + * + * A slot with @name must have been registered with the pci + * hotplug subsystem previously with a call to pci_hp_register(). + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_change_slot_info (const char *name, struct hotplug_slot_info *info) +{ + struct hotplug_slot *temp; + + if (info == NULL) + return -ENODEV; + + spin_lock (&list_lock); + temp = get_slot_from_name (name); + if (temp == NULL) { + spin_unlock (&list_lock); + return -ENODEV; + } + + memcpy (temp->info, info, sizeof (struct hotplug_slot_info)); + spin_unlock (&list_lock); + return 0; +} + +static int __init pci_hotplug_init (void) +{ + int result; + + spin_lock_init(&mount_lock); + spin_lock_init(&list_lock); + + dbg("registering filesystem.\n"); + result = register_filesystem(&pcihpfs_fs_type); + if (result) { + err("register_filesystem failed with %d\n", result); + goto exit; + } + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + +exit: + return result; +} + +static void __exit pci_hotplug_exit (void) +{ + unregister_filesystem(&pcihpfs_fs_type); +} + +module_init(pci_hotplug_init); +module_exit(pci_hotplug_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +EXPORT_SYMBOL_GPL(pci_hp_register); +EXPORT_SYMBOL_GPL(pci_hp_deregister); +EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); + diff --git a/drivers/hotplug/pci_hotplug_util.c b/drivers/hotplug/pci_hotplug_util.c new file mode 100644 index 000000000000..8eb25ebf35e4 --- /dev/null +++ b/drivers/hotplug/pci_hotplug_util.c @@ -0,0 +1,403 @@ +/* + * PCI HotPlug Utility functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include "pci_hotplug.h" + + +#if !defined(CONFIG_HOTPLUG_PCI_MODULE) + #define MY_NAME "pci_hotplug" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* local variables */ +static int debug; + + +static int build_dev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, struct pci_dev **pci_dev) +{ + struct pci_dev *my_dev; + struct pci_bus *my_bus; + + /* Some validity checks. */ + if ((function > 7) || + (slot > 31) || + (pci_dev == NULL) || + (ops == NULL)) + return -ENODEV; + + my_dev = kmalloc (sizeof (struct pci_dev), GFP_KERNEL); + if (!my_dev) + return -ENOMEM; + my_bus = kmalloc (sizeof (struct pci_bus), GFP_KERNEL); + if (!my_bus) { + kfree (my_dev); + return -ENOMEM; + } + memset(my_dev, 0, sizeof(struct pci_dev)); + memset(my_bus, 0, sizeof(struct pci_bus)); + + my_bus->number = bus; + my_bus->ops = ops; + my_dev->devfn = PCI_DEVFN(slot, function); + my_dev->bus = my_bus; + *pci_dev = my_dev; + return 0; +} + +/** + * pci_read_config_byte_nodev - read a byte from a pci device + * @ops: pointer to a &struct pci_ops that will be used to read from the pci device + * @bus: the bus of the pci device to read from + * @slot: the pci slot number of the pci device to read from + * @function: the function of the pci device to read from + * @where: the location on the pci address space to read from + * @value: pointer to where to place the data read + * + * Like pci_read_config_byte() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 *value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_read_config_byte (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_read_config_byte(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_read_config_word_nodev - read a word from a pci device + * @ops: pointer to a &struct pci_ops that will be used to read from the pci device + * @bus: the bus of the pci device to read from + * @slot: the pci slot number of the pci device to read from + * @function: the function of the pci device to read from + * @where: the location on the pci address space to read from + * @value: pointer to where to place the data read + * + * Like pci_read_config_word() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 *value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_read_config_word (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_read_config_word(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_read_config_dword_nodev - read a dword from a pci device + * @ops: pointer to a &struct pci_ops that will be used to read from the pci + * device + * @bus: the bus of the pci device to read from + * @slot: the pci slot number of the pci device to read from + * @function: the function of the pci device to read from + * @where: the location on the pci address space to read from + * @value: pointer to where to place the data read + * + * Like pci_read_config_dword() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 *value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_read_config_dword (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_read_config_dword(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_write_config_byte_nodev - write a byte to a pci device + * @ops: pointer to a &struct pci_ops that will be used to write to the pci + * device + * @bus: the bus of the pci device to write to + * @slot: the pci slot number of the pci device to write to + * @function: the function of the pci device to write to + * @where: the location on the pci address space to write to + * @value: the value to write to the pci device + * + * Like pci_write_config_byte() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_write_config_byte (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_write_config_byte(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_write_config_word_nodev - write a word to a pci device + * @ops: pointer to a &struct pci_ops that will be used to write to the pci + * device + * @bus: the bus of the pci device to write to + * @slot: the pci slot number of the pci device to write to + * @function: the function of the pci device to write to + * @where: the location on the pci address space to write to + * @value: the value to write to the pci device + * + * Like pci_write_config_word() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_write_config_word (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_write_config_word(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_write_config_dword_nodev - write a dword to a pci device + * @ops: pointer to a &struct pci_ops that will be used to write to the pci + * device + * @bus: the bus of the pci device to write to + * @slot: the pci slot number of the pci device to write to + * @function: the function of the pci device to write to + * @where: the location on the pci address space to write to + * @value: the value to write to the pci device + * + * Like pci_write_config_dword() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_write_config_dword (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_write_config_dword(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/* + * This is code that scans the pci buses. + * Every bus and every function is presented to a custom + * function that can act upon it. + */ + +static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent) +{ + struct list_head *ln; + struct pci_dev *dev; + struct pci_dev_wrapped wrapped_dev; + int result = 0; + + dbg("scanning bus %02x\n", wrapped_bus->bus->number); + + if (fn->pre_visit_pci_bus) { + result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent); + if (result) + return result; + } + + ln = wrapped_bus->bus->devices.next; + while (ln != &wrapped_bus->bus->devices) { + dev = pci_dev_b(ln); + ln = ln->next; + + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + wrapped_dev.dev = dev; + + result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus); + if (result) + return result; + } + + if (fn->post_visit_pci_bus) + result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent); + + return result; +} + + +static int pci_visit_bridge (struct pci_visit * fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent) +{ + struct pci_bus *bus = wrapped_dev->dev->subordinate; + struct pci_bus_wrapped wrapped_bus; + int result; + + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + wrapped_bus.bus = bus; + + dbg("scanning bridge %02x, %02x\n", wrapped_dev->dev->devfn >> 3, + wrapped_dev->dev->devfn & 0x7); + + if (fn->visit_pci_dev) { + result = fn->visit_pci_dev(wrapped_dev, wrapped_parent); + if (result) + return result; + } + + result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev); + return result; +} + + +int pci_visit_dev (struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent) +{ + struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL; + int result = 0; + + if (!dev) + return 0; + + if (fn->pre_visit_pci_dev) { + result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent); + if (result) + return result; + } + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_PCI: + result = pci_visit_bridge(fn, wrapped_dev, + wrapped_parent); + if (result) + return result; + break; + default: + dbg("scanning device %02x, %02x\n", + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + if (fn->visit_pci_dev) { + result = fn->visit_pci_dev (wrapped_dev, + wrapped_parent); + if (result) + return result; + } + } + + if (fn->post_visit_pci_dev) + result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent); + + return result; +} + + +EXPORT_SYMBOL(pci_visit_dev); +EXPORT_SYMBOL(pci_read_config_byte_nodev); +EXPORT_SYMBOL(pci_read_config_word_nodev); +EXPORT_SYMBOL(pci_read_config_dword_nodev); +EXPORT_SYMBOL(pci_write_config_byte_nodev); +EXPORT_SYMBOL(pci_write_config_word_nodev); +EXPORT_SYMBOL(pci_write_config_dword_nodev); + diff --git a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c index 7b56818557ab..ce26d65f0159 100644 --- a/drivers/ide/ide-geometry.c +++ b/drivers/ide/ide-geometry.c @@ -71,8 +71,8 @@ void probe_cmos_for_drives (ide_hwif_t *hwif) drive->sect = drive->bios_sect = sect; drive->ctl = *(BIOS+8); } else { - printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n", - unit, cyl, head, sect); + printk("hd%c: C/H/S=%d/%d/%d from BIOS ignored\n", + unit+'a', cyl, head, sect); } } diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index c3786a86d08d..b44cc2ba6df9 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.41.6.3 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_idi.c,v 1.41.6.4 2001/11/06 20:58:29 kai Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -25,7 +25,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.41.6.3 $"; +char *eicon_idi_revision = "$Revision: 1.41.6.4 $"; eicon_manifbuf *manbuf; @@ -3119,8 +3119,8 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) return(ret); } - timeout = jiffies + 50; - while (timeout > jiffies) { + timeout = jiffies + HZ / 2; + while (time_before(jiffies, timeout)) { if (chan->e.B2Id) break; SLEEP(10); } @@ -3181,8 +3181,8 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) eicon_schedule_tx(card); - timeout = jiffies + 50; - while (timeout > jiffies) { + timeout = jiffies + HZ / 2; + while (time_before(jiffies, timeout)) { if (chan->fsm_state) break; SLEEP(10); } diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index 1feffef7eba3..a925d1f3e962 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.16.6.1 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_isa.c,v 1.16.6.2 2001/11/06 20:58:29 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -20,7 +20,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.16.6.1 $"; +char *eicon_isa_revision = "$Revision: 1.16.6.2 $"; #undef EICON_MCA_DEBUG @@ -231,7 +231,7 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { boot = &card->shmem->boot; /* Delay 0.2 sec. */ - SLEEP(20); + SLEEP(HZ / 5); /* Start CPU */ writeb(cbuf.boot_opt, &boot->ctrl); @@ -244,10 +244,10 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { #endif /* CONFIG_MCA */ /* Delay 0.2 sec. */ - SLEEP(20); + SLEEP(HZ / 5); timeout = jiffies + (HZ * 22); - while (timeout > jiffies) { + while (time_before(jiffies, timeout)) { if (readb(&boot->ctrl) == 0) break; SLEEP(10); @@ -362,8 +362,8 @@ eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) { while (tmp--) { memcpy_toio(&boot->b, p, 256); writeb(1, &boot->ctrl); - timeout = jiffies + 10; - while (timeout > jiffies) { + timeout = jiffies + HZ / 10; + while (time_before(jiffies, timeout)) { if (readb(&boot->ctrl) == 0) break; SLEEP(2); @@ -386,7 +386,7 @@ eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) { /* Start firmware, wait for signature */ writeb(2, &boot->ctrl); timeout = jiffies + (5*HZ); - while (timeout > jiffies) { + while (time_before(jiffies, timeout)) { if (readw(&boot->signature) == 0x4447) break; SLEEP(2); @@ -410,8 +410,8 @@ eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) { tmp = readb(&card->shmem->com.ReadyInt); tmp ++; writeb(tmp, &card->shmem->com.ReadyInt); - timeout = jiffies + 20; - while (timeout > jiffies) { + timeout = jiffies + HZ / 5; + while (time_before(jiffies, timeout)) { if (card->irqprobe > 1) break; SLEEP(2); diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c index 653349abc471..67c245a886c3 100644 --- a/drivers/isdn/hysdn/boardergo.c +++ b/drivers/isdn/hysdn/boardergo.c @@ -1,4 +1,4 @@ -/* $Id: boardergo.c,v 1.5.6.6 2001/09/23 22:24:54 kai Exp $ +/* $Id: boardergo.c,v 1.5.6.7 2001/11/06 21:58:19 kai Exp $ * * Linux driver for HYSDN cards, specific routines for ergo type boards. * diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c index d823b0f07f48..1586fcaf0308 100644 --- a/drivers/isdn/hysdn/hysdn_sched.c +++ b/drivers/isdn/hysdn/hysdn_sched.c @@ -1,4 +1,4 @@ -/* $Id: hysdn_sched.c,v 1.5.6.3 2001/09/23 22:24:54 kai Exp $ +/* $Id: hysdn_sched.c,v 1.5.6.4 2001/11/06 21:58:19 kai Exp $ * * Linux driver for HYSDN cards * scheduler routines for handling exchange card <-> pc. diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 130710926447..a0749e798ce3 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.114.6.15 2001/09/23 22:24:31 kai Exp $ +/* $Id: isdn_common.c,v 1.114.6.16 2001/11/06 20:58:28 kai Exp $ * * Linux ISDN subsystem, common used functions (linklevel). * @@ -44,7 +44,7 @@ MODULE_LICENSE("GPL"); isdn_dev *dev; -static char *isdn_revision = "$Revision: 1.114.6.15 $"; +static char *isdn_revision = "$Revision: 1.114.6.16 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -1644,7 +1644,7 @@ isdn_open(struct inode *ino, struct file *filep) if (minor == ISDN_MINOR_STATUS) { infostruct *p; - if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) { + if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) { p->next = (char *) dev->infochain; p->private = (char *) &(filep->private_data); dev->infochain = p; @@ -1996,7 +1996,7 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding) if ((adding) && (d->rcverr)) kfree(d->rcverr); - if (!(d->rcverr = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { + if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); return -1; } @@ -2004,7 +2004,7 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding) if ((adding) && (d->rcvcount)) kfree(d->rcvcount); - if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { + if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); if (!adding) kfree(d->rcverr); return -1; @@ -2016,8 +2016,7 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding) skb_queue_purge(&d->rpqueue[j]); kfree(d->rpqueue); } - if (!(d->rpqueue = - (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) { + if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); if (!adding) { kfree(d->rcvcount); @@ -2031,8 +2030,7 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding) if ((adding) && (d->rcv_waitq)) kfree(d->rcv_waitq); - d->rcv_waitq = (wait_queue_head_t *) - kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL); + d->rcv_waitq = kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL); if (!d->rcv_waitq) { printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); if (!adding) { @@ -2157,7 +2155,7 @@ register_isdn(isdn_if * i) printk(KERN_WARNING "register_isdn: No write routine given.\n"); return 0; } - if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) { + if (!(d = kmalloc(sizeof(driver), GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); return 0; } diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 2d1e30e9340d..907c8711fc0f 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.140.6.10 2001/09/28 08:05:29 kai Exp $ +/* $Id: isdn_net.c,v 1.140.6.11 2001/11/06 20:58:28 kai Exp $ * * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -175,7 +175,7 @@ static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); -char *isdn_net_revision = "$Revision: 1.140.6.10 $"; +char *isdn_net_revision = "$Revision: 1.140.6.11 $"; /* * Code for raw-networking over ISDN @@ -333,7 +333,7 @@ isdn_net_autohup() anymore = 0; while (p) { isdn_net_local *l = p->local; - if ((jiffies - last_jiffies) == 0) + if (jiffies == last_jiffies) l->cps = l->transcount; else l->cps = (l->transcount * HZ) / (jiffies - last_jiffies); @@ -352,9 +352,9 @@ isdn_net_autohup() { if (l->hupflags & ISDN_MANCHARGE && l->hupflags & ISDN_CHARGEHUP) { - while (jiffies - l->chargetime > l->chargeint) + while (time_after(jiffies, l->chargetime + l->chargeint)) l->chargetime += l->chargeint; - if (jiffies - l->chargetime >= l->chargeint - 2 * HZ) + if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) if (l->outgoing || l->hupflags & ISDN_INHUP) isdn_net_hangup(&p->dev); } else if (l->outgoing) { @@ -363,7 +363,7 @@ isdn_net_autohup() printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", l->name, l->hupflags); isdn_net_hangup(&p->dev); - } else if (jiffies - l->chargetime > l->chargeint) { + } else if (time_after(jiffies, l->chargetime + l->chargeint)) { printk(KERN_DEBUG "isdn_net: %s: chtime = %lu, chint = %d\n", l->name, l->chargetime, l->chargeint); @@ -599,7 +599,7 @@ isdn_net_dial(void) anymore = 1; if(lp->dialtimeout > 0) - if(lp->dialstarted == 0 || jiffies > (lp->dialstarted + lp->dialtimeout + lp->dialwait)) { + if(lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) { lp->dialstarted = jiffies; lp->dialwait_timer = 0; } @@ -659,7 +659,7 @@ isdn_net_dial(void) printk(KERN_INFO "%s: Open leased line ...\n", lp->name); } else { if(lp->dialtimeout > 0) - if(jiffies > (lp->dialstarted + lp->dialtimeout)) { + if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { restore_flags(flags); lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; @@ -1106,7 +1106,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) lp->sqfull_stamp = jiffies; } else { /* subsequent overload: if slavedelay exceeded, start dialing */ - if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) { + if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) { slp = lp->slave->priv; if (!(slp->flags & ISDN_NET_CONNECTED)) { isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); @@ -1115,7 +1115,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) } } } else { - if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) { + if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) { lp->sqfull = 0; } /* this is a hack to allow auto-hangup for slaves on moderate loads */ @@ -1225,11 +1225,11 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) cli(); if(lp->dialwait_timer <= 0) - if(lp->dialstarted > 0 && lp->dialtimeout > 0 && jiffies < lp->dialstarted + lp->dialtimeout + lp->dialwait) + if(lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; if(lp->dialwait_timer > 0) { - if(jiffies < lp->dialwait_timer) { + if(time_before(jiffies, lp->dialwait_timer)) { isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); dev_kfree_skb(skb); restore_flags(flags); diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index eaeb23cad80b..c6ac0a6da259 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.85.6.7 2001/09/23 22:24:31 kai Exp $ +/* $Id: isdn_ppp.c,v 1.85.6.9 2001/11/06 20:58:28 kai Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -69,7 +69,7 @@ static void isdn_ppp_mp_cleanup( isdn_net_local * lp ); static int isdn_ppp_bundle(struct ippp_struct *, int unit); #endif /* CONFIG_ISDN_MPP */ -char *isdn_ppp_revision = "$Revision: 1.85.6.7 $"; +char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; @@ -977,7 +977,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } - if (is->compflags & SC_DECOMP_ON) { + if (mis->compflags & SC_DECOMP_ON) { skb = isdn_ppp_decompress(skb, is, mis, &proto); if (!skb) // decompression error return; @@ -993,6 +993,10 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff printk(KERN_DEBUG "isdn_ppp: IP\n"); skb->protocol = htons(ETH_P_IP); break; + case PPP_COMP: + case PPP_COMPFRAG: + printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); + goto drop_packet; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: if (is->debug & 0x20) @@ -1216,8 +1220,15 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) /* * normal (single link) or bundle compression */ - if(ipts->compflags & SC_COMP_ON) - skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); + if(ipts->compflags & SC_COMP_ON) { + /* We send compressed only if both down- und upstream + compression is negotiated, that means, CCP is up */ + if(ipts->compflags & SC_DECOMP_ON) { + skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); + } else { + printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n"); + } + } if (ipt->debug & 0x24) printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); @@ -2082,8 +2093,6 @@ static void isdn_ppp_ccp_timer_callback(unsigned long closure) } if(rs->ta && rs->state == CCPResetSentReq) { /* We are correct here */ - printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", - rs->id); if(!rs->expra) { /* Hmm, there is no Ack really expected. We can clean up the state now, it will be reallocated if the @@ -2092,6 +2101,8 @@ static void isdn_ppp_ccp_timer_callback(unsigned long closure) isdn_ppp_ccp_reset_free_state(rs->is, rs->id); return; } + printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", + rs->id); /* Push it again */ isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, rs->data, rs->dlen); @@ -2318,7 +2329,6 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc if (len <= 0) { switch(len) { case DECOMP_ERROR: - ri->pppcfg |= SC_DC_ERROR; printk(KERN_INFO "ippp: decomp wants reset %s params\n", rsparm.valid ? "with" : "without"); @@ -2482,7 +2492,6 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, len, NULL); /* TODO: This is not easy to decide here */ mis->compflags &= ~SC_DECOMP_DISCARD; - mis->pppcfg &= ~SC_DC_ERROR; } else { isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); @@ -2495,7 +2504,6 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, len, NULL); /* TODO: neither here */ is->compflags &= ~SC_LINK_DECOMP_DISCARD; - is->pppcfg &= ~SC_DC_ERROR; } break; @@ -2570,6 +2578,15 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, * that's too big of a change now. --kai */ +/* Actually, we might turn this into an advantage: deal with the RFC in + * the old tradition of beeing generous on what we accept, but beeing + * strict on what we send. Thus we should just + * - accept compressed frames as soon as decompression is negotiated + * - send compressed frames only when decomp *and* comp are negotiated + * - drop rx compressed frames if we cannot decomp (instead of pushing them + * up to ipppd) + * and I tried to modify this file according to that. --abp + */ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) { diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index adc7377d8dc8..c73a7d5b1cea 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.94.6.8 2001/09/23 22:24:32 kai Exp $ +/* $Id: isdn_tty.c,v 1.94.6.9 2001/11/06 20:58:29 kai Exp $ * * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -53,7 +53,7 @@ static int bit2si[8] = static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.94.6.8 $"; +char *isdn_tty_revision = "$Revision: 1.94.6.9 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -2596,11 +2596,11 @@ isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount, if (*(p++) == plus) { if ((*pluscount)++) { /* Time since last '+' > 0.5 sec. ? */ - if ((jiffies - *lastplus) > PLUSWAIT1) + if (time_after(jiffies, *lastplus + PLUSWAIT1)) *pluscount = 1; } else { /* Time since last non-'+' < 1.5 sec. ? */ - if ((jiffies - *lastplus) < PLUSWAIT2) + if (time_before(jiffies, *lastplus + PLUSWAIT2)) *pluscount = 0; } if ((*pluscount == 3) && (count == 1)) @@ -3974,7 +3974,7 @@ isdn_tty_modem_escape(void) if (info->online) { ton = 1; if ((info->emu.pluscount == 3) && - ((jiffies - info->emu.lastplus) > PLUSWAIT2)) { + time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) { info->emu.pluscount = 0; info->online = 0; isdn_tty_modem_result(RESULT_OK, info); diff --git a/drivers/isdn/tpam/tpam.h b/drivers/isdn/tpam/tpam.h index 3b6a2aa5a54b..dd139dce1c18 100644 --- a/drivers/isdn/tpam/tpam.h +++ b/drivers/isdn/tpam/tpam.h @@ -1,4 +1,4 @@ -/* $Id: tpam.h,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $ +/* $Id: tpam.h,v 1.1.2.3 2001/11/06 20:58:30 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver) * @@ -213,8 +213,8 @@ extern void tpam_recv_U3DataInd(tpam_card *, struct sk_buff *); extern void tpam_recv_U3ReadyToReceiveInd(tpam_card *, struct sk_buff *); /* Function prototypes from tpam_hdlc.c */ -extern u32 hdlc_encode(u8 *, u8 *, u32 *, u32); -extern u32 hdlc_decode(u8 *, u8 *, u32); +extern u32 tpam_hdlc_encode(u8 *, u8 *, u32 *, u32); +extern u32 tpam_hdlc_decode(u8 *, u8 *, u32); /* Function prototypes from tpam_crcpc.c */ extern void init_CRC(void); diff --git a/drivers/isdn/tpam/tpam_commands.c b/drivers/isdn/tpam/tpam_commands.c index 8d9d9b50b0a8..ca83345c3860 100644 --- a/drivers/isdn/tpam/tpam_commands.c +++ b/drivers/isdn/tpam/tpam_commands.c @@ -1,4 +1,4 @@ -/* $Id: tpam_commands.c,v 1.1.2.3 2001/09/23 22:25:03 kai Exp $ +/* $Id: tpam_commands.c,v 1.1.2.4 2001/11/06 20:58:30 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands) * @@ -206,7 +206,7 @@ static int tpam_command_ioctl_dsprun(tpam_card *card) { /* wait for the board signature */ timeout = jiffies + SIGNATURE_TIMEOUT; - while (timeout > jiffies) { + while (time_before(jiffies, timeout)) { spin_lock_irq(&card->lock); signature = copy_from_pam_dword(card, (void *)TPAM_MAGICNUMBER_REGISTER); @@ -241,7 +241,7 @@ static int tpam_command_ioctl_dsprun(tpam_card *card) { /* wait for NCO creation confirmation */ timeout = jiffies + NCOCREATE_TIMEOUT; - while (timeout > jiffies) { + while (time_before(jiffies, timeout)) { if (card->channels_tested == TPAM_NBCHANNEL) break; set_current_state(TASK_UNINTERRUPTIBLE); @@ -572,7 +572,7 @@ int tpam_writebuf_skb(int driverId, int channel, int ack, struct sk_buff *skb) { return -ENOMEM; } hdlc_no_accm_encode(skb->data, skb->len, tempdata, &templen); - finallen = hdlc_encode(tempdata, finaldata, + finallen = tpam_hdlc_encode(tempdata, finaldata, &card->channels[channel].hdlcshift, templen); free_page((u32)tempdata); @@ -897,7 +897,7 @@ void tpam_recv_U3DataInd(tpam_card *card, struct sk_buff *skb) { "get_free_page failed\n"); return; } - templen = hdlc_decode(data, tempdata, len); + templen = tpam_hdlc_decode(data, tempdata, len); templen = hdlc_no_accm_decode(tempdata, templen); if (!(result = alloc_skb(templen, GFP_ATOMIC))) { printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): " @@ -1019,6 +1019,6 @@ static void tpam_statcallb(tpam_card *card, isdn_ctrl ctrl) { init_timer(timer); timer->function = tpam_statcallb_run; timer->data = (unsigned long)ds; - timer->expires = jiffies + 0.1 * HZ; /* 0.1 second */ + timer->expires = jiffies + HZ / 10; /* 0.1 second */ add_timer(timer); } diff --git a/drivers/isdn/tpam/tpam_hdlc.c b/drivers/isdn/tpam/tpam_hdlc.c index 4c1d0971fb99..1fec4b8e53b1 100644 --- a/drivers/isdn/tpam/tpam_hdlc.c +++ b/drivers/isdn/tpam/tpam_hdlc.c @@ -1,4 +1,4 @@ -/* $Id: tpam_hdlc.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $ +/* $Id: tpam_hdlc.c,v 1.1.2.3 2001/11/06 20:58:30 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver - HDLC encoding) * @@ -35,11 +35,11 @@ Abstract: destuff5 : array necessary for the bit destuffing algorithm destuffs[] : array conaining the previous 6 arrays - hdlc_encode : bit stuffing of a byte array, with the addition of a start and - end flag, using the bit shift given in parameter (which is - updated at the end of encoding). - hdlc_decode : bit de-stuffing of a byte array with detection of possible - ABORTs. + tpam_hdlc_encode : bit stuffing of a byte array, with the addition + of a start and end flag, using the bit shift given in + parameter (which is updated at the end of encoding). + tpam_hdlc_decode : bit de-stuffing of a byte array with detection of + possible ABORTs. Revision History: @@ -553,7 +553,7 @@ WORD * destuffs[] = { destuff0, destuff1, destuff2, destuff3, destuff4, destuff5 /*- AuverTech Telecom -------------------------------------------------------+ | | - | @Function : hdlc_encode | + | @Function : tpam_hdlc_encode | | @Author : Cyrille Boudon | | | +---------------------------------------------------------------------------+ @@ -576,8 +576,8 @@ WORD * destuffs[] = { destuff0, destuff1, destuff2, destuff3, destuff4, destuff5 | beginning (for the first frame), the shift must be initialized to 0. | | | +---------------------------------------------------------------------------*/ -DWORD hdlc_encode(BYTE *pbyBuffIn, BYTE *pbyBuffOut, - DWORD *pdwInitialShift, DWORD dwLength) +DWORD tpam_hdlc_encode(BYTE *pbyBuffIn, BYTE *pbyBuffOut, + DWORD *pdwInitialShift, DWORD dwLength) { DWORD dwShifter; // temporary variable DWORD dwShiftNb; // shift due to the insertion of '0' @@ -754,7 +754,7 @@ carry: /*- AuverTech Telecom -------------------------------------------------------+ | | - | @Function : hdlc_decode | + | @Function : tpam_hdlc_decode | | @Author : Cyrille Boudon | | | +---------------------------------------------------------------------------+ @@ -773,7 +773,7 @@ carry: | If an abort is encountered, the returned count is '0'. | | | +---------------------------------------------------------------------------*/ -DWORD hdlc_decode(BYTE * pbyBuffIn, BYTE * pbyBuffOut, DWORD dwLength) +DWORD tpam_hdlc_decode(BYTE * pbyBuffIn, BYTE * pbyBuffOut, DWORD dwLength) { BYTE byCharIn; // byte being decoded BYTE byCarry; // current carry diff --git a/drivers/media/radio/Config.in b/drivers/media/radio/Config.in index c7608f8f74c0..00de39040c04 100644 --- a/drivers/media/radio/Config.in +++ b/drivers/media/radio/Config.in @@ -21,7 +21,7 @@ dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi -dep_tristate ' GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV +dep_tristate ' GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV $CONFIG_PCI dep_tristate ' Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV dep_tristate ' Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV dep_tristate ' miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER diff --git a/drivers/media/video/Config.in b/drivers/media/video/Config.in index 2286ed5a6e2f..4a4ed77a0b62 100644 --- a/drivers/media/video/Config.in +++ b/drivers/media/video/Config.in @@ -46,6 +46,9 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI fi dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +dep_tristate ' Iomega Buz support' CONFIG_VIDEO_ZORAN_BUZ $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +dep_tristate ' Miro DC10(+) support' CONFIG_VIDEO_ZORAN_DC10 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +dep_tristate ' Linux Media Labs LML33 support' CONFIG_VIDEO_ZORAN_LML33 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Sony Vaio Picturebook Motion Eye Video For Linux' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9b0e25fb6730..a47c96e3f786 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -44,7 +44,10 @@ obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o obj-$(CONFIG_VIDEO_W9966) += w9966.o -obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o saa7110.o saa7111.o saa7185.o adv7175.o bt819.o bt856.o +obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o +obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o +obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o +obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o obj-$(CONFIG_VIDEO_PMS) += pms.o obj-$(CONFIG_VIDEO_PLANB) += planb.o diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c index 390937636bf3..d5ce5f36aa84 100644 --- a/drivers/media/video/saa7110.c +++ b/drivers/media/video/saa7110.c @@ -83,6 +83,7 @@ int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsi while (len-- > 0) { if (i2c_sendbyte(decoder->bus,*data,0)) { i2c_stop(decoder->bus); + UNLOCK_I2C_BUS(decoder->bus); return -EAGAIN; } decoder->reg[subaddr++] = *data++; diff --git a/drivers/media/video/zr36067.c b/drivers/media/video/zr36067.c index 8a666285b4c2..0317ef7aa3bb 100644 --- a/drivers/media/video/zr36067.c +++ b/drivers/media/video/zr36067.c @@ -245,6 +245,13 @@ MODULE_PARM(pass_through, "i"); MODULE_PARM(lml33dpath, "i"); MODULE_PARM(video_nr, "i"); +static struct pci_device_id zr36067_pci_tbl[] = { + { PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); + /* Anybody who uses more than four? */ #define BUZ_MAX 4 diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c index 6490af3d2949..609cf285bfdb 100644 --- a/drivers/media/video/zr36120.c +++ b/drivers/media/video/zr36120.c @@ -60,6 +60,13 @@ static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE }; static int video_nr = -1; static int vbi_nr = -1; +static struct pci_device_id zr36120_pci_tbl[] = { + { PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, zr36120_pci_tbl); + MODULE_AUTHOR("Pauline Middelink "); MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber"); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c index 0d93b031cbca..b95e3b58d895 100644 --- a/drivers/mtd/chips/jedec.c +++ b/drivers/mtd/chips/jedec.c @@ -11,7 +11,7 @@ * not going to guess how to send commands to them, plus I expect they will * all speak CFI.. * - * $Id: jedec.c,v 1.11 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: jedec.c,v 1.12 2001/11/06 14:37:35 dwmw2 Exp $ */ #include @@ -42,6 +42,7 @@ static const struct JEDECTable JEDEC_table[] = {0xC2AD,"Macronix MX29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, {}}; +static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); static void jedec_sync(struct mtd_info *mtd) {}; static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); @@ -249,7 +250,7 @@ static int checkparity(u_char C) /* Take an array of JEDEC numbers that represent interleved flash chips and process them. Check to make sure they are good JEDEC numbers, look them up and then add them to the chip list */ -int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, +static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, unsigned long base,struct jedec_private *priv) { unsigned I,J; @@ -336,7 +337,7 @@ int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, } /* Lookup the chip information from the JEDEC ID table. */ -const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id) +static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id) { __u16 Id = (mfr << 8) | id; unsigned long I = 0; @@ -873,19 +874,19 @@ static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start } } -static int __init jedec_probe_init(void) +int __init jedec_init(void) { register_mtd_chip_driver(&jedec_chipdrv); return 0; } -static void __exit jedec_probe_exit(void) +static void __exit jedec_exit(void) { unregister_mtd_chip_driver(&jedec_chipdrv); } -module_init(jedec_probe_init); -module_exit(jedec_probe_exit); +module_init(jedec_init); +module_exit(jedec_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jason Gunthorpe et al."); diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 69c553bf0670..64fac448e2f7 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -422,7 +422,7 @@ static struct mtd_chip_driver jedec_chipdrv = { module: THIS_MODULE }; -static int __init jedec_probe_init(void) +int __init jedec_probe_init(void) { register_mtd_chip_driver(&jedec_chipdrv); return 0; diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 3cc97d397f48..08d029fd9668 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -1,5 +1,5 @@ /* - * $Id: redboot.c,v 1.5 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: redboot.c,v 1.6 2001/10/25 09:16:06 dwmw2 Exp $ * * Parse RedBoot-style Flash Image System (FIS) tables and * produce a Linux partition array to match. @@ -62,7 +62,15 @@ int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **ppa goto out; } - if (memcmp(buf, "RedBoot", 8)) { + /* RedBoot image could appear in any of the first three slots */ + for (i = 0; i < 3; i++) { + if (!memcmp(buf[i].name, "RedBoot", 8)) + break; + } + if (i == 3) { + /* Didn't find it */ + printk(KERN_NOTICE "No RedBoot partition table detected in %s\n", + master->name); ret = 0; goto out; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 32899ae207c4..62b7cf4739b6 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -868,7 +868,7 @@ static int vortex_cards_found; static int vortex_suspend (struct pci_dev *pdev, u32 state) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); if (dev && dev->priv) { if (netif_running(dev)) { @@ -881,7 +881,7 @@ static int vortex_suspend (struct pci_dev *pdev, u32 state) static int vortex_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); if (dev && dev->priv) { if (netif_running(dev)) { diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 9621524a3955..5fbd49d260be 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -80,6 +80,8 @@ Kalle Olavi Niemitalo - Wake-on-LAN ioctls + Robert Kuebel - Save kernel thread from dying on any signal. + Submitting bug reports: "rtl8139-diag -mmmaaavvveefN" output @@ -87,64 +89,16 @@ See 8139too.txt for more details. ------------------------------------------------------------------------------ - - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the RealTek RTL8139 series, the RealTek -Fast Ethernet controllers for PCI and CardBus. This chip is used on many -low-end boards, sometimes with its markings changed. - - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS will assign the -PCI INTA signal to a (preferably otherwise unused) system IRQ line. - -III. Driver operation - -IIIa. Rx Ring buffers - -The receive unit uses a single linear ring buffer rather than the more -common (and more efficient) descriptor-based architecture. Incoming frames -are sequentially stored into the Rx region, and the host copies them into -skbuffs. - -Comment: While it is theoretically possible to process many frames in place, -any delay in Rx processing would cause us to drop frames. More importantly, -the Linux protocol stack is not designed to operate in this manner. - -IIIb. Tx operation - -The RTL8139 uses a fixed set of four Tx descriptors in register space. -In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux -aligns the IP header on word boundaries, and 14 byte ethernet header means -that almost all frames will need to be copied to an alignment buffer. - -IVb. References - -http://www.realtek.com.tw/cn/cn.html -http://www.scyld.com/expert/NWay.html - -IVc. Errata - -1) The RTL-8139 has a serious problem with motherboards which do -posted MMIO writes to PCI space. This driver works around the -problem by having an MMIO register write be immediately followed by -an MMIO register read. - */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.20" +#define DRV_VERSION "0.9.22" #include #include #include +#include #include #include #include @@ -207,11 +161,10 @@ static int multicast_filter_limit = 32; /* Size of the in-memory receive ring. */ #define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) -#define RX_BUF_PAD 16 +#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) +#define RX_BUF_PAD 16 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ -#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) -#define RX_EARLY_THRESH 14 +#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -231,7 +184,7 @@ static int multicast_filter_limit = 32; #define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ #define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ - +#define TX_RETRY 8 /* 0-15. retries = 16 + (TX_RETRY * 16) */ /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -315,8 +268,6 @@ enum RTL8139_registers { TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ RxBuf = 0x30, - RxEarlyCnt = 0x34, - RxEarlyStatus = 0x36, ChipCmd = 0x37, RxBufPtr = 0x38, RxBufAddr = 0x3A, @@ -415,7 +366,8 @@ enum tx_config_bits { TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ TxClearAbt = (1 << 0), /* Clear abort (WO) */ - TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */ + TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */ TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ }; @@ -463,10 +415,6 @@ enum Config5Bits { }; enum RxConfigBits { - /* Early Rx threshold, none or X/16 */ - RxCfgEarlyRxNone = 0, - RxCfgEarlyRxShift = 24, - /* rx fifo threshold */ RxCfgFIFOShift = 13, RxCfgFIFONone = (7 << RxCfgFIFOShift), @@ -513,12 +461,6 @@ static const unsigned long param[4][4] = { {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83} }; -struct ring_info { - struct sk_buff *skb; - dma_addr_t mapping; -}; - - typedef enum { CH_8139 = 0, CH_8139_K, @@ -595,8 +537,6 @@ struct rtl8139_private { unsigned int tx_flag; unsigned long cur_tx; unsigned long dirty_tx; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct ring_info tx_info[NUM_TX_DESC]; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ dma_addr_t rx_ring_dma; @@ -616,6 +556,7 @@ struct rtl8139_private { struct completion thr_exited; u32 rx_config; struct rtl_extra_stats xstats; + int time_to_die; }; MODULE_AUTHOR ("Jeff Garzik "); @@ -714,10 +655,12 @@ static const u16 rtl8139_intr_mask = TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - (RX_EARLY_THRESH << RxCfgEarlyRxShift) | RxCfgRcv32K | RxNoWrap | - (RX_FIFO_THRESH << RxCfgFIFOShift) | - (RX_DMA_BURST << RxCfgDMAShift); + RxCfgRcv32K | RxNoWrap | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); +static const unsigned int rtl8139_tx_config = + (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift); static void __rtl8139_cleanup_dev (struct net_device *dev) { @@ -782,8 +725,6 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; u32 tmp; - DPRINTK ("ENTER\n"); - assert (pdev != NULL); *dev_out = NULL; @@ -792,7 +733,6 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pdev->slot_name); - DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); @@ -926,13 +866,11 @@ match: rtl8139_chip_reset (ioaddr); - DPRINTK ("EXIT, returning 0\n"); *dev_out = dev; return 0; err_out: __rtl8139_cleanup_dev (dev); - DPRINTK ("EXIT, returning %d\n", rc); return rc; } @@ -947,8 +885,6 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, static int board_idx = -1; u8 pci_rev; - DPRINTK ("ENTER\n"); - assert (pdev != NULL); assert (ent != NULL); @@ -975,10 +911,8 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, } i = rtl8139_init_board (pdev, &dev); - if (i < 0) { - DPRINTK ("EXIT, returning %d\n", i); + if (i < 0) return i; - } tp = dev->priv; ioaddr = tp->mmio_addr; @@ -1091,12 +1025,10 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - DPRINTK ("EXIT - returning 0\n"); return 0; err_out: __rtl8139_cleanup_dev (dev); - DPRINTK ("EXIT - returning %d\n", i); return i; } @@ -1106,8 +1038,6 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata (pdev); struct rtl8139_private *np; - DPRINTK ("ENTER\n"); - assert (dev != NULL); np = dev->priv; assert (np != NULL); @@ -1115,8 +1045,6 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) unregister_netdev (dev); __rtl8139_cleanup_dev (dev); - - DPRINTK ("EXIT\n"); } @@ -1149,8 +1077,6 @@ static int __devinit read_eeprom (void *ioaddr, int location, int addr_len) void *ee_addr = ioaddr + Cfg9346; int read_cmd = location | (EE_READ_CMD << addr_len); - DPRINTK ("ENTER\n"); - writeb (EE_ENB & ~EE_CS, ee_addr); writeb (EE_ENB, ee_addr); eeprom_delay (); @@ -1180,7 +1106,6 @@ static int __devinit read_eeprom (void *ioaddr, int location, int addr_len) writeb (~EE_CS, ee_addr); eeprom_delay (); - DPRINTK ("EXIT - returning %d\n", retval); return retval; } @@ -1218,16 +1143,12 @@ static void mdio_sync (void *mdio_addr) { int i; - DPRINTK ("ENTER\n"); - for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); mdio_delay (mdio_addr); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); mdio_delay (mdio_addr); } - - DPRINTK ("EXIT\n"); } #endif @@ -1241,10 +1162,7 @@ static int mdio_read (struct net_device *dev, int phy_id, int location) int i; #endif - DPRINTK ("ENTER\n"); - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - DPRINTK ("EXIT after directly using 8139 internal regs\n"); return location < 8 && mii_2_8139_map[location] ? readw (tp->mmio_addr + mii_2_8139_map[location]) : 0; } @@ -1271,7 +1189,6 @@ static int mdio_read (struct net_device *dev, int phy_id, int location) } #endif - DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); return (retval >> 1) & 0xffff; } @@ -1286,8 +1203,6 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, int i; #endif - DPRINTK ("ENTER\n"); - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ void *ioaddr = tp->mmio_addr; if (location == 0) { @@ -1330,13 +1245,9 @@ static int rtl8139_open (struct net_device *dev) void *ioaddr = tp->mmio_addr; #endif - DPRINTK ("ENTER\n"); - retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); - if (retval) { - DPRINTK ("EXIT, returning %d\n", retval); + if (retval) return retval; - } tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN, &tp->tx_bufs_dma); @@ -1352,7 +1263,6 @@ static int rtl8139_open (struct net_device *dev) pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, tp->rx_ring, tp->rx_ring_dma); - DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } @@ -1375,7 +1285,6 @@ static int rtl8139_open (struct net_device *dev) printk (KERN_WARNING "%s: unable to start kernel thread\n", dev->name); - DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -1384,8 +1293,6 @@ static void rtl_check_media (struct net_device *dev) { struct rtl8139_private *tp = dev->priv; - DPRINTK("ENTER\n"); - if (tp->phys[0] >= 0) { u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); if (mii_reg5 == 0xffff) @@ -1410,8 +1317,6 @@ static void rtl8139_hw_start (struct net_device *dev) u32 i; u8 tmp; - DPRINTK ("ENTER\n"); - /* Bring old chips out of low-power mode. */ if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'R'); @@ -1431,7 +1336,7 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W32 (RxConfig, tp->rx_config); /* Check this value: the documentation for IFG contradicts ifself. */ - RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); + RTL_W32 (TxConfig, rtl8139_tx_config); tp->cur_rx = 0; @@ -1472,8 +1377,6 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W16 (IntrMask, rtl8139_intr_mask); netif_start_queue (dev); - - DPRINTK ("EXIT\n"); } @@ -1483,19 +1386,12 @@ static void rtl8139_init_ring (struct net_device *dev) struct rtl8139_private *tp = dev->priv; int i; - DPRINTK ("ENTER\n"); - tp->cur_rx = 0; tp->cur_tx = 0; tp->dirty_tx = 0; - for (i = 0; i < NUM_TX_DESC; i++) { - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; + for (i = 0; i < NUM_TX_DESC; i++) tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE]; - } - - DPRINTK ("EXIT\n"); } @@ -1512,8 +1408,6 @@ static void rtl8139_tune_twister (struct net_device *dev, int linkcase; void *ioaddr = tp->mmio_addr; - DPRINTK ("ENTER\n"); - /* This is a complicated state machine to configure the "twister" for impedance/echos based on the cable length. All of this is magic and undocumented. @@ -1591,8 +1485,6 @@ static void rtl8139_tune_twister (struct net_device *dev, /* do nothing */ break; } - - DPRINTK ("EXIT\n"); } #endif /* CONFIG_8139TOO_TUNE_TWISTER */ @@ -1636,11 +1528,8 @@ static inline void rtl8139_thread_iter (struct net_device *dev, DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", dev->name, RTL_R16 (NWayLPAR)); - DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" - " RxStatus %4.4lx.\n", dev->name, - RTL_R16 (IntrMask), - RTL_R16 (IntrStatus), - RTL_R32 (RxEarlyStatus)); + DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n", + dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus)); DPRINTK ("%s: Chip config %2.2x %2.2x.\n", dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); @@ -1669,7 +1558,13 @@ static int rtl8139_thread (void *data) timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout); } while (!signal_pending (current) && (timeout > 0)); - if (signal_pending (current)) + if (signal_pending (current)) { + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + } + + if (tp->time_to_die) break; rtnl_lock (); @@ -1683,25 +1578,10 @@ static int rtl8139_thread (void *data) static void rtl8139_tx_clear (struct rtl8139_private *tp) { - int i; - tp->cur_tx = 0; tp->dirty_tx = 0; - /* Dump the unsent Tx packets. */ - for (i = 0; i < NUM_TX_DESC; i++) { - struct ring_info *rp = &tp->tx_info[i]; - if (rp->mapping != 0) { - pci_unmap_single (tp->pci_dev, rp->mapping, - rp->skb->len, PCI_DMA_TODEVICE); - rp->mapping = 0; - } - if (rp->skb) { - dev_kfree_skb (rp->skb); - rp->skb = NULL; - tp->stats.tx_dropped++; - } - } + /* XXX account for unsent Tx packets in tp->stats.tx_dropped */ } @@ -1755,42 +1635,29 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned int entry; - u32 dma_addr; - - mb(); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - assert (tp->tx_info[entry].skb == NULL); - assert (tp->tx_info[entry].mapping == 0); - - tp->tx_info[entry].skb = skb; - if ( !((unsigned long)skb->data & 3) && skb_shinfo(skb)->nr_frags == 0 && - skb->ip_summed != CHECKSUM_HW) { - tp->xstats.tx_buf_mapped++; - tp->tx_info[entry].mapping = - pci_map_single (tp->pci_dev, skb->data, skb->len, - PCI_DMA_TODEVICE); - dma_addr = tp->tx_info[entry].mapping; - } else if (skb->len < TX_BUF_SIZE) { + if (likely(skb->len < TX_BUF_SIZE)) { skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); - dma_addr = tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs); + dev_kfree_skb(skb); } else { dev_kfree_skb(skb); - tp->tx_info[entry].skb = NULL; + tp->stats.tx_dropped++; return 0; } + /* Note: the chip doesn't have auto-pad! */ spin_lock_irq(&tp->lock); - RTL_W32_F (TxAddr0 + (entry * 4), dma_addr); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; tp->cur_tx++; - mb(); + wmb(); + if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); spin_unlock_irq(&tp->lock); @@ -1831,7 +1698,9 @@ static void rtl8139_tx_interrupt (struct net_device *dev, tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; - RTL_W32_F (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); + RTL_W32 (TxConfig, TxClearAbt); + RTL_W16 (IntrStatus, TxErr); + wmb(); } if (txstatus & TxCarrierLost) tp->stats.tx_carrier_errors++; @@ -1853,17 +1722,6 @@ static void rtl8139_tx_interrupt (struct net_device *dev, tp->stats.tx_packets++; } - /* Free the original skb. */ - if (tp->tx_info[entry].mapping != 0) { - pci_unmap_single(tp->pci_dev, - tp->tx_info[entry].mapping, - tp->tx_info[entry].skb->len, - PCI_DMA_TODEVICE); - tp->tx_info[entry].mapping = 0; - } - dev_kfree_skb_irq (tp->tx_info[entry].skb); - tp->tx_info[entry].skb = NULL; - dirty_tx++; tx_left--; } @@ -2000,7 +1858,11 @@ static void rtl8139_rx_interrupt (struct net_device *dev, } #endif - if (rx_size == 0xfff0) { /* Early Rx in progress */ + /* Packet copy from FIFO still in progress. + * Theoretically, this should never happen + * since EarlyRx is disabled. + */ + if (rx_size == 0xfff0) { tp->xstats.early_rx++; break; } @@ -2059,10 +1921,6 @@ static void rtl8139_rx_interrupt (struct net_device *dev, RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); tp->cur_rx = cur_rx; - - if ((RTL_R8 (ChipCmd) & RxBufEmpty) && - (RTL_R16 (IntrStatus) & RxAckBits)) - RTL_W16_F (IntrStatus, RxAckBits); } @@ -2104,13 +1962,14 @@ static void rtl8139_weird_interrupt (struct net_device *dev, (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) tp->stats.rx_errors++; - if (status & (PCSTimeout)) + if (status & PCSTimeout) tp->stats.rx_length_errors++; if (status & (RxUnderrun | RxFIFOOver)) tp->stats.rx_fifo_errors++; if (status & PCIErr) { u16 pci_cmd_status; pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); + pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status); printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", dev->name, pci_cmd_status); @@ -2139,6 +1998,11 @@ static void rtl8139_interrupt (int irq, void *dev_instance, if (status == 0xFFFF) break; + if ((status & + (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | + RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) + break; + /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) @@ -2147,28 +2011,26 @@ static void rtl8139_interrupt (int irq, void *dev_instance, /* The chip takes special action when we clear RxAckBits, * so we clear them later in rtl8139_rx_interrupt */ - ackstat = status & ~RxAckBits; + ackstat = status & ~(RxAckBits | TxErr); RTL_W16 (IntrStatus, ackstat); DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", dev->name, ackstat, status, RTL_R16 (IntrStatus)); - if ((status & - (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) - break; - if (netif_running (dev) && (status & RxAckBits)) rtl8139_rx_interrupt (dev, tp, ioaddr); /* Check uncommon events with one test. */ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | TxErr | RxErr)) + RxFIFOOver | RxErr)) rtl8139_weird_interrupt (dev, tp, ioaddr, status, link_changed); - if (netif_running (dev) && (status & (TxOK | TxErr))) + if (netif_running (dev) && (status & (TxOK | TxErr))) { rtl8139_tx_interrupt (dev, tp, ioaddr); + if (status & TxErr) + RTL_W16 (IntrStatus, TxErr); + } boguscnt--; } while (boguscnt > 0); @@ -2195,11 +2057,11 @@ static int rtl8139_close (struct net_device *dev) int ret = 0; unsigned long flags; - DPRINTK ("ENTER\n"); - netif_stop_queue (dev); if (tp->thr_pid >= 0) { + tp->time_to_die = 1; + wmb(); ret = kill_proc (tp->thr_pid, SIGTERM, 1); if (ret) { printk (KERN_ERR "%s: unable to signal thread\n", dev->name); @@ -2243,7 +2105,6 @@ static int rtl8139_close (struct net_device *dev) if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - DPRINTK ("EXIT\n"); return 0; } @@ -2439,8 +2300,6 @@ static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) int rc = 0; int phy = tp->phys[0] & 0x3f; - DPRINTK ("ENTER\n"); - if (cmd != SIOCETHTOOL) { /* With SIOCETHTOOL, this would corrupt the pointer. */ data->phy_id &= 0x1f; @@ -2488,7 +2347,6 @@ static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) break; } - DPRINTK ("EXIT, returning %d\n", rc); return rc; } @@ -2499,8 +2357,6 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) void *ioaddr = tp->mmio_addr; unsigned long flags; - DPRINTK ("ENTER\n"); - if (netif_running(dev)) { spin_lock_irqsave (&tp->lock, flags); tp->stats.rx_missed_errors += RTL_R32 (RxMissed); @@ -2508,7 +2364,6 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) spin_unlock_irqrestore (&tp->lock, flags); } - DPRINTK ("EXIT\n"); return &tp->stats; } @@ -2520,8 +2375,6 @@ static inline u32 ether_crc (int length, unsigned char *data) { int crc = -1; - DPRINTK ("ENTER\n"); - while (--length >= 0) { unsigned char current_octet = *data++; int bit; @@ -2530,7 +2383,6 @@ static inline u32 ether_crc (int length, unsigned char *data) ethernet_polynomial : 0); } - DPRINTK ("EXIT, returning %u\n", crc); return crc; } @@ -2543,8 +2395,6 @@ static void __set_rx_mode (struct net_device *dev) int i, rx_mode; u32 tmp; - DPRINTK ("ENTER\n"); - DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", dev->name, dev->flags, RTL_R32 (RxConfig)); @@ -2583,9 +2433,6 @@ static void __set_rx_mode (struct net_device *dev) } RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); - - - DPRINTK ("EXIT\n"); } static void rtl8139_set_rx_mode (struct net_device *dev) diff --git a/drivers/net/Config.in b/drivers/net/Config.in index db488cecc753..5b781d9b1b28 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -274,6 +274,9 @@ if [ ! "$CONFIG_PPP" = "n" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP fi + if [ ! "$CONFIG_ATM" = "n" ]; then + dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP + fi fi tristate 'SLIP (serial line) support' CONFIG_SLIP diff --git a/drivers/net/appletalk/Config.in b/drivers/net/appletalk/Config.in index e42231cbfc83..49473618aec0 100644 --- a/drivers/net/appletalk/Config.in +++ b/drivers/net/appletalk/Config.in @@ -6,14 +6,14 @@ if [ "$CONFIG_ATALK" != "n" ]; then mainmenu_option next_comment comment 'Appletalk devices' bool 'Appletalk interfaces support' CONFIG_APPLETALK - if [ "$CONFIG_APPLETALK" != "n" ]; then - dep_tristate ' Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_APPLETALK - dep_tristate ' COPS LocalTalk PC support' CONFIG_COPS $CONFIG_APPLETALK + if [ "$CONFIG_ATALK" != "n" ]; then + dep_tristate ' Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_DEV_APPLETALK + dep_tristate ' COPS LocalTalk PC support' CONFIG_COPS $CONFIG_DEV_APPLETALK if [ "$CONFIG_COPS" != "n" ]; then bool ' Dayna firmware support' CONFIG_COPS_DAYNA bool ' Tangent firmware support' CONFIG_COPS_TANGENT fi - dep_tristate ' Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_APPLETALK + dep_tristate ' Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_DEV_APPLETALK if [ "$CONFIG_IPDDP" != "n" ]; then bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 4858285e861d..a6b5bc7efe88 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -83,7 +83,7 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de goto out_dev; } memset(lp, 0, sizeof(struct arcnet_local)); - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); ioaddr = pci_resource_start(pdev, 2); dev->base_addr = ioaddr; @@ -128,7 +128,7 @@ out_dev: static void __devexit com20020pci_remove(struct pci_dev *pdev) { - com20020_remove(pdev->driver_data); + com20020_remove(pci_get_drvdata(pdev)); } static struct pci_device_id com20020pci_id_table[] __devinitdata = { diff --git a/drivers/net/arlan.c b/drivers/net/arlan.c index 2f8c50e4c38f..1bc62e2ecd26 100644 --- a/drivers/net/arlan.c +++ b/drivers/net/arlan.c @@ -8,6 +8,10 @@ #include #include "arlan.h" +#if BITS_PER_LONG != 32 +# error FIXME: this driver requires a 32-bit platform +#endif + static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/"; struct net_device *arlan_device[MAX_ARLANS]; diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c index 401671513982..a93784df6638 100644 --- a/drivers/net/bsd_comp.c +++ b/drivers/net/bsd_comp.c @@ -1173,4 +1173,4 @@ void __exit bsdcomp_cleanup(void) module_init(bsdcomp_init); module_exit(bsdcomp_cleanup); -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c index fba554e9ea22..c94409b258b2 100644 --- a/drivers/net/dmfe.c +++ b/drivers/net/dmfe.c @@ -1,6 +1,4 @@ /* - dmfe.c: Version 1.36p1 2001-05-12 for Linux kernel 2.4.x - A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast ethernet driver for Linux. Copyright (C) 1997 Sten Wang @@ -38,19 +36,33 @@ Tobias Ringstrom : Cleaned up and added SMP safety. Thanks go to Jeff Garzik, - Andrew Morton and Frank Davis for the SMP safety fixes. + Andrew Morton and Frank Davis for the SMP safety fixes. + + Vojtech Pavlik : + Cleaned up pointer arithmetics. + Fixed a lot of 64bit issues. + Cleaned up printk()s a bit. + Fixed some obvious big endian problems. + + Tobias Ringstrom : + Use time_after for jiffies calculation. Added ethtool + support. Updated PCI resource allocation. Do not + forget to unmap PCI mapped skbs. TODO Implement pci_driver::suspend() and pci_driver::resume() power management methods. - Check and fix on 64bit and big endian boxes. + Check on 64 bit boxes. + Check and fix on big endian boxes. Test and make sure PCI latency is now correct for all cases. */ -#define DMFE_VERSION "1.36p1 (May 12, 2001)" +#define DRV_NAME "dmfe" +#define DRV_VERSION "1.36.3" +#define DRV_RELDATE "2001-11-06" #include @@ -68,6 +80,7 @@ #include #include #include +#include #include #include #include @@ -76,10 +89,7 @@ #include #include #include - -#if BITS_PER_LONG == 64 -#error FIXME: driver does not support 64-bit platforms -#endif +#include /* Board/System/Debug information/definition ---------------- */ @@ -130,9 +140,9 @@ #define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */ #define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */ -#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR ": %s %lx\n", (msg), (long) (value)) +#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value)) -#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); +#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); /* CR9 definition: SROM/MII */ @@ -160,26 +170,22 @@ /* Structure/enum declaration ------------------------------- */ struct tx_desc { - u32 tdes0, tdes1, tdes2, tdes3; - u32 tx_skb_ptr; - u32 tx_buf_ptr; - u32 next_tx_desc; - u32 reserved; -}; + u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ + char *tx_buf_ptr; /* Data for us */ + struct tx_desc *next_tx_desc; +} __attribute__(( aligned(32) )); struct rx_desc { - u32 rdes0, rdes1, rdes2, rdes3; - u32 rx_skb_ptr; - u32 rx_buf_ptr; - u32 next_rx_desc; - u32 reserved; -}; + u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ + struct sk_buff *rx_skb_ptr; /* Data for us */ + struct rx_desc *next_rx_desc; +} __attribute__(( aligned(32) )); struct dmfe_board_info { u32 chip_id; /* Chip vendor/Device ID */ u32 chip_revision; /* Chip revision */ struct DEVICE *next_dev; /* next device */ - struct pci_dev * net_dev; /* PCI device */ + struct pci_dev *pdev; /* PCI device */ spinlock_t lock; long ioaddr; /* I/O base address */ @@ -206,10 +212,10 @@ struct dmfe_board_info { struct rx_desc *first_rx_desc; struct rx_desc *rx_insert_ptr; struct rx_desc *rx_ready_ptr; /* packet come pointer */ - unsigned long tx_packet_cnt; /* transmitted packet count */ - unsigned long tx_queue_cnt; /* wait to send packet count */ - unsigned long rx_avail_cnt; /* available rx descriptor count */ - unsigned long interval_rx_cnt; /* rx packet count a callback time */ + unsigned long tx_packet_cnt; /* transmitted packet count */ + unsigned long tx_queue_cnt; /* wait to send packet count */ + unsigned long rx_avail_cnt; /* available rx descriptor count */ + unsigned long interval_rx_cnt; /* rx packet count a callback time */ u16 HPNA_command; /* For HPNA register 16 */ u16 HPNA_timer; /* For HPNA remote device check */ @@ -263,7 +269,8 @@ enum dmfe_CR6_bits { /* Global variable declaration ----------------------------- */ static int __devinitdata printed_version; static char version[] __devinitdata = - KERN_INFO "Davicom DM9xxx net driver, version " DMFE_VERSION "\n"; + KERN_INFO DRV_NAME ": Davicom DM9xxx net driver, version " + DRV_VERSION " (" DRV_RELDATE ")\n"; static int dmfe_debug; static unsigned char dmfe_media_mode = DMFE_AUTO; @@ -358,7 +365,7 @@ static int dmfe_do_ioctl(struct DEVICE *, struct ifreq *, int); static u16 read_srom_word(long ,int); static void dmfe_interrupt(int , void *, struct pt_regs *); static void dmfe_descriptor_init(struct dmfe_board_info *, unsigned long); -static void allocated_rx_buffer(struct dmfe_board_info *); +static void allocate_rx_buffer(struct dmfe_board_info *); static void update_cr6(u32, unsigned long); static void send_filter_frame(struct DEVICE * ,int); static void dm9132_id_table(struct DEVICE * ,int); @@ -371,7 +378,7 @@ static void dmfe_process_mode(struct dmfe_board_info *); static void dmfe_timer(unsigned long); static void dmfe_rx_packet(struct DEVICE *, struct dmfe_board_info *); static void dmfe_free_tx_pkt(struct DEVICE *, struct dmfe_board_info *); -static void dmfe_reused_skb(struct dmfe_board_info *, struct sk_buff *); +static void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *); static void dmfe_dynamic_reset(struct DEVICE *); static void dmfe_free_rxbuffer(struct dmfe_board_info *); static void dmfe_init_dm910x(struct DEVICE *); @@ -391,31 +398,46 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *); static int __devinit dmfe_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - unsigned long pci_iobase; - u8 pci_irqline; struct dmfe_board_info *db; /* board information structure */ - int i; struct net_device *dev; u32 dev_rev, pci_pmr; + int i, err; + + DMFE_DBUG(0, "dmfe_init_one()", 0); if (!printed_version++) printk(version); - DMFE_DBUG(0, "dmfe_init_one()", 0); + /* Init network device */ + dev = alloc_etherdev(sizeof(*db)); + if (dev == NULL) + return -ENOMEM; + SET_MODULE_OWNER(dev); + + if (pci_set_dma_mask(pdev, 0xffffffff)) { + printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n"); + err = -ENODEV; + goto err_out_free; + } /* Enable Master/IO access, Disable memory access */ - i = pci_enable_device(pdev); - if (i) - return i; - pci_set_master(pdev); + err = pci_enable_device(pdev); + if (err) + goto err_out_free; + + if (!pci_resource_start(pdev, 0)) { + printk(KERN_ERR DRV_NAME ": I/O base is zero\n"); + err = -ENODEV; + goto err_out_disable; + } - pci_iobase = pci_resource_start(pdev, 0); - pci_irqline = pdev->irq; + /* Read Chip revision */ + pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev); - /* iobase check */ - if (pci_iobase == 0) { - printk(KERN_ERR ": I/O base is zero\n"); - return -ENODEV; + if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) { + printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n"); + err = -ENODEV; + goto err_out_disable; } #if 0 /* pci_{enable_device,set_master} sets minimum latency for us now */ @@ -427,51 +449,32 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80); #endif - /* Read Chip revision */ - pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev); - - /* Init network device */ - dev = alloc_etherdev(sizeof(*db)); - if (dev == NULL) - return -ENOMEM; - SET_MODULE_OWNER(dev); - - /* IO range check */ - if (pci_resource_len (pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) { - printk(KERN_ERR ": Allocated I/O size too small\n"); - goto err_out; - } - - if (!request_region(pci_iobase, - pci_resource_len (pdev, 0), - dev->name)) { - printk(KERN_ERR ": I/O conflict : IO=%lx Range=%x\n", - pci_iobase, CHK_IO_SIZE(pdev, dev_rev)); - goto err_out; + if (pci_request_regions(pdev, DRV_NAME)) { + printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n"); + err = -ENODEV; + goto err_out_disable; } /* Init system & device */ db = dev->priv; - /* Allocated Tx/Rx descriptor memory */ + /* Allocate Tx/Rx descriptor memory */ db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr); db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr); - db->first_tx_desc = (struct tx_desc *)db->desc_pool_ptr; + db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr; db->first_tx_desc_dma = db->desc_pool_dma_ptr; db->buf_pool_start = db->buf_pool_ptr; db->buf_pool_dma_start = db->buf_pool_dma_ptr; - pdev->driver_data = dev; - db->chip_id = ent->driver_data; - db->ioaddr = pci_iobase; + db->ioaddr = pci_resource_start(pdev, 0); db->chip_revision = dev_rev; - db->net_dev = pdev; + db->pdev = pdev; - dev->base_addr = pci_iobase; - dev->irq = pci_irqline; + dev->base_addr = db->ioaddr; + dev->irq = pdev->irq; pci_set_drvdata(pdev, dev); dev->open = &dmfe_open; dev->hard_start_xmit = &dmfe_start_xmit; @@ -490,29 +493,37 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, /* read 64 word srom data */ for (i = 0; i < 64; i++) - ((u16 *) db->srom)[i] = read_srom_word(pci_iobase, i); + ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i)); /* Set Node address */ for (i = 0; i < 6; i++) dev->dev_addr[i] = db->srom[20 + i]; - i = register_netdev (dev); - if (i) goto err_out; + err = register_netdev (dev); + if (err) + goto err_out_res; - printk(KERN_INFO "%s: Davicom DM%04lx at 0x%lx,", - dev->name, - ent->driver_data >> 16, - pci_iobase); + printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,", + dev->name, + ent->driver_data >> 16, + pdev->slot_name); for (i = 0; i < 6; i++) printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - printk(", IRQ %d\n", pci_irqline); + printk(", irq %d.\n", dev->irq); + + pci_set_master(pdev); return 0; -err_out: +err_out_res: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); +err_out_free: pci_set_drvdata(pdev, NULL); kfree(dev); - return -ENODEV; + + return err; } @@ -524,14 +535,13 @@ static void __exit dmfe_remove_one (struct pci_dev *pdev) DMFE_DBUG(0, "dmfe_remove_one()", 0); if (dev) { - pci_free_consistent(db->net_dev, sizeof(struct tx_desc) * + pci_free_consistent(db->pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, db->desc_pool_ptr, db->desc_pool_dma_ptr); - pci_free_consistent(db->net_dev, TX_BUF_ALLOC * TX_DESC_CNT + 4, + pci_free_consistent(db->pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, db->buf_pool_ptr, db->buf_pool_dma_ptr); unregister_netdev(dev); - release_region(dev->base_addr, - CHK_IO_SIZE(pdev, db->chip_revision)); + pci_release_regions(pdev); kfree(dev); /* free board information */ pci_set_drvdata(pdev, NULL); } @@ -552,7 +562,7 @@ static int dmfe_open(struct DEVICE *dev) DMFE_DBUG(0, "dmfe_open", 0); - ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev); + ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev); if (ret) return ret; @@ -683,7 +693,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* Too large packet check */ if (skb->len > MAX_PACKET_SIZE) { - printk(KERN_ERR ": big packet = %d\n", (u16)skb->len); + printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); return 0; } @@ -693,7 +703,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* No Tx resource check, it never happen nromally */ if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); - printk(KERN_ERR ": No Tx resource %ld\n", db->tx_queue_cnt); + printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt); return 1; } @@ -702,11 +712,11 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* transmit this packet */ txptr = db->tx_insert_ptr; - memcpy( (char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len); + memcpy(txptr->tx_buf_ptr, skb->data, skb->len); txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len); /* Point to next transmit free descriptor */ - db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc; + db->tx_insert_ptr = txptr->next_tx_desc; /* Transmit Packet Process */ if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) { @@ -765,7 +775,7 @@ static int dmfe_stop(struct DEVICE *dev) #if 0 /* show statistic counter */ - printk(": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", + printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", db->tx_fifo_underrun, db->tx_excessive_collision, db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, db->tx_jabber_timeout, db->reset_count, db->reset_cr8, @@ -822,9 +832,9 @@ static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs) if ( (db->cr5_data & 0x40) && db->rx_avail_cnt ) dmfe_rx_packet(dev, db); - /* reallocated rx descriptor buffer */ + /* reallocate rx descriptor buffer */ if (db->rx_avail_cntcr5_data & 0x01) @@ -852,11 +862,13 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) { struct tx_desc *txptr; unsigned long ioaddr = dev->base_addr; + u32 tdes0; txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { - /* printk(": tdes0=%x\n", txptr->tdes0); */ - if (txptr->tdes0 & 0x80000000) + tdes0 = le32_to_cpu(txptr->tdes0); + /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ + if (tdes0 & 0x80000000) break; /* A packet sent completed */ @@ -864,38 +876,38 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) db->stats.tx_packets++; /* Transmit statistic counter */ - if ( txptr->tdes0 != 0x7fffffff ) { - /* printk(": tdes0=%x\n", txptr->tdes0); */ - db->stats.collisions += (txptr->tdes0 >> 3) & 0xf; - db->stats.tx_bytes += txptr->tdes1 & 0x7ff; - if (txptr->tdes0 & TDES0_ERR_MASK) { + if ( tdes0 != 0x7fffffff ) { + /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ + db->stats.collisions += (tdes0 >> 3) & 0xf; + db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; + if (tdes0 & TDES0_ERR_MASK) { db->stats.tx_errors++; - if (txptr->tdes0 & 0x0002) { /* UnderRun */ + if (tdes0 & 0x0002) { /* UnderRun */ db->tx_fifo_underrun++; if ( !(db->cr6_data & CR6_SFT) ) { db->cr6_data = db->cr6_data | CR6_SFT; update_cr6(db->cr6_data, db->ioaddr); } } - if (txptr->tdes0 & 0x0100) + if (tdes0 & 0x0100) db->tx_excessive_collision++; - if (txptr->tdes0 & 0x0200) + if (tdes0 & 0x0200) db->tx_late_collision++; - if (txptr->tdes0 & 0x0400) + if (tdes0 & 0x0400) db->tx_no_carrier++; - if (txptr->tdes0 & 0x0800) + if (tdes0 & 0x0800) db->tx_loss_carrier++; - if (txptr->tdes0 & 0x4000) + if (tdes0 & 0x4000) db->tx_jabber_timeout++; } } - txptr = (struct tx_desc *) txptr->next_tx_desc; + txptr = txptr->next_tx_desc; }/* End of while */ /* Update TX remove pointer to next */ - db->tx_remove_ptr = (struct tx_desc *) txptr; + db->tx_remove_ptr = txptr; /* Send the Tx packet in queue */ if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) { @@ -921,49 +933,51 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) struct rx_desc *rxptr; struct sk_buff *skb; int rxlen; + u32 rdes0; rxptr = db->rx_ready_ptr; while(db->rx_avail_cnt) { - if (rxptr->rdes0 & 0x80000000) /* packet owner check */ + rdes0 = le32_to_cpu(rxptr->rdes0); + if (rdes0 & 0x80000000) /* packet owner check */ break; db->rx_avail_cnt--; db->interval_rx_cnt++; - if ( (rxptr->rdes0 & 0x300) != 0x300) { + pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + if ( (rdes0 & 0x300) != 0x300) { /* A packet without First/Last flag */ - /* reused this SKB */ - DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0); - dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + /* reuse this SKB */ + DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0); + dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } else { /* A packet with First/Last flag */ - rxlen = ( (rxptr->rdes0 >> 16) & 0x3fff) - 4; + rxlen = ( (rdes0 >> 16) & 0x3fff) - 4; /* error summary bit check */ - if (rxptr->rdes0 & 0x8000) { + if (rdes0 & 0x8000) { /* This is a error packet */ - //printk(": rdes0: %lx\n", rxptr->rdes0); + //printk(DRV_NAME ": rdes0: %lx\n", rdes0); db->stats.rx_errors++; - if (rxptr->rdes0 & 1) + if (rdes0 & 1) db->stats.rx_fifo_errors++; - if (rxptr->rdes0 & 2) + if (rdes0 & 2) db->stats.rx_crc_errors++; - if (rxptr->rdes0 & 0x80) + if (rdes0 & 0x80) db->stats.rx_length_errors++; } - if ( !(rxptr->rdes0 & 0x8000) || + if ( !(rdes0 & 0x8000) || ((db->cr6_data & CR6_PM) && (rxlen>6)) ) { - skb = (struct sk_buff *) rxptr->rx_skb_ptr; + skb = rxptr->rx_skb_ptr; /* Received Packet CRC check need or not */ if ( (db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1) != - (*(unsigned long *) (skb->tail+rxlen) ) - ) ) { + (*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */ /* Found a error received packet */ - dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + dmfe_reuse_skb(db, rxptr->rx_skb_ptr); db->dm910x_chk_mode = 3; } else { /* Good packet, send to upper layer */ @@ -971,11 +985,11 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) if ( (rxlen < RX_COPY_SIZE) && ( (skb = dev_alloc_skb(rxlen + 2) ) != NULL) ) { - /* size less than COPY_SIZE, allocated a rxlen SKB */ + /* size less than COPY_SIZE, allocate a rxlen SKB */ skb->dev = dev; skb_reserve(skb, 2); /* 16byte align */ - memcpy(skb_put(skb, rxlen), ((struct sk_buff *) rxptr->rx_skb_ptr)->tail, rxlen); - dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen); + dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } else { skb->dev = dev; skb_put(skb, rxlen); @@ -988,12 +1002,12 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) } } else { /* Reuse SKB buffer when the packet is error */ - DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0); - dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0); + dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } } - rxptr = (struct rx_desc *) rxptr->next_rx_desc; + rxptr = rxptr->next_rx_desc; } db->rx_ready_ptr = rxptr; @@ -1050,20 +1064,58 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) } +/* + * Process the ethtool ioctl command + */ + +static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct dmfe_board_info *db = dev->priv; + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + if (db->pdev) + strcpy(info.bus_info, db->pdev->slot_name); + else + sprintf(info.bus_info, "EISA 0x%lx %d", + dev->base_addr, dev->irq); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + return -EOPNOTSUPP; +} + + /* * Process the upper socket ioctl command */ static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd) { + int retval = -EOPNOTSUPP; DMFE_DBUG(0, "dmfe_do_ioctl()", 0); - return 0; + + switch(cmd) { + case SIOCETHTOOL: + return dmfe_ethtool_ioctl(dev, (void*)ifr->ifr_data); + } + + return retval; } /* * A periodic timer routine - * Dynamic media sense, allocated Rx buffer... + * Dynamic media sense, allocate Rx buffer... */ static void dmfe_timer(unsigned long data) @@ -1109,11 +1161,11 @@ static void dmfe_timer(unsigned long data) /* TX polling kick monitor */ if ( db->tx_packet_cnt && - ((jiffies - dev->trans_start) > DMFE_TX_KICK) ) { + time_after(jiffies, dev->trans_start + DMFE_TX_KICK) ) { outl(0x1, dev->base_addr + DCR1); /* Tx polling again */ /* TX Timeout */ - if ( (jiffies - dev->trans_start) > DMFE_TX_TIMEOUT ) { + if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) { db->reset_TXtimeout++; db->wait_reset = 1; printk(KERN_WARNING "%s: Tx timeout - resetting\n", @@ -1244,35 +1296,36 @@ static void dmfe_free_rxbuffer(struct dmfe_board_info * db) /* free allocated rx buffer */ while (db->rx_avail_cnt) { - dev_kfree_skb( (void *) (db->rx_ready_ptr->rx_skb_ptr) ); - db->rx_ready_ptr = (struct rx_desc *) db->rx_ready_ptr->next_rx_desc; + dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr); + db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc; db->rx_avail_cnt--; } } /* - * Reused the SK buffer + * Reuse the SK buffer */ -static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff * skb) +static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb) { struct rx_desc *rxptr = db->rx_insert_ptr; - if (!(rxptr->rdes0 & 0x80000000)) { - rxptr->rx_skb_ptr = (u32) skb; - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) { + rxptr->rx_skb_ptr = skb; + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); db->rx_avail_cnt++; - db->rx_insert_ptr = (struct rx_desc *) rxptr->next_rx_desc; + db->rx_insert_ptr = rxptr->next_rx_desc; } else - DMFE_DBUG(0, "SK Buffer reused method error", db->rx_avail_cnt); + DMFE_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt); } /* * Initialize transmit/Receive descriptor - * Using Chain structure, and allocated Tx/Rx buffer + * Using Chain structure, and allocate Tx/Rx buffer */ static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioaddr) @@ -1292,8 +1345,8 @@ static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioadd outl(db->first_tx_desc_dma, ioaddr + DCR4); /* TX DESC address */ /* rx descriptor start pointer */ - db->first_rx_desc = (struct rx_desc *) ( (u32) db->first_tx_desc + sizeof(struct rx_desc) * TX_DESC_CNT ); - db->first_rx_desc_dma = ( db->first_tx_desc_dma + sizeof(struct rx_desc) * TX_DESC_CNT); + db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT; + db->first_rx_desc_dma = db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT; db->rx_insert_ptr = db->first_rx_desc; db->rx_ready_ptr = db->first_rx_desc; outl(db->first_rx_desc_dma, ioaddr + DCR3); /* RX DESC address */ @@ -1303,18 +1356,18 @@ static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioadd tmp_buf_dma = db->buf_pool_dma_start; tmp_tx_dma = db->first_tx_desc_dma; for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) { - tmp_tx->tx_buf_ptr = (u32) tmp_buf; + tmp_tx->tx_buf_ptr = tmp_buf; tmp_tx->tdes0 = cpu_to_le32(0); tmp_tx->tdes1 = cpu_to_le32(0x81000000); /* IC, chain */ tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma); tmp_tx_dma += sizeof(struct tx_desc); tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma); - tmp_tx->next_tx_desc = (u32) ((u32) tmp_tx + sizeof(struct tx_desc)); - tmp_buf = (unsigned char *) ((u32) tmp_buf + TX_BUF_ALLOC); + tmp_tx->next_tx_desc = tmp_tx + 1; + tmp_buf = tmp_buf + TX_BUF_ALLOC; tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC; } (--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma); - tmp_tx->next_tx_desc = (u32) db->first_tx_desc; + tmp_tx->next_tx_desc = db->first_tx_desc; /* Init Receive descriptor chain */ tmp_rx_dma=db->first_rx_desc_dma; @@ -1323,13 +1376,13 @@ static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioadd tmp_rx->rdes1 = cpu_to_le32(0x01000600); tmp_rx_dma += sizeof(struct rx_desc); tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma); - tmp_rx->next_rx_desc = (u32) ((u32) tmp_rx + sizeof(struct rx_desc)); + tmp_rx->next_rx_desc = tmp_rx + 1; } (--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma); - tmp_rx->next_rx_desc = (u32) db->first_rx_desc; + tmp_rx->next_rx_desc = db->first_rx_desc; - /* pre-allocated Rx buffer */ - allocated_rx_buffer(db); + /* pre-allocate Rx buffer */ + allocate_rx_buffer(db); } @@ -1438,7 +1491,7 @@ static void send_filter_frame(struct DEVICE *dev, int mc_cnt) } /* prepare the setup frame */ - db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc; + db->tx_insert_ptr = txptr->next_tx_desc; txptr->tdes1 = cpu_to_le32(0x890000c0); /* Resource Check and Send the setup packet */ @@ -1457,10 +1510,10 @@ static void send_filter_frame(struct DEVICE *dev, int mc_cnt) /* * Allocate rx buffer, - * As possible as allocated maxiumn Rx buffer + * As possible as allocate maxiumn Rx buffer */ -static void allocated_rx_buffer(struct dmfe_board_info *db) +static void allocate_rx_buffer(struct dmfe_board_info *db) { struct rx_desc *rxptr; struct sk_buff *skb; @@ -1470,10 +1523,11 @@ static void allocated_rx_buffer(struct dmfe_board_info *db) while(db->rx_avail_cnt < RX_DESC_CNT) { if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) break; - rxptr->rx_skb_ptr = (u32) skb; /* FIXME */ - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rx_skb_ptr = skb; /* FIXME (?) */ + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); - rxptr = (struct rx_desc *) rxptr->next_rx_desc; + rxptr = rxptr->next_rx_desc; db->rx_avail_cnt++; } @@ -1540,7 +1594,7 @@ static u8 dmfe_sense_speed(struct dmfe_board_info * db) phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000; else /* DM9102/DM9102A */ phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000; - /* printk(": Phy_mode %x ",phy_mode); */ + /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ switch (phy_mode) { case 0x1000: db->op_mode = DMFE_10MHF; break; case 0x2000: db->op_mode = DMFE_10MFD; break; @@ -1830,7 +1884,7 @@ static void dmfe_parse_srom(struct dmfe_board_info * db) if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) { /* SROM V4.01 */ /* Get NIC support media mode */ - db->NIC_capability = *(u16 *) (&srom[34]); + db->NIC_capability = le16_to_cpup(srom + 34); db->PHY_reg4 = 0; for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) { switch( db->NIC_capability & tmp_reg ) { @@ -1842,7 +1896,7 @@ static void dmfe_parse_srom(struct dmfe_board_info * db) } /* Media Mode Force or not check */ - dmfe_mode = *( (int *) &srom[34]) & *( (int *) &srom[36] ); + dmfe_mode = le32_to_cpup(srom + 34) & le32_to_cpup(srom + 36); switch(dmfe_mode) { case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */ case 0x2: dmfe_media_mode = DMFE_10MFD; break; /* 10MFD */ @@ -2024,7 +2078,7 @@ MODULE_PARM(SF_mode, "i"); MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)"); MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA"); MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)"); - + /* Description: * when user used insmod to add module, system invoked init_module() * to initilize and register. diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index c12c00c59b0b..aac937002ca2 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -8,7 +8,7 @@ according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached at bao.ha@srs.gov + The author may be reached at bao.ha@srs.gov or 418 Hastings Place, Martinez, GA 30907. Things remaining to do: @@ -23,26 +23,29 @@ This is a compatibility hardware problem. Versions: + 0.12d fixing a problem with single card detected as eight eth devices + fixing a problem with sudden drop in card performance + (chris (asdn@go2.pl), 10/29/2001) 0.12c fixing some problems with old cards (aris, 01/08/2001) 0.12b misc fixes (aris, 06/26/2000) 0.12a port of version 0.12a of 2.2.x kernels to 2.3.x (aris (aris@conectiva.com.br), 05/19/2000) 0.11e some tweaks about multiple cards support (PdP, jul/aug 1999) 0.11d added __initdata, __init stuff; call spin_lock_init - in eepro_probe1. Replaced "eepro" by dev->name. Augmented - the code protected by spin_lock in interrupt routine + in eepro_probe1. Replaced "eepro" by dev->name. Augmented + the code protected by spin_lock in interrupt routine (PdP, 12/12/1998) - 0.11c minor cleanup (PdP, RMC, 09/12/1998) - 0.11b Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module - under 2.1.xx. Debug messages are flagged as KERN_DEBUG to - avoid console flooding. Added locking at critical parts. Now + 0.11c minor cleanup (PdP, RMC, 09/12/1998) + 0.11b Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module + under 2.1.xx. Debug messages are flagged as KERN_DEBUG to + avoid console flooding. Added locking at critical parts. Now the dawn thing is SMP safe. 0.11a Attempt to get 2.1.xx support up (RMC) 0.11 Brian Candler added support for multiple cards. Tested as a module, no idea if it works when compiled into kernel. 0.10e Rick Bressler notified me that ifconfig up;ifconfig down fails - because the irq is lost somewhere. Fixed that by moving + because the irq is lost somewhere. Fixed that by moving request_irq and free_irq to eepro_open and eepro_close respectively. 0.10d Ugh! Now Wakeup works. Was seriously broken in my first attempt. I'll need to find a way to specify an ioport other than @@ -50,8 +53,8 @@ And, yes, this is not the only reason. 0.10c PnP Wakeup Test for 595FX. uncomment #define PnPWakeup; to use. - 0.10b Should work now with (some) Pro/10+. At least for - me (and my two cards) it does. _No_ guarantee for + 0.10b Should work now with (some) Pro/10+. At least for + me (and my two cards) it does. _No_ guarantee for function with non-Pro/10+ cards! (don't have any) (RMC, 9/11/96) @@ -75,7 +78,7 @@ 0.07a Fix a stat report which counts every packet as a heart-beat failure. (BCH, 6/3/95) - 0.07 Modified to support all other 82595-based lan cards. + 0.07 Modified to support all other 82595-based lan cards. The IRQ vector of the EtherExpress Pro will be set according to the value saved in the EEPROM. For other cards, I will do autoirq_request() to grab the next @@ -85,14 +88,14 @@ print out format. (BCH, 3/9/95 and 3/14/95) 0.06 First stable release that I am comfortable with. (BCH, - 3/2/95) + 3/2/95) - 0.05 Complete testing of multicast. (BCH, 2/23/95) + 0.05 Complete testing of multicast. (BCH, 2/23/95) - 0.04 Adding multicast support. (BCH, 2/14/95) + 0.04 Adding multicast support. (BCH, 2/14/95) - 0.03 First widely alpha release for public testing. - (BCH, 2/14/95) + 0.03 First widely alpha release for public testing. + (BCH, 2/14/95) */ @@ -104,18 +107,18 @@ static const char version[] = /* Sources: - This driver wouldn't have been written without the availability - of the Crynwr's Lan595 driver source code. It helps me to - familiarize with the 82595 chipset while waiting for the Intel - documentation. I also learned how to detect the 82595 using + This driver wouldn't have been written without the availability + of the Crynwr's Lan595 driver source code. It helps me to + familiarize with the 82595 chipset while waiting for the Intel + documentation. I also learned how to detect the 82595 using the packet driver's technique. This driver is written by cutting and pasting the skeleton.c driver provided by Donald Becker. I also borrowed the EEPROM routine from Donald Becker's 82586 driver. - Datasheet for the Intel 82595 (including the TX and FX version). It - provides just enough info that the casual reader might think that it + Datasheet for the Intel 82595 (including the TX and FX version). It + provides just enough info that the casual reader might think that it documents the i82595. The User Manual for the 82595. It provides a lot of the missing @@ -157,7 +160,7 @@ static const char version[] = /* A zero-terminated list of I/O addresses to be probed. */ static unsigned int eepro_portlist[] compat_init_data = { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0}; -/* note: 0x300 is default, the 595FX supports ALL IO Ports +/* note: 0x300 is default, the 595FX supports ALL IO Ports from 0x000 to 0x3F0, some of which are reserved in PCs */ /* To try the (not-really PnP Wakeup: */ @@ -194,7 +197,7 @@ struct eepro_local { version of the 82595 chip. */ int stepping; - spinlock_t lock; /* Serializing lock */ + spinlock_t lock; /* Serializing lock */ }; /* The station (ethernet) address prefix, used for IDing the board. */ @@ -244,7 +247,7 @@ struct eepro_local { /* Word 5: */ #define ee_BNC_TPE 0 /* 0=TPE */ #define ee_BootType 1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */ -#define ee_BootTypeMask 0x3 +#define ee_BootTypeMask 0x3 #define ee_NumConn 3 /* Number of Connections 0= One or Two */ #define ee_FlashSock 4 /* Presence of Flash Socket 0= Present */ #define ee_PortTPE 5 @@ -323,10 +326,10 @@ single packet. In other systems with faster computers and more congested network traffics, the ring linked list should improve performance by allowing up to 8K worth of packets to be queued. -The sizes of the receive and transmit buffers can now be changed via lilo +The sizes of the receive and transmit buffers can now be changed via lilo or insmod. Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0" where rx-buffer is in KB unit. Modules uses the parameter mem which is -also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer." +also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer." The receive buffer has to be more than 3K or less than 29K. Otherwise, it is reset to the default of 24K, and, hence, 8K for the trasnmit buffer (transmit-buffer = 32K - receive-buffer). @@ -369,9 +372,9 @@ static unsigned rcv_start = RCV_START_PRO; #define XMT_CHAIN 0x04 #define XMT_COUNT 0x06 -#define BANK0_SELECT 0x00 -#define BANK1_SELECT 0x40 -#define BANK2_SELECT 0x80 +#define BANK0_SELECT 0x00 +#define BANK1_SELECT 0x40 +#define BANK2_SELECT 0x80 /* Bank 0 registers */ #define COMMAND_REG 0x00 /* Register 0 */ @@ -440,7 +443,7 @@ static unsigned xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; #define REG13 0x0d #define FDX 0x00 #define A_N_ENABLE 0x02 - + #define I_ADD_REG0 0x04 #define I_ADD_REG1 0x05 #define I_ADD_REG2 0x06 @@ -536,13 +539,13 @@ static unsigned eeprom_reg = EEPROM_REG_PRO; int __init eepro_probe(struct net_device *dev) { int i; - int base_addr = dev->base_addr; + int base_addr = dev ? dev->base_addr : 0; SET_MODULE_OWNER(dev); #ifdef PnPWakeup /* XXXX for multiple cards should this only be run once? */ - + /* Wakeup: */ #define WakeupPort 0x279 #define WakeupSeq {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\ @@ -568,7 +571,6 @@ int __init eepro_probe(struct net_device *dev) } #endif - if (base_addr > 0x1ff) /* Check a single specified location. */ return eepro_probe1(dev, base_addr); @@ -601,7 +603,7 @@ static void __init printEEPROMInfo(short ioaddr, struct net_device *dev) printk(KERN_DEBUG "Word0:\n"); printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP)); printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 ); - printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg)); + printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg)); printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4); if (net_debug>4) { @@ -660,15 +662,15 @@ static int __init eepro_probe1(struct net_device *dev, short ioaddr) ID_REG (register 2 of bank 0) */ id=inb(ioaddr + ID_REG); - + if (((id) & ID_REG_MASK) == ID_REG_SIG) { /* We seem to have the 82595 signature, let's play with its counter (last 2 bits of register 2 of bank 0) to be sure. */ - - counter = (id & R_ROBIN_BITS); - if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) == + + counter = (id & R_ROBIN_BITS); + if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) == (counter + 0x40)) { /* Yes, the 82595 has been found */ @@ -702,40 +704,40 @@ static int __init eepro_probe1(struct net_device *dev, short ioaddr) station_addr[0] = read_eeprom(ioaddr, 2, dev); } - + station_addr[1] = read_eeprom(ioaddr, 3, dev); station_addr[2] = read_eeprom(ioaddr, 4, dev); if (eepro) { printk("%s: Intel EtherExpress 10 ISA\n at %#x,", dev->name, ioaddr); - } else if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) { + } else if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) { /* int to IRQ Mask */ eepro = 2; - printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", + printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", dev->name, ioaddr); } else if (station_addr[2] == 0x00aa) { eepro = 1; - printk("%s: Intel EtherExpress Pro/10 ISA at %#x,", + printk("%s: Intel EtherExpress Pro/10 ISA at %#x,", dev->name, ioaddr); } else { eepro = 0; - printk("%s: Intel 82595-based lan card at %#x,", + printk("%s: Intel 82595-based lan card at %#x,", dev->name, ioaddr); } /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; - + for (i=0; i < 6; i++) { dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); } - + dev->mem_start = (RCV_LOWER_LIMIT << 8); - + if ((dev->mem_end & 0x3f) < 3 || /* RX buffer must be more than 3K */ (dev->mem_end & 0x3f) > 29) /* and less than 29K */ dev->mem_end = (RCV_UPPER_LIMIT << 8); @@ -745,15 +747,15 @@ static int __init eepro_probe1(struct net_device *dev, short ioaddr) rcv_ram = dev->mem_end - (RCV_LOWER_LIMIT << 8); } - /* From now on, dev->mem_end - dev->mem_start contains - * the actual size of rx buffer + /* From now on, dev->mem_end - dev->mem_start contains + * the actual size of rx buffer */ - + if (net_debug > 3) printk(", %dK RCV buffer", (int)(dev->mem_end - dev->mem_start)/1024); - - + + /* ............... */ if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) @@ -767,7 +769,7 @@ static int __init eepro_probe1(struct net_device *dev, short ioaddr) i = read_eeprom(ioaddr, 1, dev); irqMask = read_eeprom(ioaddr, 7, dev); i &= 0x07; /* Mask off INT number */ - + for (j=0; ((j<16) && (i>=0)); j++) { if ((irqMask & (1<priv); return -ENODEV; - } else - + } else + if (dev->irq==2) dev->irq = 9; } - + if (dev->irq > 2) { printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]); } else printk(", %s.\n", ifmap[dev->if_port]); - + if ((dev->mem_start & 0xf) > 0) /* I don't know if this is */ net_debug = dev->mem_start & 7; /* still useful or not */ @@ -803,7 +805,7 @@ static int __init eepro_probe1(struct net_device *dev, short ioaddr) dev->name); } - if (net_debug) + if (net_debug) printk(version); /* Grab the region so we can find another board if autoIRQ fails. */ @@ -854,15 +856,15 @@ static int eepro_grab_irq(struct net_device *dev) { int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 }; int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr; - + eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */ /* Enable the interrupt line. */ eepro_en_intline(ioaddr); - + /* be CAREFUL, BANK 0 now */ eepro_sw2bank0(ioaddr); - + /* clear all interrupts */ eepro_clear_int(ioaddr); @@ -882,7 +884,7 @@ static int eepro_grab_irq(struct net_device *dev) autoirq_setup(0); eepro_diag(ioaddr); /* RESET the 82595 */ - + if (*irqp == autoirq_report(2)) /* It's a good IRQ line */ break; @@ -920,38 +922,38 @@ static int eepro_open(struct net_device *dev) irqMask = read_eeprom(ioaddr,7,dev); if (lp->eepro == LAN595FX_10ISA) { - if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n"); + if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n"); } else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */ { lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */ - if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); + if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); } else if ((dev->dev_addr[0] == SA_ADDR0 && dev->dev_addr[1] == SA_ADDR1 && dev->dev_addr[2] == SA_ADDR2)) - { + { lp->eepro = 1; - if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n"); + if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n"); } /* Yes, an Intel EtherExpress Pro/10 */ else lp->eepro = 0; /* No, it is a generic 82585 lan card */ - /* Get the interrupt vector for the 82595 */ + /* Get the interrupt vector for the 82595 */ if (dev->irq < 2 && eepro_grab_irq(dev) == 0) { printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } - + if (request_irq(dev->irq , &eepro_interrupt, 0, dev->name, dev)) { printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } - + #ifdef irq2dev_map if (((irq2dev_map[dev->irq] != 0) - || (irq2dev_map[dev->irq] = dev) == 0) && + || (irq2dev_map[dev->irq] = dev) == 0) && (irq2dev_map[dev->irq]!=dev)) { /* printk("%s: IRQ map wrong\n", dev->name); */ free_irq(dev->irq, dev); @@ -965,18 +967,18 @@ static int eepro_open(struct net_device *dev) temp_reg = inb(ioaddr + eeprom_reg); lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */ - + if (net_debug > 3) printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping); if (temp_reg & 0x10) /* Check the TurnOff Enable bit */ outb(temp_reg & 0xef, ioaddr + eeprom_reg); - for (i=0; i < 6; i++) - outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); - + for (i=0; i < 6; i++) + outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); + temp_reg = inb(ioaddr + REG1); /* Setup Transmit Chaining */ outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */ - | RCV_Discard_BadFrame, ioaddr + REG1); + | RCV_Discard_BadFrame, ioaddr + REG1); temp_reg = inb(ioaddr + REG2); /* Match broadcast */ outb(temp_reg | 0x14, ioaddr + REG2); @@ -987,11 +989,11 @@ static int eepro_open(struct net_device *dev) /* Set the receiving mode */ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */ - /* Set the interrupt vector */ + /* Set the interrupt vector */ temp_reg = inb(ioaddr + INT_NO_REG); if (lp->eepro == 2 || lp->eepro == LAN595FX_10ISA) outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG); - else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); + else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); temp_reg = inb(ioaddr + INT_NO_REG); @@ -1004,8 +1006,8 @@ static int eepro_open(struct net_device *dev) /* Initialize the RCV and XMT upper and lower limits */ - outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); - outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); + outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); + outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); outb(XMT_LOWER_LIMIT, ioaddr + xmt_lower_limit_reg); outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg); @@ -1022,12 +1024,12 @@ static int eepro_open(struct net_device *dev) eepro_clear_int(ioaddr); /* Initialize RCV */ - outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); + outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); lp->rx_start = (RCV_LOWER_LIMIT << 8) ; - outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); + outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); /* Initialize XMT */ - outw(XMT_LOWER_LIMIT << 8, ioaddr + xmt_bar); + outw(XMT_LOWER_LIMIT << 8, ioaddr + xmt_bar); /* Check for the i82595TX and i82595FX */ old8 = inb(ioaddr + 8); @@ -1044,7 +1046,7 @@ static int eepro_open(struct net_device *dev) old9 = inb(ioaddr + 9); /*outb(~old9, ioaddr + 9); if (((temp_reg = inb(ioaddr + 9)) == ( (~old9)&0xff) )) {*/ - + if (irqMask==ee_FX_INT2IRQ) { enum iftype { AUI=0, BNC=1, TPE=2 }; @@ -1070,7 +1072,7 @@ static int eepro_open(struct net_device *dev) printk(KERN_DEBUG "i82595TX detected!\n"); } } - + eepro_sel_reset(ioaddr); SLOW_DOWN; SLOW_DOWN; @@ -1078,7 +1080,7 @@ static int eepro_open(struct net_device *dev) lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; lp->tx_last = 0; - netif_start_queue(dev); + netif_start_queue(dev); if (net_debug > 3) printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name); @@ -1097,7 +1099,7 @@ static void eepro_tx_timeout (struct net_device *dev) /* if (net_debug > 1) */ printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name, "network cable problem"); - /* This is not a duplicate. One message for the console, + /* This is not a duplicate. One message for the console, one for the the log file */ printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name, "network cable problem"); @@ -1109,10 +1111,10 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) { struct eepro_local *lp = (struct eepro_local *)dev->priv; unsigned long flags; - + if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name); - + netif_stop_queue (dev); spin_lock_irqsave(&lp->lock, flags); @@ -1138,7 +1140,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name); spin_unlock_irqrestore(&lp->lock, flags); - + return 0; } @@ -1163,17 +1165,17 @@ eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs) if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name); - + ioaddr = dev->base_addr; while (((status = inb(ioaddr + STATUS_REG)) & 0x06) && (boguscount--)) { - switch (status & (RX_INT | TX_INT)) { + #ifdef ANSWER_TX_AND_RX + switch (status & (RX_INT | TX_INT)) { case (RX_INT | TX_INT): eepro_ack_rxtx(ioaddr); break; -#endif case RX_INT: eepro_ack_rx(ioaddr); break; @@ -1181,20 +1183,24 @@ eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs) eepro_ack_tx(ioaddr); break; } +#endif if (status & RX_INT) { if (net_debug > 4) printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name); - /* Get the received packets */ - eepro_rx(dev); #ifndef ANSWER_TX_AND_RX - continue; + eepro_ack_rx(ioaddr); #endif + /* Get the received packets */ + eepro_rx(dev); } if (status & TX_INT) { if (net_debug > 4) printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name); +#ifndef ANSWER_TX_AND_RX + eepro_ack_tx(ioaddr); +#endif /* Process the status of transmitted packets */ eepro_transmit_interrupt(dev); } @@ -1219,12 +1225,12 @@ static int eepro_close(struct net_device *dev) /* Disable the physical interrupt line. */ temp_reg = inb(ioaddr + REG1); - outb(temp_reg & 0x7f, ioaddr + REG1); + outb(temp_reg & 0x7f, ioaddr + REG1); eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */ /* Flush the Tx and disable Rx. */ - outb(STOP_RCV_CMD, ioaddr); + outb(STOP_RCV_CMD, ioaddr); lp->tx_start = lp->tx_end = (XMT_LOWER_LIMIT << 8); lp->tx_last = 0; @@ -1269,7 +1275,7 @@ set_multicast_list(struct net_device *dev) unsigned short mode; struct dev_mc_list *dmi=dev->mc_list; - if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) + if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) { /* * We must make the kernel realise we had to move @@ -1277,18 +1283,18 @@ set_multicast_list(struct net_device *dev) * the cable. If it was a promisc request the * flag is already set. If not we assert it. */ - dev->flags|=IFF_PROMISC; + dev->flags|=IFF_PROMISC; eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); - outb(mode | PRMSC_Mode, ioaddr + REG2); + outb(mode | PRMSC_Mode, ioaddr + REG2); mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ printk("%s: promiscuous mode enabled.\n", dev->name); } - - else if (dev->mc_count==0 ) + + else if (dev->mc_count==0 ) { eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); @@ -1297,12 +1303,12 @@ set_multicast_list(struct net_device *dev) outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ } - - else + + else { unsigned short status, *eaddrs; int i, boguscount = 0; - + /* Disable RX and TX interrupts. Necessary to avoid corruption of the HOST_ADDRESS_REG by interrupt service routines. */ @@ -1310,7 +1316,7 @@ set_multicast_list(struct net_device *dev) eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); - outb(mode | Multi_IA, ioaddr + REG2); + outb(mode | Multi_IA, ioaddr + REG2); mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ @@ -1319,8 +1325,8 @@ set_multicast_list(struct net_device *dev) outw(0, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(6*(dev->mc_count + 1), ioaddr + IO_PORT); - - for (i = 0; i < dev->mc_count; i++) + + for (i = 0; i < dev->mc_count; i++) { eaddrs=(unsigned short *)dmi->dmi_addr; dmi=dmi->next; @@ -1328,7 +1334,7 @@ set_multicast_list(struct net_device *dev) outw(*eaddrs++, ioaddr + IO_PORT); outw(*eaddrs++, ioaddr + IO_PORT); } - + eaddrs = (unsigned short *) dev->dev_addr; outw(eaddrs[0], ioaddr + IO_PORT); outw(eaddrs[1], ioaddr + IO_PORT); @@ -1338,10 +1344,10 @@ set_multicast_list(struct net_device *dev) /* Update the transmit queue */ i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1); - - if (lp->tx_start != lp->tx_end) + + if (lp->tx_start != lp->tx_end) { - /* update the next address and the chain bit in the + /* update the next address and the chain bit in the last packet */ outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); outw(i, ioaddr + IO_PORT); @@ -1358,13 +1364,13 @@ set_multicast_list(struct net_device *dev) do { /* We should be doing this in the eepro_interrupt()! */ SLOW_DOWN; SLOW_DOWN; - if (inb(ioaddr + STATUS_REG) & 0x08) + if (inb(ioaddr + STATUS_REG) & 0x08) { i = inb(ioaddr); outb(0x08, ioaddr + STATUS_REG); - + if (i & 0x20) { /* command ABORTed */ - printk("%s: multicast setup failed.\n", + printk("%s: multicast setup failed.\n", dev->name); break; } else if ((i & 0x0f) == 0x03) { /* MC-Done */ @@ -1411,10 +1417,10 @@ read_eeprom(int ioaddr, int location, struct net_device *dev) eepro_sw2bank1(ioaddr); outb(0x00, ioaddr + STATUS_REG); } - + eepro_sw2bank2(ioaddr); outb(ctrl_val, ee_addr); - + /* Shift the read command bits out. */ for (i = 8; i >= 0; i--) { short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI @@ -1426,7 +1432,7 @@ read_eeprom(int ioaddr, int location, struct net_device *dev) eeprom_delay(); } outb(ctrl_val, ee_addr); - + for (i = 16; i > 0; i--) { outb(ctrl_val | EESK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0); @@ -1467,7 +1473,7 @@ hardware_send_packet(struct net_device *dev, void *buf, short length) tx_available = lp->tx_start - lp->tx_end; else tx_available = XMT_RAM; - if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) + if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) /* No space available ??? */ { eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */ @@ -1481,19 +1487,19 @@ hardware_send_packet(struct net_device *dev, void *buf, short length) end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; if (end >= (XMT_UPPER_LIMIT << 8)) { /* the transmit buffer is wrapped around */ - if (((XMT_UPPER_LIMIT << 8) - last) <= XMT_HEADER) { + if (((XMT_UPPER_LIMIT << 8) - last) <= XMT_HEADER) { /* Arrrr!!!, must keep the xmt header together, several days were lost to chase this one down. */ - + last = (XMT_LOWER_LIMIT << 8); end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; } - + else end = (XMT_LOWER_LIMIT << 8) + (end - (XMT_UPPER_LIMIT <<8)); } outw(last, ioaddr + HOST_ADDRESS_REG); - outw(XMT_CMD, ioaddr + IO_PORT); + outw(XMT_CMD, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(end, ioaddr + IO_PORT); outw(length, ioaddr + IO_PORT); @@ -1508,24 +1514,24 @@ hardware_send_packet(struct net_device *dev, void *buf, short length) } /* A dummy read to flush the DRAM write pipeline */ - status = inw(ioaddr + IO_PORT); + status = inw(ioaddr + IO_PORT); - if (lp->tx_start == lp->tx_end) { + if (lp->tx_start == lp->tx_end) { outw(last, ioaddr + xmt_bar); outb(XMT_CMD, ioaddr); lp->tx_start = last; /* I don't like to change tx_start here */ } else { - /* update the next address and the chain bit in the + /* update the next address and the chain bit in the last packet */ - + if (lp->tx_end != last) { outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); - outw(last, ioaddr + IO_PORT); + outw(last, ioaddr + IO_PORT); } - + outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG); - status = inw(ioaddr + IO_PORT); + status = inw(ioaddr + IO_PORT); outw(status | CHAIN_BIT, ioaddr + IO_PORT); /* Continue the transmit command */ @@ -1543,7 +1549,7 @@ hardware_send_packet(struct net_device *dev, void *buf, short length) */ if (lp->eepro == LAN595FX_10ISA) netif_stop_queue(dev); - + /* Enable RX and TX interrupts */ eepro_en_int(ioaddr); @@ -1572,17 +1578,17 @@ eepro_rx(struct net_device *dev) /* Set the read pointer to the start of the RCV */ outw(rcv_car, ioaddr + HOST_ADDRESS_REG); - + rcv_event = inw(ioaddr + IO_PORT); while (rcv_event == RCV_DONE) { - - rcv_status = inw(ioaddr + IO_PORT); + + rcv_status = inw(ioaddr + IO_PORT); rcv_next_frame = inw(ioaddr + IO_PORT); - rcv_size = inw(ioaddr + IO_PORT); + rcv_size = inw(ioaddr + IO_PORT); if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) { - + /* Malloc up new buffer. */ struct sk_buff *skb; @@ -1602,31 +1608,31 @@ eepro_rx(struct net_device *dev) else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */ unsigned short temp = inb(ioaddr + INT_MASK_REG); outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG); - insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), + insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), (rcv_size + 3) >> 2); outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG); } - - skb->protocol = eth_type_trans(skb,dev); + + skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; } - - else { /* Not sure will ever reach here, + + else { /* Not sure will ever reach here, I set the 595 to discard bad received frames */ lp->stats.rx_errors++; - + if (rcv_status & 0x0100) lp->stats.rx_over_errors++; - + else if (rcv_status & 0x0400) lp->stats.rx_frame_errors++; - + else if (rcv_status & 0x0800) lp->stats.rx_crc_errors++; - - printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", + + printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size); } @@ -1641,10 +1647,10 @@ eepro_rx(struct net_device *dev) outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG); rcv_event = inw(ioaddr + IO_PORT); - } + } if (rcv_car == 0) rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff; - + outw(rcv_car - 1, ioaddr + RCV_STOP); if (net_debug > 5) @@ -1656,9 +1662,9 @@ eepro_transmit_interrupt(struct net_device *dev) { struct eepro_local *lp = (struct eepro_local *)dev->priv; short ioaddr = dev->base_addr; - short boguscount = 20; + short boguscount = 20; unsigned xmt_status; - + /* if (dev->tbusy == 0) { printk("%s: transmit_interrupt called with tbusy = 0 ??\n", @@ -1667,11 +1673,11 @@ eepro_transmit_interrupt(struct net_device *dev) dev->name); } */ - while (lp->tx_start != lp->tx_end && boguscount) { + while (lp->tx_start != lp->tx_end && boguscount) { - outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); + outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); xmt_status = inw(ioaddr+IO_PORT); - + if ((xmt_status & TX_DONE_BIT) == 0) { if (lp->eepro == LAN595FX_10ISA) { udelay(40); @@ -1682,20 +1688,20 @@ eepro_transmit_interrupt(struct net_device *dev) break; } - xmt_status = inw(ioaddr+IO_PORT); + xmt_status = inw(ioaddr+IO_PORT); lp->tx_start = inw(ioaddr+IO_PORT); if (lp->eepro == LAN595FX_10ISA) { lp->tx_start = (XMT_LOWER_LIMIT << 8); lp->tx_end = lp->tx_start; - + /* yeah, black magic :( */ eepro_sw2bank0(ioaddr); eepro_en_int(ioaddr); /* disabling rx */ eepro_dis_rx(ioaddr); - + /* enabling rx */ eepro_en_rx(ioaddr); } @@ -1703,7 +1709,7 @@ eepro_transmit_interrupt(struct net_device *dev) netif_wake_queue (dev); if (xmt_status & 0x2000) - lp->stats.tx_packets++; + lp->stats.tx_packets++; else { lp->stats.tx_errors++; if (xmt_status & 0x0400) { @@ -1719,7 +1725,7 @@ eepro_transmit_interrupt(struct net_device *dev) printk(KERN_DEBUG "%s: XMT status = %#x\n", dev->name, xmt_status); } - if (lp->eepro == LAN595FX_10ISA) { + if (lp->eepro == LAN595FX_10ISA) { /* Try to restart the adaptor. */ /* We are supposed to wait for 2 us after a SEL_RESET */ eepro_sel_reset(ioaddr); @@ -1727,7 +1733,7 @@ eepro_transmit_interrupt(struct net_device *dev) /* first enable interrupts */ eepro_sw2bank0(ioaddr); outb(ALL_MASK & ~(RX_INT | TX_INT), ioaddr + STATUS_REG); - + /* enabling rx */ eepro_en_rx(ioaddr); } @@ -1735,7 +1741,7 @@ eepro_transmit_interrupt(struct net_device *dev) if (xmt_status & 0x000f) { lp->stats.collisions += (xmt_status & 0x000f); } - + if ((xmt_status & 0x0040) == 0x0) { lp->stats.tx_heartbeat_errors++; } @@ -1778,7 +1784,7 @@ MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)"); MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)"); MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)"); -int +int init_module(void) { int i; @@ -1790,23 +1796,25 @@ init_module(void) else if (autodetect) { /* if autodetect is set then we must force detection */ io[0] = 0; - + printk("eepro_init_module: Auto-detecting boards (May God protect us...)\n"); - } + } for (i = 0; i < MAX_EEPRO; i++) { struct net_device *d = &dev_eepro[n_eepro]; d->mem_end = mem[n_eepro]; - d->base_addr = io[0]; + d->base_addr = io[n_eepro]; d->irq = irq[n_eepro]; d->init = eepro_probe; - if (register_netdev(d) == 0) - n_eepro++; - else - break; + if (io[n_eepro]>0) { + if (register_netdev(d) == 0) + n_eepro++; + else + break; + } } - + return n_eepro ? 0 : -ENODEV; } @@ -1814,7 +1822,7 @@ void cleanup_module(void) { int i; - + for (i=0; ibase_addr, EEPRO_IO_EXTENT); - + } } #endif /* MODULE */ diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 74a014ceef85..93ceec9f7c9d 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -108,10 +108,12 @@ static int debug = -1; /* The debug level */ #include #include +#include #include #include #include +#include #include MODULE_AUTHOR("Maintainer: Andrey V. Savochkin "); @@ -1913,6 +1915,35 @@ speedo_get_stats(struct net_device *dev) return &sp->stats; } +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + struct speedo_private *sp = dev->priv; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "eepro100", sizeof(info.driver)-1); + strncpy(info.version, version, sizeof(info.version)-1); + if (sp && sp->pdev) + strcpy(info.bus_info, sp->pdev->slot_name); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + } + + return -EOPNOTSUPP; +} + + + + + static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct speedo_private *sp = (struct speedo_private *)dev->priv; @@ -1952,6 +1983,8 @@ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) add_timer(&sp->timer); /* may be set to the past --SAW */ pci_set_power_state(sp->pdev, saved_acpi); return 0; + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); default: return -EOPNOTSUPP; } diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index d5b0da42a4ca..b92bf8543805 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1815,7 +1815,7 @@ static int netdev_close(struct net_device *dev) return 0; } -static struct pci_device_id fealnx_pci_tbl[] = __devinitdata { +static struct pci_device_id fealnx_pci_tbl[] __devinitdata = { {0x1516, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x1516, 0x0803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, {0x1516, 0x0891, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index a170e743ea18..8c6fd51055d4 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -279,7 +279,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) purb->timeout = MSECS_TO_JIFFIES(100); if ((ret = usb_submit_urb(purb))) { - IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n"); + WARNING(__FUNCTION__ "(), failed Speed URB\n"); } spin_unlock_irqrestore(&self->lock, flags); } @@ -296,14 +296,14 @@ static void speed_bulk_callback(purb_t purb) /* We should always have a context */ if (self == NULL) { - IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n"); + WARNING(__FUNCTION__ "(), Bug : self == NULL\n"); return; } /* Check for timeout and other USB nasties */ if(purb->status != USB_ST_NOERROR) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); /* Don't do anything here, that might confuse the USB layer. * Instead, we will wait for irda_usb_net_timeout(), the @@ -452,7 +452,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) /* Ask USB to send the packet */ if ((res = usb_submit_urb(purb))) { - IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n"); + WARNING(__FUNCTION__ "(), failed Tx URB\n"); self->stats.tx_errors++; /* Let USB recover : We will catch that in the watchdog */ /*netif_start_queue(netdev);*/ @@ -481,7 +481,7 @@ static void write_bulk_callback(purb_t purb) /* We should always have a context */ if (self == NULL) { - IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n"); + WARNING(__FUNCTION__ "(), Bug : self == NULL\n"); return; } @@ -492,7 +492,7 @@ static void write_bulk_callback(purb_t purb) /* Check for timeout and other USB nasties */ if(purb->status != USB_ST_NOERROR) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); /* Don't do anything here, that might confuse the USB layer, * and we could go in recursion and blow the kernel stack... @@ -514,7 +514,7 @@ static void write_bulk_callback(purb_t purb) /* If we need to change the speed or xbofs, do it now */ if ((self->new_speed != -1) || (self->new_xbofs != -1)) { - IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n"); + IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed now...\n"); irda_usb_change_speed_xbofs(self); } else { /* Otherwise, allow the stack to send more packets */ @@ -548,7 +548,7 @@ static void irda_usb_net_timeout(struct net_device *netdev) /* Check speed URB */ purb = &(self->speed_urb); if (purb->status != USB_ST_NOERROR) { - WARNING("%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); + IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); switch (purb->status) { case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */ @@ -575,7 +575,7 @@ static void irda_usb_net_timeout(struct net_device *netdev) if (purb->status != USB_ST_NOERROR) { struct sk_buff *skb = purb->context; - WARNING("%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); + IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); /* Increase error count */ self->stats.tx_errors++; @@ -694,7 +694,7 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_ /* Check that we have an urb */ if (!purb) { - IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n"); + WARNING(__FUNCTION__ "(), Bug : purb == NULL\n"); return; } @@ -704,7 +704,7 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_ if (!skb) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ - IRDA_DEBUG(0, __FUNCTION__ "(), Failed to allocate Rx skb\n"); + WARNING(__FUNCTION__ "(), Failed to allocate Rx skb\n"); return; } } else { @@ -734,7 +734,7 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_ if (ret) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ - IRDA_DEBUG(0, __FUNCTION__ "(), Failed to submit Rx URB %d\n", ret); + WARNING(__FUNCTION__ "(), Failed to submit Rx URB %d\n", ret); } } @@ -775,13 +775,13 @@ static void irda_usb_receive(purb_t purb) self->stats.rx_crc_errors++; break; case -ECONNRESET: /* -104 */ - WARNING(__FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags); /* uhci_cleanup_unlink() is going to kill the Rx * URB just after we return. No problem, at this * point the URB will be idle ;-) - Jean II */ break; default: - WARNING(__FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags); break; } goto done; @@ -893,7 +893,7 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self) */ static int irda_usb_net_init(struct net_device *dev) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); /* Set up to be a normal IrDA network device driver */ irda_device_setup(dev); @@ -917,7 +917,7 @@ static int irda_usb_net_open(struct net_device *netdev) char hwname[16]; int i; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; @@ -977,7 +977,7 @@ static int irda_usb_net_close(struct net_device *netdev) struct irda_usb_cb *self; int i; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; @@ -1142,7 +1142,7 @@ static inline int irda_usb_open(struct irda_usb_cb *self) struct net_device *netdev; int err; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); spin_lock_init(&self->lock); @@ -1197,7 +1197,7 @@ static inline int irda_usb_open(struct irda_usb_cb *self) */ static inline int irda_usb_close(struct irda_usb_cb *self) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(self != NULL, return -1;); @@ -1326,39 +1326,43 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) */ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) { - struct usb_interface_descriptor *interface; - struct irda_class_desc *desc, *ptr; + struct irda_class_desc *desc; int ret; - - desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL); + + desc = kmalloc(sizeof (*desc), GFP_KERNEL); if (desc == NULL) return NULL; - memset(desc, 0, sizeof(struct irda_class_desc)); - - ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc)); - IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret); - if (ret) { - WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret); - } + memset(desc, 0, sizeof(*desc)); - /* Check if we found it? */ - if (desc->bDescriptorType == USB_DT_IRDA) - return desc; + /* USB-IrDA class spec 1.0: + * 6.1.3: Standard "Get Descriptor" Device Request is not + * appropriate to retrieve class-specific descriptor + * 6.2.5: Class Specific "Get Class Descriptor" Interface Request + * is mandatory and returns the USB-IrDA class descriptor + */ - IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n"); + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), + IU_REQ_GET_CLASS_DESC, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500)); - /* Check if the class descriptor is interleaved with standard descriptors */ - interface = &dev->actconfig->interface[ifnum].altsetting[0]; - ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr); - if (ret) { - kfree(desc); - return NULL; + IRDA_DEBUG(1, __FUNCTION__ "(), ret=%d\n", ret); + if (ret < sizeof(*desc)) { + WARNING("usb-irda: class_descriptor read %s (%d)\n", + (ret<0) ? "failed" : "too short", ret); + } + else if (desc->bDescriptorType != USB_DT_IRDA) { + WARNING("usb-irda: bad class_descriptor type\n"); } - *desc = *ptr; + else { #ifdef IU_DUMP_CLASS_DESC - irda_usb_dump_class_desc(desc); + irda_usb_dump_class_desc(desc); #endif /* IU_DUMP_CLASS_DESC */ - return desc; + + return desc; + } + kfree(desc); + return NULL; } /*********************** USB DEVICE CALLBACKS ***********************/ @@ -1389,9 +1393,9 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, * don't need to check if the dongle is really ours. * Jean II */ - IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); - - MESSAGE("IRDA-USB found at address %d\n", dev->devnum); + MESSAGE("IRDA-USB found at address %d, Vendor: %x, Product: %x\n", + dev->devnum, dev->descriptor.idVendor, + dev->descriptor.idProduct); /* Try to cleanup all instance that have a pending disconnect * Instance will be in this state is the disconnect() occurs @@ -1416,7 +1420,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, } } if(self == NULL) { - IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n", + WARNING("Too many USB IrDA devices !!! (max = %d)\n", NIRUSB); return NULL; } @@ -1436,7 +1440,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, * specify an alternate, but very few driver do like this. * Jean II */ ret = usb_set_interface(dev, ifnum, 0); - IRDA_DEBUG(0, "usb-irda: set interface %d result %d\n", ifnum, ret); + IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", ifnum, ret); switch (ret) { case USB_ST_NOERROR: /* 0 */ break; @@ -1485,7 +1489,7 @@ static void irda_usb_disconnect(struct usb_device *dev, void *ptr) struct irda_usb_cb *self = (struct irda_usb_cb *) ptr; int i; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); /* Oups ! We are not there any more */ self->present = 0; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index e54e4bc03012..0627bd8e9062 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1238,7 +1238,7 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) } printk(KERN_INFO "%s: registered device %s\n", drivername, ndev->name); - pdev->driver_data = ndev; + pci_set_drvdata(pdev, ndev); return 0; @@ -1247,13 +1247,13 @@ out_freedev: out_disable: pci_disable_device(pdev); out: - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); return -ENODEV; } static void __devexit vlsi_irda_remove(struct pci_dev *pdev) { - struct net_device *ndev = pdev->driver_data; + struct net_device *ndev = pci_get_drvdata(pdev); if (ndev) { printk(KERN_INFO "%s: unregister device %s\n", @@ -1267,7 +1267,7 @@ static void __devexit vlsi_irda_remove(struct pci_dev *pdev) } else printk(KERN_CRIT "%s: lost netdevice?\n", drivername); - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); printk(KERN_INFO "%s: %s disabled\n", drivername, pdev->name); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 15678ae93f49..19dcbf23f934 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1,6 +1,7 @@ /* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP8381x series. */ /* Written/copyright 1999-2001 by Donald Becker. + Portions copyright (c) 2001 Sun Microsystems (thockin@sun.com) This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. @@ -95,6 +96,9 @@ * MDIO Cleanup (Tim Hockin) * Reformat register offsets/bits (jgarzik) + version 1.0.12: + * ETHTOOL_* further support (Tim Hockin) + TODO: * big endian support with CFG:BEM instead of cpu_to_le32 * support for an external PHY @@ -102,7 +106,7 @@ */ #define DRV_NAME "natsemi" -#define DRV_VERSION "1.07+LK1.0.11" +#define DRV_VERSION "1.07+LK1.0.12" #define DRV_RELDATE "Oct 19, 2001" /* Updated to recommendations in pci-skeleton v2.03. */ @@ -162,6 +166,9 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #define NATSEMI_HW_TIMEOUT 400 #define NATSEMI_TIMER_FREQ 3*HZ +#define NATSEMI_PG0_NREGS 64 +#define NATSEMI_PG1_NREGS 4 +#define NATSEMI_NREGS (NATSEMI_PG0_NREGS + NATSEMI_PG1_NREGS) #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ @@ -647,6 +654,7 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd); static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd); static void enable_wol_mode(struct net_device *dev, int enable_intr); static int netdev_close(struct net_device *dev); +static int netdev_get_regs(struct net_device *dev, u32 *buf); static int __devinit natsemi_probe1 (struct pci_dev *pdev, @@ -789,7 +797,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, chip_config & CfgAnegFull ? "full" : "half"); } printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", - dev->name, (int)mdio_read(dev, 1, MII_BMSR), + dev->name, mdio_read(dev, 1, MII_BMSR), np->advertising); /* save the silicon revision for later querying */ @@ -1647,8 +1655,12 @@ static void netdev_error(struct net_device *dev, int intr_status) printk(KERN_NOTICE "%s: Link wake-up event %8.8x\n", dev->name, wol_status); } - if (intr_status & RxStatusFIFOOver && debug) { - printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", dev->name); + if (intr_status & RxStatusFIFOOver) { + if (debug >= 2) { + printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", + dev->name); + } + np->stats.rx_fifo_errors++; } /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & IntrPCIErr) { @@ -1794,22 +1806,28 @@ static void set_rx_mode(struct net_device *dev) static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { struct netdev_private *np = dev->priv; - struct ethtool_cmd ecmd; - - if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) + u32 cmd; + + if (get_user(cmd, (u32 *)useraddr)) return -EFAULT; - switch (ecmd.cmd) { + switch (cmd) { + /* get driver info */ case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; - strcpy(info.driver, DRV_NAME); - strcpy(info.version, DRV_VERSION); - strcpy(info.bus_info, np->pci_dev->slot_name); + strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN); + strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN); + info.fw_version[0] = '\0'; + strncpy(info.bus_info, np->pci_dev->slot_name, + ETHTOOL_BUSINFO_LEN); + info.regdump_len = NATSEMI_NREGS; if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } + /* get settings */ case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = { ETHTOOL_GSET }; spin_lock_irq(&np->lock); netdev_get_ecmd(dev, &ecmd); spin_unlock_irq(&np->lock); @@ -1817,7 +1835,9 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) return -EFAULT; return 0; } + /* set settings */ case ETHTOOL_SSET: { + struct ethtool_cmd ecmd; int r; if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) return -EFAULT; @@ -1826,6 +1846,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) spin_unlock_irq(&np->lock); return r; } + /* get wake-on-lan */ case ETHTOOL_GWOL: { struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; spin_lock_irq(&np->lock); @@ -1836,6 +1857,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) return -EFAULT; return 0; } + /* set wake-on-lan */ case ETHTOOL_SWOL: { struct ethtool_wolinfo wol; int r; @@ -1847,6 +1869,71 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) spin_unlock_irq(&np->lock); return r; } + /* get registers */ + case ETHTOOL_GREGS: { + struct ethtool_regs regs; + u32 regbuf[NATSEMI_NREGS]; + int r; + + if (copy_from_user(®s, useraddr, sizeof(regs))) + return -EFAULT; + + if (regs.len > NATSEMI_NREGS) { + regs.len = NATSEMI_NREGS; + } + regs.version = 0; + if (copy_to_user(useraddr, ®s, sizeof(regs))) + return -EFAULT; + + useraddr += offsetof(struct ethtool_regs, data); + + spin_lock_irq(&np->lock); + r = netdev_get_regs(dev, regbuf); + spin_unlock_irq(&np->lock); + + if (r) + return r; + if (copy_to_user(useraddr, regbuf, regs.len*sizeof(u32))) + return -EFAULT; + return 0; + } + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + debug = edata.data; + return 0; + } + /* restart autonegotiation */ + case ETHTOOL_NWAY_RST: { + int tmp; + int r = -EINVAL; + /* if autoneg is off, it's an error */ + tmp = mdio_read(dev, 1, MII_BMCR); + if (tmp & BMCR_ANENABLE) { + tmp |= (BMCR_ANRESTART); + mdio_write(dev, 1, MII_BMCR, tmp); + r = 0; + } + return r; + } + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } } @@ -2085,6 +2172,33 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) return 0; } +static int netdev_get_regs(struct net_device *dev, u32 *buf) +{ + int i; + + /* read all of page 0 of registers */ + for (i = 0; i < NATSEMI_PG0_NREGS; i++) { + buf[i] = readl(dev->base_addr + i*4); + } + + /* read only the 'magic' registers from page 1 */ + writew(1, dev->base_addr + PGSEL); + buf[i++] = readw(dev->base_addr + PMDCSR); + buf[i++] = readw(dev->base_addr + TSTDAT); + buf[i++] = readw(dev->base_addr + DSPCFG); + buf[i++] = readw(dev->base_addr + SDCFG); + writew(0, dev->base_addr + PGSEL); + + /* the interrupt status is clear-on-read - see if we missed any */ + if (buf[4] & buf[5]) { + printk(KERN_WARNING + "%s: shoot, we dropped an interrupt (0x%x)\n", + dev->name, buf[4] & buf[5]); + } + + return 0; +} + static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 95d636283e43..8a1187855208 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1465,7 +1465,7 @@ static struct pci_driver driver = { static int __init ns83820_init(void) { - printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/100 driver.\n"); + printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/1000 driver.\n"); return pci_module_init(&driver); } diff --git a/drivers/net/pcmcia/xircom_cb.c b/drivers/net/pcmcia/xircom_cb.c index 47ed54e36a55..9fb35d9d0ff6 100644 --- a/drivers/net/pcmcia/xircom_cb.c +++ b/drivers/net/pcmcia/xircom_cb.c @@ -319,7 +319,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ */ static void __devexit xircom_remove(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *card; enter(); diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index eebd05d2300c..e7fe6ae79e54 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -1701,7 +1701,7 @@ MODULE_DEVICE_TABLE(pci, xircom_pci_table); #ifdef CONFIG_PM static int xircom_suspend(struct pci_dev *pdev, u32 state) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *tp = dev->priv; printk(KERN_INFO "xircom_suspend(%s)\n", dev->name); if (tp->open) @@ -1712,7 +1712,7 @@ static int xircom_suspend(struct pci_dev *pdev, u32 state) static int xircom_resume(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *tp = dev->priv; printk(KERN_INFO "xircom_resume(%s)\n", dev->name); @@ -1734,7 +1734,7 @@ static int xircom_resume(struct pci_dev *pdev) static void __devexit xircom_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); printk(KERN_INFO "xircom_remove_one(%s)\n", dev->name); unregister_netdev(dev); diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index c333e6180b20..a5e3595d5937 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -5,7 +5,7 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.8 + * Version: 0.6.9 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against @@ -29,6 +29,8 @@ * the original skb that was passed in on success, never on * failure. Delete the copy of the skb on failure to avoid * a memory leak. + * 081001 : Misc. cleanup (licence string, non-blocking, prevent + * reference of device on close). * * Author: Michal Ostrowski * Contributors: @@ -349,7 +351,7 @@ int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) if (relay_po == NULL) goto abort_kfree; - + if ((relay_po->sk->state & PPPOX_CONNECTED) == 0) goto abort_put; @@ -543,13 +545,12 @@ int pppoe_release(struct socket *sock) po = sk->protinfo.pppox; if (po->pppoe_pa.sid) { delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote); - po->pppoe_pa.sid = 0 ; } if (po->pppoe_dev) - dev_put(po->pppoe_dev); + dev_put(po->pppoe_dev); - po->pppoe_dev = NULL ; + po->pppoe_dev = NULL; sock_orphan(sk); sock->sk = NULL; @@ -944,7 +945,8 @@ int pppoe_rcvmsg(struct socket *sock, struct msghdr *m, int total_len, int flags goto end; } - skb = skb_recv_datagram(sk, flags, 0, &error); + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &error); if (error < 0) { goto end; @@ -1077,3 +1079,7 @@ void __exit pppoe_exit(void) module_init(pppoe_init); module_exit(pppoe_exit); + +MODULE_AUTHOR("Michal Ostrowski "); +MODULE_DESCRIPTION("PPP over Ethernet driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index f8b35ab6e1ff..ab01ac9f51bd 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -158,3 +158,7 @@ static void __exit pppox_exit(void) module_init(pppox_init); module_exit(pppox_exit); + +MODULE_AUTHOR("Michal Ostrowski "); +MODULE_DESCRIPTION("PPP over Ethernet driver (generic socket layer)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index be0805a21317..f476a5d483b3 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -826,7 +826,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) case E_RX_IDLE: printk(KERN_WARNING "%s: RX data not moving\n", dev->name); - break; + goto drop; case E_WATCHDOG: printk(KERN_INFO "%s: The watchdog is here to see " "us\n", dev->name); @@ -912,15 +912,43 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) case E_RX_PAR_ERR: printk(KERN_WARNING "%s: Receive parity error\n", dev->name); - break; + goto drop; case E_RX_LLRC_ERR: printk(KERN_WARNING "%s: Receive LLRC error\n", dev->name); - break; + goto drop; case E_PKT_LN_ERR: printk(KERN_WARNING "%s: Receive packet length " "error\n", dev->name); - break; + goto drop; + case E_DTA_CKSM_ERR: + printk(KERN_WARNING "%s: Data checksum error\n", + dev->name); + goto drop; + case E_SHT_BST: + printk(KERN_WARNING "%s: Unexpected short burst " + "error\n", dev->name); + goto drop; + case E_STATE_ERR: + printk(KERN_WARNING "%s: Recv. state transition" + " error\n", dev->name); + goto drop; + case E_UNEXP_DATA: + printk(KERN_WARNING "%s: Unexpected data error\n", + dev->name); + goto drop; + case E_LST_LNK_ERR: + printk(KERN_WARNING "%s: Link lost error\n", + dev->name); + goto drop; + case E_FRM_ERR: + printk(KERN_WARNING "%s: Framming Error\n", + dev->name); + goto drop; + case E_FLG_SYN_ERR: + printk(KERN_WARNING "%s: Flag sync. lost during" + "packet\n", dev->name); + goto drop; case E_RX_INV_BUF: printk(KERN_ERR "%s: Invalid receive buffer " "address\n", dev->name); @@ -942,6 +970,23 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) ®s->HostCtrl); wmb(); break; + drop: + /* Label packet to be dropped. + * Actual dropping occurs in rx + * handling. + * + * The index of packet we get to drop is + * the index of the packet following + * the bad packet. -kbf + */ + { + u16 index = rrpriv->evt_ring[eidx].index; + index = (index + (RX_RING_ENTRIES - 1)) % + RX_RING_ENTRIES; + rrpriv->rx_ring[index].mode |= + (PACKET_BAD | PACKET_END); + } + break; default: printk(KERN_WARNING "%s: Unhandled event 0x%02x\n", dev->name, rrpriv->evt_ring[eidx].code); @@ -968,6 +1013,11 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) printk("len %x, mode %x\n", pkt_len, rrpriv->rx_ring[index].mode); #endif + if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){ + rrpriv->stats.rx_dropped++; + goto defer; + } + if (pkt_len > 0){ struct sk_buff *skb; @@ -1046,6 +1096,15 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) printk("%s: interrupt, prodidx = %i, eidx = %i\n", dev->name, prodidx, rrpriv->info->evt_ctrl.pi); #endif + /* + * Order here is important. We must handle events + * before doing anything else in order to catch + * such things as LLRC errors, etc -kbf + */ + + eidx = rrpriv->info->evt_ctrl.pi; + if (prodidx != eidx) + eidx = rr_handle_event(dev, prodidx, eidx); rxindex = rrpriv->cur_rx; if (rxindex != rxlimit) @@ -1054,15 +1113,19 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) txcon = rrpriv->dirty_tx; if (txcsmr != txcon) { do { - rrpriv->stats.tx_packets++; - rrpriv->stats.tx_bytes +=rrpriv->tx_skbuff[txcon]->len; - dev_kfree_skb_irq(rrpriv->tx_skbuff[txcon]); - - rrpriv->tx_skbuff[txcon] = NULL; - rrpriv->tx_ring[txcon].size = 0; - set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); - rrpriv->tx_ring[txcon].mode = 0; - + /* Due to occational firmware TX producer/consumer out + * of sync. error need to check entry in ring -kbf + */ + if(rrpriv->tx_skbuff[txcon]){ + rrpriv->stats.tx_packets++; + rrpriv->stats.tx_bytes +=rrpriv->tx_skbuff[txcon]->len; + dev_kfree_skb_irq(rrpriv->tx_skbuff[txcon]); + + rrpriv->tx_skbuff[txcon] = NULL; + rrpriv->tx_ring[txcon].size = 0; + set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); + rrpriv->tx_ring[txcon].mode = 0; + } txcon = (txcon + 1) % TX_RING_ENTRIES; } while (txcsmr != txcon); wmb(); @@ -1077,10 +1140,6 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) } } - eidx = rrpriv->info->evt_ctrl.pi; - if (prodidx != eidx) - eidx = rr_handle_event(dev, prodidx, eidx); - eidx |= ((txcsmr << 8) | (rxlimit << 16)); writel(eidx, ®s->EvtCon); wmb(); @@ -1238,7 +1297,7 @@ static void rr_dump(struct net_device *dev) index, cons); if (rrpriv->tx_skbuff[index]){ - len = min(0x80, rrpriv->tx_skbuff[index]->len); + len = min_t(int, 0x80, rrpriv->tx_skbuff[index]->len); printk("skbuff for index %i is valid - dumping data (0x%x bytes - DMA len 0x%x)\n", index, len, rrpriv->tx_ring[index].size); for (i = 0; i < len; i++){ if (!(i & 7)) @@ -1249,7 +1308,7 @@ static void rr_dump(struct net_device *dev) } if (rrpriv->tx_skbuff[cons]){ - len = min(0x80, rrpriv->tx_skbuff[cons]->len); + len = min_t(int, 0x80, rrpriv->tx_skbuff[cons]->len); printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n", rrpriv->tx_ring[cons].mode, diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h index 81acdf88b38f..cf10c5c6217e 100644 --- a/drivers/net/rrunner.h +++ b/drivers/net/rrunner.h @@ -478,6 +478,7 @@ struct cmd { * Mode bits */ +#define PACKET_BAD 0x01 /* Packet had link-layer error */ #define INTERRUPT 0x02 #define TX_IP_CKSUM 0x04 #define PACKET_END 0x08 diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index d83aeffb391c..b1a855c3f5e9 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -797,4 +797,4 @@ EXPORT_SYMBOL(slhc_uncompress); EXPORT_SYMBOL(slhc_toss); #endif /* CONFIG_INET */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/strip.c b/drivers/net/strip.c index e78d5b991df0..3055536549da 100644 --- a/drivers/net/strip.c +++ b/drivers/net/strip.c @@ -2871,7 +2871,7 @@ module_exit(strip_exit_driver); MODULE_AUTHOR("Stuart Cheshire "); MODULE_DESCRIPTION("Starmode Radio IP (STRIP) Device Driver"); -MODULE_LICENSE("BSD without advertisement clause"); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_SUPPORTED_DEVICE("Starmode Radio IP (STRIP) modem"); diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 61a4759939fe..f70b8b149065 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -1230,6 +1230,7 @@ void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs) ti->open_action = RESTART; outb(0, dev->base_addr + ADAPTRESET); ibmtr_reset_timer(&(ti->tr_timer), dev);/*BMS try to reopen*/ + spin_unlock(&(ti->lock)); return; } if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 8dc7c621f67f..60b9e998564b 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -299,7 +299,7 @@ static int __devinit streamer_init_one(struct pci_dev *pdev, streamer_priv->streamer_ring_speed = ringspeed[card_no]; streamer_priv->streamer_message_level = message_level[card_no]; - pdev->driver_data=dev; + pci_set_drvdata(pdev, dev); spin_lock_init(&streamer_priv->streamer_lock); @@ -329,7 +329,7 @@ err_out: } static void __devexit streamer_remove_one(struct pci_dev *pdev) { - struct net_device *dev=pdev->driver_data; + struct net_device *dev=pci_get_drv_data(pdev); struct streamer_private *streamer_priv; #if STREAMER_DEBUG @@ -373,7 +373,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev) { release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev,0)); release_mem_region(pci_resource_start(pdev, 1), pci_resource_len(pdev,1)); kfree(dev); - pdev->driver_data=NULL; + pci_set_drvdata(pdev, NULL); } @@ -1704,7 +1704,7 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset, for(sdev=dev_streamer; sdev; sdev=sdev->next) { pci_device=sdev->pci_dev; - dev=pci_device->driver_data; + dev=pci_get_drvdata(pci_device); size = sprintf_info(buffer + len, dev); len += size; diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 082dc4583598..ec2cc2346afc 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -737,7 +737,7 @@ static void olympic_rx(struct net_device *dev) } else { if (buffer_cnt == 1) { - skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; + skb = dev_alloc_skb(max_t(int, olympic_priv->pkt_buf_sz,length)) ; } else { skb = dev_alloc_skb(length) ; } @@ -1684,7 +1684,7 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt static void __devexit olympic_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data ; + struct net_device *dev = pci_get_drvdata(pdev) ; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; if (olympic_priv->olympic_network_monitor) { @@ -1722,4 +1722,4 @@ static void __exit olympic_pci_cleanup(void) module_init(olympic_pci_init) ; module_exit(olympic_pci_cleanup) ; -MODULE_LICENSE("GPL"); \ No newline at end of file +MODULE_LICENSE("GPL"); diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index df814a4621d5..3a88c44120fe 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -106,10 +106,6 @@ void t21142_start_nway(struct net_device *dev) dev->if_port = 0; tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; - if (tp->chip_id == PNIC2) { - tp->csr6 = 0x01000000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0); - return; - } if (tulip_debug > 1) printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n", dev->name, csr14); @@ -127,23 +123,6 @@ void t21142_start_nway(struct net_device *dev) } -void pnic2_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); - - if (tulip_debug > 1) - printk(KERN_INFO"%s: PNIC-2 link status changed, CSR5/12/14 %8.8x" - " %8.8x, %8.8x.\n", - dev->name, csr12, csr5, (int)inl(ioaddr + CSR14)); - dev->if_port = 5; - tp->lpar = csr12 >> 16; - tp->nwayset = 1; - tp->csr6 = 0x01000000 | (tp->csr6 & 0xffff); - outl(tp->csr6, ioaddr + CSR6); - -} void t21142_lnk_change(struct net_device *dev, int csr5) { diff --git a/drivers/net/tulip/ChangeLog b/drivers/net/tulip/ChangeLog index 62a5a9d3fd51..1e0f5470fc79 100644 --- a/drivers/net/tulip/ChangeLog +++ b/drivers/net/tulip/ChangeLog @@ -1,3 +1,24 @@ +2001-11-06 Richard Mortimer + + * tulip_core.c: Correct set of values to mask out of csr0, + for DM9102A chips. Limit burst/alignment of DM9102A chips + on Sparcs. + +2001-11-06 Jun Sun + + * tulip_core.c: Support finding MAC address on + two MIPS boards, DDB5476 and DDB5477. + +2001-11-06 Kevin B. Hendricks + + * Makefile, tulip.h, tulip_core.c, pnic2.c, 21142.c: + Fixes for PNIC II support. + +2001-11-06 David S. Miller + + * tulip_core.c: Support reading MAC address from + Sparc OBP property local-mac-address. + 2001-07-17 Erik A. Hendriks * 21142.c: Merge fix from tulip.c 0.92w which prevents the diff --git a/drivers/net/tulip/Makefile b/drivers/net/tulip/Makefile index fabdaaa86dc6..b5b0767f80e3 100644 --- a/drivers/net/tulip/Makefile +++ b/drivers/net/tulip/Makefile @@ -11,7 +11,7 @@ O_TARGET := tulip.o obj-y := eeprom.o interrupt.o media.o \ timer.o tulip_core.o \ - 21142.o pnic.o + 21142.o pnic.o pnic2.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 797e1d83281c..c92b12ea9250 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -28,8 +28,8 @@ unsigned int tulip_max_interrupt_work; #define MIT_SIZE 15 unsigned int mit_table[MIT_SIZE+1] = { - /* CRS11 21143 hardware Mitigation Control Interrupt - We use only RX mitigation we other techniques for + /* CRS11 21143 hardware Mitigation Control Interrupt + We use only RX mitigation we other techniques for TX intr. mitigation. 31 Cycle Size (timer control) @@ -39,7 +39,7 @@ unsigned int mit_table[MIT_SIZE+1] = 19:17 RX No pkts before Int. 16 Continues Mode (CM) */ - + 0x0, /* IM disabled */ 0x80150000, /* RX time = 1, RX pkts = 2, CM = 1 */ 0x80150000, @@ -110,7 +110,7 @@ static int tulip_rx(struct net_device *dev) #ifdef CONFIG_NET_HW_FLOWCONTROL int drop = 0, mit_sel = 0; -/* that one buffer is needed for mit activation; or might be a +/* that one buffer is needed for mit activation; or might be a bug in the ring buffer code; check later -- JHS*/ if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--; @@ -210,7 +210,7 @@ static int tulip_rx(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); #ifdef CONFIG_NET_HW_FLOWCONTROL - mit_sel = + mit_sel = #endif netif_rx(skb); @@ -258,34 +258,34 @@ throttle: /* We use this simplistic scheme for IM. It's proven by real life installations. We can have IM enabled - continuesly but this would cause unnecessary latency. - Unfortunely we can't use all the NET_RX_* feedback here. - This would turn on IM for devices that is not contributing - to backlog congestion with unnecessary latency. + continuesly but this would cause unnecessary latency. + Unfortunely we can't use all the NET_RX_* feedback here. + This would turn on IM for devices that is not contributing + to backlog congestion with unnecessary latency. We monitor the the device RX-ring and have: HW Interrupt Mitigation either ON or OFF. - ON: More then 1 pkt received (per intr.) OR we are dropping + ON: More then 1 pkt received (per intr.) OR we are dropping OFF: Only 1 pkt received - + Note. We only use min and max (0, 15) settings from mit_table */ if( tp->flags & HAS_INTR_MITIGATION) { - if((received > 1 || mit_sel == NET_RX_DROP) - && tp->mit_sel != 15 ) { - tp->mit_sel = 15; + if((received > 1 || mit_sel == NET_RX_DROP) + && tp->mit_sel != 15 ) { + tp->mit_sel = 15; tp->mit_change = 1; /* Force IM change */ } if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) { - tp->mit_sel = 0; + tp->mit_sel = 0; tp->mit_change = 1; /* Force IM change */ } } - return RX_RING_SIZE+1; /* maxrx+1 */ + return RX_RING_SIZE+1; /* maxrx+1 */ #else return received; #endif diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index 2085146e7cf2..ce0f59d10489 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -62,7 +62,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5) dev->name, phy_reg, csr5); if (inl(ioaddr + CSR5) & TPLnkFail) { outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); - /* If we use an external MII, then we mustn't use the + /* If we use an external MII, then we mustn't use the * internal negotiation. */ if (tulip_media_cap[dev->if_port] & MediaIsMII) @@ -92,7 +92,7 @@ void pnic_timer(unsigned long data) struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; - + if(!inl(ioaddr + CSR7)) { /* the timer was called due to a work overflow * in the interrupt handler. Skip the connection diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c new file mode 100644 index 000000000000..9b209d2c8403 --- /dev/null +++ b/drivers/net/tulip/pnic2.c @@ -0,0 +1,407 @@ +/* + drivers/net/tulip/pnic2.c + + Maintained by Jeff Garzik + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. + Modified to hep support PNIC_II by Kevin B. Hendricks + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ + +*/ + + +/* Understanding the PNIC_II - everything is this file is based + * on the PNIC_II_PDF datasheet which is sorely lacking in detail + * + * As I understand things, here are the registers and bits that + * explain the masks and constants used in this file that are + * either different from the 21142/3 or important for basic operation. + * + * + * CSR 6 (mask = 0xfe3bd1fd of bits not to change) + * ----- + * Bit 24 - SCR + * Bit 23 - PCS + * Bit 22 - TTM (Trasmit Threshold Mode) + * Bit 18 - Port Select + * Bit 13 - Start - 1, Stop - 0 Transmissions + * Bit 11:10 - Loop Back Operation Mode + * Bit 9 - Full Duplex mode (Advertise 10BaseT-FD is CSR14<7> is set) + * Bit 1 - Start - 1, Stop - 0 Receive + * + * + * CSR 14 (mask = 0xfff0ee39 of bits not to change) + * ------ + * Bit 19 - PAUSE-Pause + * Bit 18 - Advertise T4 + * Bit 17 - Advertise 100baseTx-FD + * Bit 16 - Advertise 100baseTx-HD + * Bit 12 - LTE - Link Test Enable + * Bit 7 - ANE - Auto Negotiate Enable + * Bit 6 - HDE - Advertise 10baseT-HD + * Bit 2 - Reset to Power down - kept as 1 for normal operation + * Bit 1 - Loop Back enable for 10baseT MCC + * + * + * CSR 12 + * ------ + * Bit 25 - Partner can do T4 + * Bit 24 - Partner can do 100baseTx-FD + * Bit 23 - Partner can do 100baseTx-HD + * Bit 22 - Partner can do 10baseT-FD + * Bit 21 - Partner can do 10baseT-HD + * Bit 15 - LPN is 1 if all above bits are valid other wise 0 + * Bit 14:12 - autonegotiation state (write 001 to start autonegotiate) + * Bit 3 - Autopolarity state + * Bit 2 - LS10B - link state of 10baseT 0 - good, 1 - failed + * Bit 1 - LS100B - link state of 100baseT 0 - good, 1- faild + * + * + * Data Port Selection Info + *------------------------- + * + * CSR14<7> CSR6<18> CSR6<22> CSR6<23> CSR6<24> MODE/PORT + * 1 0 0 (X) 0 (X) 1 NWAY + * 0 0 1 0 (X) 0 10baseT + * 0 1 0 1 1 (X) 100baseT + * + * + */ + + + +#include "tulip.h" +#include +#include + + +void pnic2_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 3) + printk(KERN_INFO"%s: PNIC2 negotiation status %8.8x.\n", + dev->name,inl(ioaddr + CSR12)); + + if (next_tick) { + mod_timer(&tp->timer, RUN_AT(next_tick)); + } +} + + +void pnic2_start_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14; + int csr12; + + /* set up what to advertise during the negotiation */ + + /* load in csr14 and mask off bits not to touch + * comment at top of file explains mask value + */ + csr14 = (inl(ioaddr + CSR14) & 0xfff0ee39); + + /* bit 17 - advetise 100baseTx-FD */ + if (tp->sym_advertise & 0x0100) csr14 |= 0x00020000; + + /* bit 16 - advertise 100baseTx-HD */ + if (tp->sym_advertise & 0x0080) csr14 |= 0x00010000; + + /* bit 6 - advertise 10baseT-HD */ + if (tp->sym_advertise & 0x0020) csr14 |= 0x00000040; + + /* Now set bit 12 Link Test Enable, Bit 7 Autonegotiation Enable + * and bit 0 Don't PowerDown 10baseT + */ + csr14 |= 0x00001184; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, " + "csr14=%8.8x.\n", dev->name, csr14); + + /* tell pnic2_lnk_change we are doing an nway negotiation */ + dev->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + + /* now we have to set up csr6 for NWAY state */ + + tp->csr6 = inl(ioaddr + CSR6); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: On Entry to Nway, " + "csr6=%8.8x.\n", dev->name, tp->csr6); + + /* mask off any bits not to touch + * comment at top of file explains mask value + */ + tp->csr6 = tp->csr6 & 0xfe3bd1fd; + + /* don't forget that bit 9 is also used for advertising */ + /* advertise 10baseT-FD for the negotiation (bit 9) */ + if (tp->sym_advertise & 0x0040) tp->csr6 |= 0x00000200; + + /* set bit 24 for nway negotiation mode ... + * see Data Port Selection comment at top of file + * and "Stop" - reset both Transmit (bit 13) and Receive (bit 1) + */ + tp->csr6 |= 0x01000000; + outl(csr14, ioaddr + CSR14); + outl(tp->csr6, ioaddr + CSR6); + udelay(100); + + /* all set up so now force the negotiation to begin */ + + /* read in current values and mask off all but the + * Autonegotiation bits 14:12. Writing a 001 to those bits + * should start the autonegotiation + */ + csr12 = (inl(ioaddr + CSR12) & 0xffff8fff); + csr12 |= 0x1000; + outl(csr12, ioaddr + CSR12); +} + + + +void pnic2_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14; + + /* read the staus register to find out what is up */ + int csr12 = inl(ioaddr + CSR12); + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC2 link status interrupt %8.8x, " + " CSR5 %x, %8.8x.\n", dev->name, csr12, + csr5, inl(ioaddr + CSR14)); + + /* If NWay finished and we have a negotiated partner capability. + * check bits 14:12 for bit pattern 101 - all is good + */ + if (tp->nway && !tp->nwayset) { + + /* we did an auto negotiation */ + + if ((csr12 & 0x7000) == 0x5000) { + + /* negotiation ended successfully */ + + /* get the link partners reply and mask out all but + * bits 24-21 which show the partners capabilites + * and match those to what we advertised + * + * then begin to interpret the results of the negotiation. + * Always go in this order : (we are ignoring T4 for now) + * 100baseTx-FD, 100baseTx-HD, 10baseT-FD, 10baseT-HD + */ + + int negotiated = ((csr12 >> 16) & 0x01E0) & tp->sym_advertise; + tp->lpar = (csr12 >> 16); + tp->nwayset = 1; + + if (negotiated & 0x0100) dev->if_port = 5; + else if (negotiated & 0x0080) dev->if_port = 3; + else if (negotiated & 0x0040) dev->if_port = 4; + else if (negotiated & 0x0020) dev->if_port = 0; + else { + if (tulip_debug > 1) + printk(KERN_INFO "%s: funny autonegotiate result " + "csr12 %8.8x advertising %4.4x\n", + dev->name, csr12, tp->sym_advertise); + tp->nwayset = 0; + /* so check if 100baseTx link state is okay */ + if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180)) + dev->if_port = 3; + } + + /* now record the duplex that was negotiated */ + tp->full_duplex = 0; + if ((dev->if_port == 4) || (dev->if_port == 5)) + tp->full_duplex = 1; + + if (tulip_debug > 1) { + if (tp->nwayset) + printk(KERN_INFO "%s: Switching to %s based on link " + "negotiation %4.4x & %4.4x = %4.4x.\n", + dev->name, medianame[dev->if_port], + tp->sym_advertise, tp->lpar, negotiated); + } + + /* remember to turn off bit 7 - autonegotiate + * enable so we can properly end nway mode and + * set duplex (ie. use csr6<9> again) + */ + csr14 = (inl(ioaddr + CSR14) & 0xffffff7f); + outl(csr14,ioaddr + CSR14); + + + /* now set the data port and operating mode + * (see the Data Port Selection comments at + * the top of the file + */ + + /* get current csr6 and mask off bits not to touch */ + /* see comment at top of file */ + + tp->csr6 = (inl(ioaddr + CSR6) & 0xfe3bd1fd); + + /* so if using if_port 3 or 5 then select the 100baseT + * port else select the 10baseT port. + * See the Data Port Selection table at the top + * of the file which was taken from the PNIC_II.PDF + * datasheet + */ + if (dev->if_port & 1) tp->csr6 |= 0x01840000; + else tp->csr6 |= 0x00400000; + + /* now set the full duplex bit appropriately */ + if (tp->full_duplex) tp->csr6 |= 0x00000200; + + outl(1, ioaddr + CSR13); + + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 " + "%8.8x.\n", dev->name, tp->csr6, + inl(ioaddr + CSR6), inl(ioaddr + CSR12)); + + /* now the following actually writes out the + * new csr6 values + */ + tulip_start_rxtx(tp); + + return; + + } else { + printk(KERN_INFO "%s: Autonegotiation failed, " + "using %s, link beat status %4.4x.\n", + dev->name, medianame[dev->if_port], csr12); + + /* remember to turn off bit 7 - autonegotiate + * enable so we don't forget + */ + csr14 = (inl(ioaddr + CSR14) & 0xffffff7f); + outl(csr14,ioaddr + CSR14); + + /* what should we do when autonegotiate fails? + * should we try again or default to baseline + * case. I just don't know. + * + * for now default to some baseline case + */ + + dev->if_port = 0; + tp->nway = 0; + tp->nwayset = 1; + + /* set to 10baseTx-HD - see Data Port Selection + * comment given at the top of the file + */ + tp->csr6 = (inl(ioaddr + CSR6) & 0xfe3bd1fd); + tp->csr6 |= 0x00400000; + + tulip_restart_rxtx(tp); + + return; + + } + } + + if ((tp->nwayset && (csr5 & 0x08000000) + && (dev->if_port == 3 || dev->if_port == 5) + && (csr12 & 2) == 2) || (tp->nway && (csr5 & (TPLnkFail)))) { + + /* Link blew? Maybe restart NWay. */ + + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Ugh! Link blew?\n", dev->name); + + del_timer_sync(&tp->timer); + pnic2_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + + return; + } + + + if (dev->if_port == 3 || dev->if_port == 5) { + + /* we are at 100mb and a potential link change occurred */ + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); + + /* check 100 link beat */ + + tp->nway = 0; + tp->nwayset = 1; + + /* if failed then try doing an nway to get in sync */ + if ((csr12 & 2) && ! tp->medialock) { + del_timer_sync(&tp->timer); + pnic2_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + + return; + } + + if (dev->if_port == 0 || dev->if_port == 4) { + + /* we are at 10mb and a potential link change occurred */ + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 4) ? "failed" : "good"); + + + tp->nway = 0; + tp->nwayset = 1; + + /* if failed, try doing an nway to get in sync */ + if ((csr12 & 4) && ! tp->medialock) { + del_timer_sync(&tp->timer); + pnic2_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + + return; + } + + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC2 Link Change Default?\n",dev->name); + + /* if all else fails default to trying 10baseT-HD */ + dev->if_port = 0; + + /* make sure autonegotiate enable is off */ + csr14 = (inl(ioaddr + CSR14) & 0xffffff7f); + outl(csr14,ioaddr + CSR14); + + /* set to 10baseTx-HD - see Data Port Selection + * comment given at the top of the file + */ + tp->csr6 = (inl(ioaddr + CSR6) & 0xfe3bd1fd); + tp->csr6 |= 0x00400000; + + tulip_restart_rxtx(tp); +} + diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 1ae8d543f393..2171eb9dc8f8 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -118,7 +118,7 @@ enum tulip_offsets { }; /* register offset and bits for CFDD PCI config reg */ -enum pci_cfg_driver_reg { +enum pci_cfg_driver_reg { CFDD = 0x40, CFDD_Sleep = (1 << 31), CFDD_Snooze = (1 << 30), @@ -405,6 +405,12 @@ extern u16 t21142_csr14[]; void t21142_timer(unsigned long data); void t21142_start_nway(struct net_device *dev); void t21142_lnk_change(struct net_device *dev, int csr5); + + +/* PNIC2.c */ +void pnic2_lnk_change(struct net_device *dev, int csr5); +void pnic2_timer(unsigned long data); +void pnic2_start_nway(struct net_device *dev); void pnic2_lnk_change(struct net_device *dev, int csr5); /* eeprom.c */ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 92ecf91b31f2..46e8a6332d46 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -15,8 +15,8 @@ */ #define DRV_NAME "tulip" -#define DRV_VERSION "0.9.15-pre8" -#define DRV_RELDATE "Oct 11, 2001" +#define DRV_VERSION "0.9.15-pre9" +#define DRV_RELDATE "Nov 6, 2001" #include #include @@ -30,6 +30,10 @@ #include #include +#ifdef __sparc__ +#include +#endif + static char version[] __devinitdata = "Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n"; @@ -165,7 +169,7 @@ struct tulip_chip_table tulip_tbl[] = { /* PNIC2 */ { "Lite-On PNIC-II", 256, 0x0801fbff, - HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, t21142_timer }, + HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer }, /* COMET */ { "ADMtek Comet", 256, 0x0001abef, @@ -261,7 +265,7 @@ static void tulip_set_power_state (struct tulip_private *tp, if (tmp != newtmp) pci_write_config_dword (tp->pdev, CFDD, newtmp); } - + } @@ -297,14 +301,6 @@ static void tulip_up(struct net_device *dev) tp->cur_rx = tp->cur_tx = 0; tp->dirty_rx = tp->dirty_tx = 0; - if (tp->chip_id == PNIC2) { - u32 addr_high = (dev->dev_addr[1]<<8) + (dev->dev_addr[0]<<0); - /* This address setting does not appear to impact chip operation?? */ - outl((dev->dev_addr[5]<<8) + dev->dev_addr[4] + - (dev->dev_addr[3]<<24) + (dev->dev_addr[2]<<16), - ioaddr + 0xB0); - outl(addr_high + (addr_high<<16), ioaddr + 0xB8); - } if (tp->flags & MC_HASH_ONLY) { u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); @@ -420,7 +416,12 @@ media_picked: } else t21142_start_nway(dev); } else if (tp->chip_id == PNIC2) { - t21142_start_nway(dev); + /* for initial startup advertise 10/100 Full and Half */ + tp->sym_advertise = 0x01E0; + /* enable autonegotiate end interrupt */ + outl(inl(ioaddr+CSR5)| 0x00008010, ioaddr + CSR5); + outl(inl(ioaddr+CSR7)| 0x00008010, ioaddr + CSR7); + pnic2_start_nway(dev); } else if (tp->chip_id == LC82C168 && ! tp->medialock) { if (tp->mii_cnt) { dev->if_port = 11; @@ -901,7 +902,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { struct tulip_private *np = dev->priv; u32 ethcmd; - + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; @@ -917,7 +918,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) } } - + return -EOPNOTSUPP; } @@ -971,7 +972,7 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) case 4: /* Advertised value, bogus 10baseTx-FD value from CSR6. */ data->val_out = - ((inl(ioaddr + CSR6) >> 3) & 0x0040) + + ((inl(ioaddr + CSR6) >> 3) & 0x0040) + ((csr14 >> 1) & 0x20) + 1; if (tp->chip_id != DC21041) data->val_out |= ((csr14 >> 9) & 0x03C0); @@ -1007,8 +1008,13 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) if (data->phy_id == 32 && (tp->flags & HAS_NWAY)) { u16 value = data->val_in; if (regnum == 0) { - if ((value & 0x1200) == 0x1200) - t21142_start_nway (dev); + if ((value & 0x1200) == 0x1200) { + if (tp->chip_id == PNIC2) { + pnic2_start_nway (dev); + } else { + t21142_start_nway (dev); + } + } } else if (regnum == 4) tp->sym_advertise = value; } else { @@ -1257,7 +1263,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, u8 cache; u16 pci_command, new_command; u32 csr0; - + if (tulip_debug > 3) printk(KERN_DEBUG "%s: tulip_mwi_config()\n", pdev->slot_name); @@ -1283,7 +1289,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, /* if we have any cache line size at all, we can do MRM */ csr0 |= MRM; - + /* ...and barring hardware bugs, MWI */ if (!(tp->chip_id == DC21143 && tp->revision == 65)) csr0 |= MWI; @@ -1321,7 +1327,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, tp->csr0 = csr0; goto out; - + early_out: if (csr0 & MWI) { pci_command &= ~PCI_COMMAND_INVALIDATE; @@ -1369,16 +1375,16 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, * Lan media wire a tulip chip to a wan interface. Needs a very * different driver (lmc driver) */ - + if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) { printk (KERN_ERR PFX "skipping LMC card.\n"); return -ENODEV; } - + /* * Early DM9100's need software CRC and the DMFE driver */ - + if (pdev->vendor == 0x1282 && pdev->device == 0x9100) { u32 dev_rev; @@ -1390,17 +1396,17 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, return -ENODEV; } } - + /* - * Looks for early PCI chipsets where people report hangs + * Looks for early PCI chipsets where people report hangs * without the workarounds being on. */ - - /* Intel Saturn. Switch to 8 long words burst, 8 long word cache aligned + + /* Intel Saturn. Switch to 8 long words burst, 8 long word cache aligned Aries might need this too. The Saturn errata are not pretty reading but thankfully its an old 486 chipset. */ - + if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL)) { csr0 = MRL | MRM | (8 << BurstLenShift) | (1 << CALShift); force_csr0 = 1; @@ -1410,25 +1416,31 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, csr0 = MRL | MRM | (8 << BurstLenShift) | (1 << CALShift); force_csr0 = 1; } - + /* bugfix: the ASIX must have a burst limit or horrible things happen. */ if (chip_idx == AX88140) { if ((csr0 & 0x3f00) == 0) csr0 |= 0x2000; } - + /* PNIC doesn't have MWI/MRL/MRM... */ if (chip_idx == LC82C168) csr0 &= ~0xfff10000; /* zero reserved bits 31:20, 16 */ - /* DM9102A has troubles with MRM, clear bit 24 too. */ + /* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */ if (pdev->vendor == 0x1282 && pdev->device == 0x9102) - csr0 &= ~0x01200000; + csr0 &= ~0x01f100ff; + +#if defined(__sparc__) + /* DM9102A needs 32-dword alignment/burst length on sparc - chip bug? */ + if (pdev->vendor == 0x1282 && pdev->device == 0x9102) + csr0 = (csr0 & ~0xff00) | 0xe000; +#endif /* * And back to business */ - + i = pci_enable_device(pdev); if (i) { printk (KERN_ERR PFX @@ -1575,6 +1587,22 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, sa_offset = 2; /* Grrr, damn Matrox boards. */ multiport_cnt = 4; } +#ifdef CONFIG_DDB5476 + if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 6)) { + /* DDB5476 MAC address in first EEPROM locations. */ + sa_offset = 0; + /* No media table either */ + tp->flags &= ~HAS_MEDIA_TABLE; + } +#endif +#ifdef CONFIG_DDB5477 + if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 4)) { + /* DDB5477 MAC address in first EEPROM locations. */ + sa_offset = 0; + /* No media table either */ + tp->flags &= ~HAS_MEDIA_TABLE; + } +#endif for (i = 0; i < 6; i ++) { dev->dev_addr[i] = ee_data[i + sa_offset]; sum += ee_data[i + sa_offset]; @@ -1590,14 +1618,26 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, } /* On the Zynx 315 Etherarray and other multiport boards only the first Tulip has an EEPROM. + On Sparc systems the mac address is held in the OBP property + "local-mac-address". The addresses of the subsequent ports are derived from the first. Many PCI BIOSes also incorrectly report the IRQ line, so we correct that here as well. */ if (sum == 0 || sum == 6*0xff) { +#if defined(__sparc__) + struct pcidev_cookie *pcp = pdev->sysdata; +#endif eeprom_missing = 1; for (i = 0; i < 5; i++) dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; +#if defined(__sparc__) + if ((pcp != NULL) && prom_getproplen(pcp->prom_node, + "local-mac-address") == 6) { + prom_getproperty(pcp->prom_node, "local-mac-address", + dev->dev_addr, 6); + } +#endif #if defined(__i386__) /* Patch up x86 BIOS bug. */ if (last_irq) irq = last_irq; @@ -1690,10 +1730,10 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]); printk(", IRQ %d.\n", irq); - if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041) - tp->link_change = t21142_lnk_change; - else if (tp->chip_id == PNIC2) + if (tp->chip_id == PNIC2) tp->link_change = pnic2_lnk_change; + else if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041) + tp->link_change = t21142_lnk_change; else if (tp->flags & HAS_PNICNWAY) tp->link_change = pnic_lnk_change; @@ -1719,7 +1759,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); break; case DC21142: - case PNIC2: if (tp->mii_cnt || tulip_media_cap[dev->if_port] & MediaIsMII) { outl(csr6_mask_defstate, ioaddr + CSR6); outl(0x0000, ioaddr + CSR13); @@ -1728,6 +1767,11 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, } else t21142_start_nway(dev); break; + case PNIC2: + /* just do a reset for sanity sake */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + break; case LC82C168: if ( ! tp->mii_cnt) { tp->nway = 1; diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 0fd4f56889e3..2e753ad174a4 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -73,6 +73,9 @@ - David Woodhouse: Set dev->base_addr before the first time we call wait_for_reset(). It's a lot happier that way. Free np->tx_bufs only if we actually allocated it. + + LK1.1.12: + - Martin Eriksson: Allow Memory-Mapped IO to be enabled. */ @@ -155,7 +158,7 @@ static const int multicast_filter_limit = 32; /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = -KERN_INFO "via-rhine.c:v1.10-LK1.1.11 20/08/2001 Written by Donald Becker\n" +KERN_INFO "via-rhine.c:v1.10-LK1.1.12 03/11/2001 Written by Donald Becker\n" KERN_INFO " http://www.scyld.com/network/via-rhine.html\n"; static char shortname[] __devinitdata = "via-rhine"; @@ -163,9 +166,8 @@ static char shortname[] __devinitdata = "via-rhine"; /* This driver was written to use PCI memory space, however most versions of the Rhine only work correctly with I/O space accesses. */ -#if defined(VIA_USE_MEMORY) -#warning Many adapters using the VIA Rhine chip are not configured to work -#warning with PCI memory space accesses. +#ifdef CONFIG_VIA_RHINE_MMIO +#define USE_MEM #else #define USE_IO #undef readb @@ -318,12 +320,10 @@ enum chip_capability_flags { CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4, ReqTxAlign=0x10, HasWOL=0x20, }; -#if defined(VIA_USE_MEMORY) +#ifdef USE_MEM #define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1) -#define RHINEII_IOSIZE 4096 #else #define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0) -#define RHINEII_IOSIZE 256 #endif /* directly indexed by enum via_rhine_chips, above */ @@ -331,7 +331,7 @@ static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = { { "VIA VT86C100A Rhine", RHINE_IOTYPE, 128, CanHaveMII | ReqTxAlign }, - { "VIA VT6102 Rhine-II", RHINE_IOTYPE, RHINEII_IOSIZE, + { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII | ReqTxAlign } @@ -355,10 +355,19 @@ enum register_offsets { RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74, - Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E, + ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, + RxMissed=0x7C, RxCRCErrs=0x7E, StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC, }; +#ifdef USE_MEM +/* Registers we check that mmio and reg are the same. */ +int mmio_verify_registers[] = { + RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD, + 0 +}; +#endif + /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, @@ -505,6 +514,31 @@ static void wait_for_reset(struct net_device *dev, char *name) name, 5*i); } +#ifdef USE_MEM +static void __devinit enable_mmio(long ioaddr, int chip_id) +{ + int n; + if (chip_id == VT3043 || chip_id == VT86C100A) { + /* More recent docs say that this bit is reserved ... */ + n = inb(ioaddr + ConfigA) | 0x20; + outb(n, ioaddr + ConfigA); + } else if (chip_id == VT6102) { + n = inb(ioaddr + ConfigD) | 0x80; + outb(n, ioaddr + ConfigD); + } +} +#endif + +static void __devinit reload_eeprom(long ioaddr) +{ + int i; + outb(0x20, ioaddr + MACRegEEcsr); + /* Typically 2 cycles to reload. */ + for (i = 0; i < 150; i++) + if (! (inb(ioaddr + MACRegEEcsr) & 0x20)) + break; +} + static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -514,8 +548,12 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, int chip_id = (int) ent->driver_data; static int card_idx = -1; long ioaddr; + long memaddr; int io_size; int pci_flags; +#ifdef USE_MEM + long ioaddr0; +#endif /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -545,8 +583,9 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, goto err_out; } - ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1); - + ioaddr = pci_resource_start (pdev, 0); + memaddr = pci_resource_start (pdev, 1); + if (pci_flags & PCI_USES_MASTER) pci_set_master (pdev); @@ -560,14 +599,29 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, if (pci_request_regions(pdev, shortname)) goto err_out_free_netdev; -#ifndef USE_IO - ioaddr = (long) ioremap (ioaddr, io_size); +#ifdef USE_MEM + ioaddr0 = ioaddr; + enable_mmio(ioaddr0, chip_id); + + ioaddr = (long) ioremap (memaddr, io_size); if (!ioaddr) { - printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n", - pdev->slot_name, io_size, - pci_resource_start (pdev, 1)); + printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%lX\n", + pdev->slot_name, io_size, memaddr); goto err_out_free_res; } + + /* Check that selected MMIO registers match the PIO ones */ + i = 0; + while (mmio_verify_registers[i]) { + int reg = mmio_verify_registers[i++]; + unsigned char a = inb(ioaddr0+reg); + unsigned char b = readb(ioaddr+reg); + if (a != b) { + printk (KERN_ERR "MMIO do not match PIO [%02x] (%02x != %02x)\n", + reg, a, b); + goto err_out_unmap; + } + } #endif /* D-Link provided reset code (with comment additions) */ @@ -595,11 +649,16 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, wait_for_reset(dev, shortname); /* Reload the station address from the EEPROM. */ - writeb(0x20, ioaddr + MACRegEEcsr); - /* Typically 2 cycles to reload. */ - for (i = 0; i < 150; i++) - if (! (readb(ioaddr + MACRegEEcsr) & 0x20)) - break; +#ifdef USE_IO + reload_eeprom(ioaddr); +#else + reload_eeprom(ioaddr0); + /* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO. + If reload_eeprom() was done first this could be avoided, but it is + not known if that still works with the "win98-reboot" problem. */ + enable_mmio(ioaddr0, chip_id); +#endif + for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); @@ -660,7 +719,9 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, goto err_out_unmap; printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, via_rhine_chip_info[chip_id].name, ioaddr); + dev->name, via_rhine_chip_info[chip_id].name, + (pci_flags & PCI_USES_IO) ? ioaddr : memaddr); + for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); @@ -711,7 +772,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, return 0; err_out_unmap: -#ifndef USE_IO +#ifdef USE_MEM iounmap((void *)ioaddr); err_out_free_res: #endif @@ -1587,18 +1648,17 @@ static int via_rhine_close(struct net_device *dev) static void __devexit via_rhine_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct netdev_private *np = dev->priv; unregister_netdev(dev); pci_release_regions(pdev); -#ifndef USE_IO +#ifdef USE_MEM iounmap((char *)(dev->base_addr)); #endif kfree(dev); - + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 4b671e9f196d..e78dfa4ba235 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -672,7 +672,6 @@ static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr) ppriv->root = dev; ppriv->pdev = pdev; spin_lock_init(&ppriv->lock); - pdev->driver_data = ppriv; pci_set_drvdata(pdev, ppriv); return 0; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 23812dcbc2b8..031506a5c2da 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -1746,7 +1746,7 @@ fst_add_one ( struct pci_dev *pdev, const struct pci_device_id *ent ) } /* Record driver data for later use */ - pdev->driver_data = card; + pci_set_drvdata(pdev, card); /* Remainder of card setup */ fst_init_card ( card ); @@ -1785,7 +1785,7 @@ fst_remove_one ( struct pci_dev *pdev ) struct fst_card_info *card; int i; - card = pdev->driver_data; + card = pci_get_drvdata(pdev); for ( i = 0 ; i < card->nports ; i++ ) { diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index abc551f57656..243999874fae 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -4,8 +4,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * (c) Copyright 1998 Building Number Three Ltd - * (c) Copyright 2000 Red Hat Software + * (c) Copyright 1998 Alan Cox + * (c) Copyright 2000, 2001 Red Hat Inc * * Development of this driver was funded by Equiinet Ltd * http://www.equiinet.com @@ -18,6 +18,8 @@ * DMA now uses get_free_page as kmalloc buffers may span a 64K * boundary. * + * Modified for SMP safety and SMP locking by Alan Cox + * * Performance * * Z85230: @@ -53,8 +55,6 @@ #include "z85230.h" -static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; - /** * z8530_read_port - Architecture specific interface function * @p: port to read @@ -116,21 +116,14 @@ static void z8530_tx_done(struct z8530_channel *c); * * Most of the Z8530 registers are indexed off the control registers. * A read is done by writing to the control register and reading the - * register back. We do the locking needed to protect this - * operation. + * register back. The caller must hold the lock */ static inline u8 read_zsreg(struct z8530_channel *c, u8 reg) { - u8 r; - unsigned long flags; - save_flags(flags); - cli(); if(reg) z8530_write_port(c->ctrlio, reg); - r=z8530_read_port(c->ctrlio); - restore_flags(flags); - return r; + return z8530_read_port(c->ctrlio); } /** @@ -154,7 +147,7 @@ static inline u8 read_zsdata(struct z8530_channel *c) * @reg: Register number * @val: Value to write * - * Write a value to an indexed register. Perform the locking needed + * Write a value to an indexed register. The caller must hold the lock * to honour the irritating delay rules. We know about register 0 * being fast to access. */ @@ -162,12 +155,14 @@ static inline u8 read_zsdata(struct z8530_channel *c) static inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) { unsigned long flags; - save_flags(flags); - cli(); + + spin_lock_irqsave(c->lock, flags); + if(reg) z8530_write_port(c->ctrlio, reg); z8530_write_port(c->ctrlio, val); - restore_flags(flags); + + spin_unlock_irqrestore(c->lock, flags); } /** @@ -299,7 +294,7 @@ static void z8530_flush_fifo(struct z8530_channel *c) * @set: 1 to set, 0 to clear * * Sets or clears DTR/RTS on the requested line. All locking is handled - * for the caller. For now we assume all boards use the actual RTS/DTR + * by the caller. For now we assume all boards use the actual RTS/DTR * on the chip. Apparently one or two don't. We'll scream about them * later. */ @@ -333,12 +328,14 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set) * do it yourself but consider medical assistance first. This non DMA * synchronous mode is portable code. The DMA mode assumes PCI like * ISA DMA + * + * Called with the device lock held */ static void z8530_rx(struct z8530_channel *c) { u8 ch,stat; - + while(1) { /* FIFO empty ? */ @@ -382,6 +379,10 @@ static void z8530_rx(struct z8530_channel *c) } else { + /* + * Drop the lock for RX processing, or + * there are deadlocks + */ z8530_rx_done(c); write_zsctrl(c, RES_Rx_CRC); } @@ -407,8 +408,7 @@ static void z8530_rx(struct z8530_channel *c) static void z8530_tx(struct z8530_channel *c) { - while(c->txcount) - { + while(c->txcount) { /* FIFO full ? */ if(!(read_zsreg(c, R0)&4)) break; @@ -424,8 +424,8 @@ static void z8530_tx(struct z8530_channel *c) write_zsctrl(c, RES_EOM_L); write_zsreg(c, R10, c->regs[10]&~ABUNDER); } - return; } + /* * End of frame TX - fire another one @@ -434,7 +434,6 @@ static void z8530_tx(struct z8530_channel *c) write_zsctrl(c, RES_Tx_P); z8530_tx_done(c); -/* write_zsreg(c, R8, *c->tx_ptr++); */ write_zsctrl(c, RES_H_IUS); } @@ -451,8 +450,10 @@ static void z8530_tx(struct z8530_channel *c) static void z8530_status(struct z8530_channel *chan) { - u8 status=read_zsreg(chan, R0); - u8 altered=chan->status^status; + u8 status, altered; + + status=read_zsreg(chan, R0); + altered=chan->status^status; chan->status=status; @@ -512,11 +513,12 @@ static void z8530_dma_rx(struct z8530_channel *chan) { /* Special condition check only */ u8 status; - + read_zsreg(chan, R7); read_zsreg(chan, R6); status=read_zsreg(chan, R1); + if(status&END_FR) { z8530_rx_done(chan); /* Fire up the next one */ @@ -565,16 +567,20 @@ static void z8530_dma_tx(struct z8530_channel *chan) static void z8530_dma_status(struct z8530_channel *chan) { - unsigned long flags; - u8 status=read_zsreg(chan, R0); - u8 altered=chan->status^status; + u8 status, altered; + + status=read_zsreg(chan, R0); + altered=chan->status^status; chan->status=status; + if(chan->dma_tx) { if(status&TxEOM) { + unsigned long flags; + flags=claim_dma_lock(); disable_dma(chan->txdma); clear_dma_ff(chan->txdma); @@ -706,6 +712,10 @@ EXPORT_SYMBOL(z8530_nop); * the channel specific call backs for each channel that has events. * We have to use callback functions because the two channels can be * in different modes. + * + * Locking is done for the handlers. Note that locking is done + * at the chip level (the 5uS delay issue is per chip not per + * channel). c->lock for both channels points to dev->lock */ void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -714,6 +724,7 @@ void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) u8 intr; static volatile int locker=0; int work=0; + struct z8530_irqhandler *irqs=dev->chanA.irqs; if(locker) { @@ -721,11 +732,12 @@ void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) return; } locker=1; - + + spin_lock(&dev->lock); + while(++work<5000) { - struct z8530_irqhandler *irqs=dev->chanA.irqs; - + intr = read_zsreg(&dev->chanA, R3); if(!(intr & (CHARxIP|CHATxIP|CHAEXT|CHBRxIP|CHBTxIP|CHBEXT))) break; @@ -758,6 +770,7 @@ void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) irqs->status(&dev->chanB); } } + spin_unlock(&dev->lock); if(work==5000) printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr); /* Ok all done */ @@ -786,12 +799,17 @@ static char reg_init[16]= int z8530_sync_open(struct net_device *dev, struct z8530_channel *c) { + unsigned long flags; + + spin_lock_irqsave(c->lock, flags); + c->sync = 1; c->mtu = dev->mtu+64; c->count = 0; c->skb = NULL; c->skb2 = NULL; c->irqs = &z8530_sync; + /* This loads the double buffer up */ z8530_rx_done(c); /* Load the frame ring */ z8530_rx_done(c); /* Load the backup frame */ @@ -800,6 +818,8 @@ int z8530_sync_open(struct net_device *dev, struct z8530_channel *c) c->regs[R1]|=TxINT_ENAB; write_zsreg(c, R1, c->regs[R1]); write_zsreg(c, R3, c->regs[R3]|RxENABLE); + + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -818,7 +838,9 @@ EXPORT_SYMBOL(z8530_sync_open); int z8530_sync_close(struct net_device *dev, struct z8530_channel *c) { u8 chk; + unsigned long flags; + spin_lock_irqsave(c->lock, flags); c->irqs = &z8530_nop; c->max = 0; c->sync = 0; @@ -826,6 +848,8 @@ int z8530_sync_close(struct net_device *dev, struct z8530_channel *c) chk=read_zsreg(c,R0); write_zsreg(c, R3, c->regs[R3]); z8530_rtsdtr(c,0); + + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -887,6 +911,8 @@ int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c) /* * Enable DMA control mode */ + + spin_lock_irqsave(c->lock, flags); /* * TX DMA via DIR/REQ @@ -945,6 +971,8 @@ int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c) c->irqs = &z8530_dma_sync; z8530_rtsdtr(c,1); write_zsreg(c, R3, c->regs[R3]|RxENABLE); + + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -986,6 +1014,8 @@ int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c) c->txdma_on = 0; c->tx_dma_used = 0; + spin_lock_irqsave(c->lock, flags); + /* * Disable DMA control mode */ @@ -1011,6 +1041,9 @@ int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c) chk=read_zsreg(c,R0); write_zsreg(c, R3, c->regs[R3]); z8530_rtsdtr(c,0); + + spin_unlock_irqrestore(c->lock, flags); + return 0; } @@ -1037,20 +1070,6 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c) c->skb = NULL; c->skb2 = NULL; - /* - * Load the PIO receive ring - */ - - z8530_rx_done(c); - z8530_rx_done(c); - - /* - * Load the DMA interfaces up - */ - - c->rxdma_on = 0; - c->txdma_on = 0; - /* * Allocate the DMA flip buffers. Limit by page size. * Everyone runs 1500 mtu or less on wan links so this @@ -1066,6 +1085,23 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c) c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE/2; + + spin_lock_irqsave(c->lock, flags); + + /* + * Load the PIO receive ring + */ + + z8530_rx_done(c); + z8530_rx_done(c); + + /* + * Load the DMA interfaces up + */ + + c->rxdma_on = 0; + c->txdma_on = 0; + c->tx_dma_used=0; c->dma_num=0; c->dma_ready=1; @@ -1106,10 +1142,9 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c) c->tx_dma_used = 1; c->irqs = &z8530_txdma_sync; - printk("Loading RX\n"); z8530_rtsdtr(c,1); - printk("Rx interrupts ON\n"); write_zsreg(c, R3, c->regs[R3]|RxENABLE); + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -1129,6 +1164,9 @@ int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c) { unsigned long flags; u8 chk; + + + spin_lock_irqsave(c->lock, flags); c->irqs = &z8530_nop; c->max = 0; @@ -1208,25 +1246,11 @@ void z8530_describe(struct z8530_dev *dev, char *mapping, unsigned long io) EXPORT_SYMBOL(z8530_describe); -/** - * z8530_init - Initialise a Z8530 device - * @dev: Z8530 device to initialise. - * - * Configure up a Z8530/Z85C30 or Z85230 chip. We check the device - * is present, identify the type and then program it to hopefully - * keep quite and behave. This matters a lot, a Z8530 in the wrong - * state will sometimes get into stupid modes generating 10Khz - * interrupt streams and the like. - * - * We set the interrupt handler up to discard any events, in case - * we get them during reset or setp. - * - * Return 0 for success, or a negative value indicating the problem - * in errno form. +/* + * Locked operation part of the z8530 init code */ - -int z8530_init(struct z8530_dev *dev) +static int do_z8530_init(struct z8530_dev *dev) { /* NOP the interrupt handlers first - we might get a floating IRQ transition when we reset the chip */ @@ -1234,6 +1258,12 @@ int z8530_init(struct z8530_dev *dev) dev->chanB.irqs=&z8530_nop; dev->chanA.dcdcheck=DCD; dev->chanB.dcdcheck=DCD; + + /* Set up the chip level lock */ + spin_lock_init(&dev->lock); + dev->chanA.lock = &dev->lock; + dev->chanB.lock = &dev->lock; + /* Reset the chip */ write_zsreg(&dev->chanA, R9, 0xC0); udelay(200); @@ -1287,6 +1317,40 @@ int z8530_init(struct z8530_dev *dev) return 0; } +/** + * z8530_init - Initialise a Z8530 device + * @dev: Z8530 device to initialise. + * + * Configure up a Z8530/Z85C30 or Z85230 chip. We check the device + * is present, identify the type and then program it to hopefully + * keep quite and behave. This matters a lot, a Z8530 in the wrong + * state will sometimes get into stupid modes generating 10Khz + * interrupt streams and the like. + * + * We set the interrupt handler up to discard any events, in case + * we get them during reset or setp. + * + * Return 0 for success, or a negative value indicating the problem + * in errno form. + */ + +int z8530_init(struct z8530_dev *dev) +{ + unsigned long flags; + int ret; + + /* Set up the chip level lock */ + spin_lock_init(&dev->lock); + dev->chanA.lock = &dev->lock; + dev->chanB.lock = &dev->lock; + + spin_lock_irqsave(&dev->lock, flags); + ret = do_z8530_init(dev); + spin_unlock_irqrestore(&dev->lock, flags); + + return ret; +} + EXPORT_SYMBOL(z8530_init); @@ -1297,15 +1361,22 @@ EXPORT_SYMBOL(z8530_init); * We set the interrupt handlers to silence any interrupts. We then * reset the chip and wait 100uS to be sure the reset completed. Just * in case the caller then tries to do stuff. + * + * This is called without the lock held */ int z8530_shutdown(struct z8530_dev *dev) { + unsigned long flags; /* Reset the chip */ + + spin_lock_irqsave(&dev->lock, flags); dev->chanA.irqs=&z8530_nop; dev->chanB.irqs=&z8530_nop; write_zsreg(&dev->chanA, R9, 0xC0); + /* We must lock the udelay, the chip is offlimits here */ udelay(100); + spin_unlock_irqrestore(&dev->lock, flags); return 0; } @@ -1324,6 +1395,10 @@ EXPORT_SYMBOL(z8530_shutdown); int z8530_channel_load(struct z8530_channel *c, u8 *rtable) { + unsigned long flags; + + spin_lock_irqsave(c->lock, flags); + while(*rtable!=255) { int reg=*rtable++; @@ -1344,6 +1419,8 @@ int z8530_channel_load(struct z8530_channel *c, u8 *rtable) c->status=read_zsreg(c, R0); c->sync=1; write_zsreg(c, R3, c->regs[R3]|RxENABLE); + + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -1360,6 +1437,8 @@ EXPORT_SYMBOL(z8530_channel_load); * * Note: We are handling this code path in the interrupt path, keep it * fast or bad things will happen. + * + * Called with the lock held. */ static void z8530_tx_begin(struct z8530_channel *c) @@ -1430,8 +1509,7 @@ static void z8530_tx_begin(struct z8530_channel *c) } else { - save_flags(flags); - cli(); + /* ABUNDER off */ write_zsreg(c, R10, c->regs[10]); write_zsctrl(c, RES_Tx_CRC); @@ -1442,7 +1520,7 @@ static void z8530_tx_begin(struct z8530_channel *c) write_zsreg(c, R8, *c->tx_ptr++); c->txcount--; } - restore_flags(flags); + } } } @@ -1454,25 +1532,22 @@ static void z8530_tx_begin(struct z8530_channel *c) * This is called when we complete a packet send. We wake the queue, * start the next packet going and then free the buffer of the existing * packet. This code is fairly timing sensitive. + * + * Called with the register lock held. */ static void z8530_tx_done(struct z8530_channel *c) { - unsigned long flags; struct sk_buff *skb; - spin_lock_irqsave(&z8530_buffer_lock, flags); netif_wake_queue(c->netdevice); /* Actually this can happen.*/ if(c->tx_skb==NULL) - { - spin_unlock_irqrestore(&z8530_buffer_lock, flags); return; - } + skb=c->tx_skb; c->tx_skb=NULL; z8530_tx_begin(c); - spin_unlock_irqrestore(&z8530_buffer_lock, flags); c->stats.tx_packets++; c->stats.tx_bytes+=skb->len; dev_kfree_skb_irq(skb); @@ -1489,7 +1564,7 @@ static void z8530_tx_done(struct z8530_channel *c) void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb) { - kfree_skb(skb); + dev_kfree_skb_any(skb); } EXPORT_SYMBOL(z8530_null_rx); @@ -1503,6 +1578,8 @@ EXPORT_SYMBOL(z8530_null_rx); * ESCC mode, but on the older chips we have no choice. We flip to the * new buffer immediately in DMA mode so that the DMA of the next * frame can occur while we are copying the previous buffer to an sk_buff + * + * Called with the lock held */ static void z8530_rx_done(struct z8530_channel *c) @@ -1673,6 +1750,9 @@ static inline int spans_boundary(struct sk_buff *skb) * hard to hit interrupt latencies for the Z85230 per packet * even in DMA mode we do the flip to DMA buffer if needed here * not in the IRQ. + * + * Called from the network code. The lock is not held at this + * point. */ int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) @@ -1711,9 +1791,9 @@ int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) c->tx_next_skb=skb; RT_UNLOCK; - spin_lock_irqsave(&z8530_buffer_lock, flags); + spin_lock_irqsave(c->lock, flags); z8530_tx_begin(c); - spin_unlock_irqrestore(&z8530_buffer_lock, flags); + spin_unlock_irqrestore(c->lock, flags); netif_wake_queue(c->netdevice); return 0; @@ -1727,6 +1807,9 @@ EXPORT_SYMBOL(z8530_queue_xmit); * * Get the statistics block. We keep the statistics in software as * the chip doesn't do it for us. + * + * Locking is ignored here - we could lock for a copy but its + * not likely to be that big an issue */ struct net_device_stats *z8530_get_stats(struct z8530_channel *c) diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h index a92c56316385..070eff77c134 100644 --- a/drivers/net/wan/z85230.h +++ b/drivers/net/wan/z85230.h @@ -368,6 +368,8 @@ struct z8530_channel unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ + + spinlock_t *lock; /* Devicr lock */ }; /* @@ -386,6 +388,7 @@ struct z8530_dev int irq; /* Interrupt for the device */ int active; /* Soft interrupt enable - the Mac doesn't always have a hard disable on its 8530s... */ + spinlock_t lock; }; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 1b1a4d47e70b..458cb73a1ce0 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3214,17 +3214,19 @@ static void del_airo_dev( struct net_device *dev ) { static int __devinit airo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pent) { - pdev->driver_data = init_airo_card(pdev->irq, - pdev->resource[2].start, 0); - if (!pdev->driver_data) { + struct net_device *dev; + + dev = init_airo_card(pdev->irq, pdev->resource[2].start, 0); + if (!dev) return -ENODEV; - } + + pci_set_drvdata(pdev, dev); return 0; } static void __devexit airo_pci_remove(struct pci_dev *pdev) { - stop_airo_card(pdev->driver_data, 1); + stop_airo_card(pci_get_drvdata(pdev), 1); } #endif diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog index f5badc8f9980..c6fb2633b590 100644 --- a/drivers/parport/ChangeLog +++ b/drivers/parport/ChangeLog @@ -1,3 +1,8 @@ +2001-11-01 Damian Gruszka + + * parport_serial.c (serial_register): Set base_baud before + calling register_serial. + 2001-10-26 Tim Waugh * parport_pc.c (parport_irq_probe): When ECR programmable IRQ diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 8b156f210619..6eb80f07f2ef 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -217,6 +217,7 @@ static int __devinit serial_register (struct pci_dev *dev, if (get_pci_port (dev, board, &serial_req, k)) break; serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; + serial_req.baud_base = base_baud; line = register_serial (&serial_req); if (line < 0) { printk (KERN_DEBUG diff --git a/drivers/pci/names.c b/drivers/pci/names.c index e84d16ee07bc..5ae80f8a6cf8 100644 --- a/drivers/pci/names.c +++ b/drivers/pci/names.c @@ -52,7 +52,7 @@ static struct pci_vendor_info __initdata pci_vendor_list[] = { #define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info)) -void __init pci_name_device(struct pci_dev *dev) +void __devinit pci_name_device(struct pci_dev *dev) { const struct pci_vendor_info *vendor_p = pci_vendor_list; int i = VENDORS; diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index fb78a472d071..c73f0bd65bb3 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -540,6 +540,11 @@ 7411 AMD-765 [Viper] IDE 7413 AMD-765 [Viper] ACPI 7414 AMD-765 [Viper] USB + 7440 AMD-768 [??] ISA + 7441 AMD-768 [??] IDE + 7443 AMD-768 [??] ACPI + 7448 AMD-768 [??] PCI + 7449 AMD-768 [??] USB 1023 Trident Microsystems 0194 82C194 2000 4DWave DX @@ -1094,6 +1099,8 @@ 4d33 20246 4d38 20262 4d68 20268 + 6268 20268R + 4d69 20269 5300 DC5300 105b Foxconn International, Inc. 105c Wipro Infotech Limited @@ -1370,6 +1377,7 @@ 0650 PBC0650A 0670 USB0670 0673 USB0673 + 0680 PCI0680 1096 Alacron 1097 Appian Technology 1098 Quantum Designs (H.K.) Ltd diff --git a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in index 6f43eabd2249..6556020c1231 100644 --- a/drivers/pcmcia/Config.in +++ b/drivers/pcmcia/Config.in @@ -17,7 +17,7 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then if [ "$CONFIG_PCI" != "n" ]; then bool ' CardBus support' CONFIG_CARDBUS fi - bool ' i82092 compatible bridge support' CONFIG_I82092 + dep_bool ' i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI bool ' i82365 compatible bridge support' CONFIG_I82365 bool ' Databook TCIC host bridge support' CONFIG_TCIC if [ "$CONFIG_HD64465" = "y" ]; then diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index 5719277c8de4..a28cf4d029c4 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -795,7 +795,7 @@ static int i82092aa_get_mem_map(unsigned sock, struct pccard_mem_map *mem) mem->card_start = ( (unsigned long)(i & 0x3fff)<12) + mem->sys_start; mem->card_start &= 0x3ffffff; - printk("Card %i is from %x to %x \n",sock,mem->sys_start,mem->sys_stop); + printk("Card %i is from %lx to %lx \n",sock,mem->sys_start,mem->sys_stop); leave("i82092aa_get_mem_map"); return 0; @@ -819,7 +819,7 @@ static int i82092aa_set_mem_map(unsigned sock, struct pccard_mem_map *mem) if ( (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) || (mem->speed > 1000) ) { leave("i82092aa_set_mem_map: invalid address / speed"); - printk("invalid mem map for socket %i : %x to %x with a start of %x \n",sock,mem->sys_start, mem->sys_stop, mem->card_start); + printk("invalid mem map for socket %i : %lx to %lx with a start of %x \n",sock,mem->sys_start, mem->sys_stop, mem->card_start); return -EINVAL; } @@ -895,7 +895,6 @@ static int i82092aa_module_init(void) static void i82092aa_module_exit(void) { - int i; enter("i82092aa_module_exit"); pci_unregister_driver(&i82092aa_pci_drv); unregister_ss_entry(&i82092aa_operations); diff --git a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c index 1531f260b8c2..7c6615a64160 100644 --- a/drivers/pcmcia/pci_socket.c +++ b/drivers/pcmcia/pci_socket.c @@ -177,13 +177,13 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock memset(socket, 0, sizeof(*socket)); socket->dev = dev; socket->op = ops; - dev->driver_data = socket; + pci_set_drvdata(dev, socket); spin_lock_init(&socket->event_lock); err = socket->op->open(socket); if(err) { socket->dev = NULL; - dev->driver_data = NULL; + pci_set_drvdata(dev, NULL); } return err; } @@ -210,24 +210,24 @@ cardbus_probe (struct pci_dev *dev, const struct pci_device_id *id) static void __devexit cardbus_remove (struct pci_dev *dev) { - pci_socket_t *socket = (pci_socket_t *) dev->driver_data; + pci_socket_t *socket = pci_get_drvdata(dev); pcmcia_unregister_socket (socket->pcmcia_socket); if (socket->op && socket->op->close) socket->op->close(socket); - dev->driver_data = 0; + pci_set_drvdata(dev, NULL); } static int cardbus_suspend (struct pci_dev *dev, u32 state) { - pci_socket_t *socket = (pci_socket_t *) dev->driver_data; + pci_socket_t *socket = pci_get_drvdata(dev); pcmcia_suspend_socket (socket->pcmcia_socket); return 0; } static int cardbus_resume (struct pci_dev *dev) { - pci_socket_t *socket = (pci_socket_t *) dev->driver_data; + pci_socket_t *socket = pci_get_drvdata(dev); pcmcia_resume_socket (socket->pcmcia_socket); return 0; } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4af2079ce569..82131bcd6e86 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -117,6 +117,8 @@ EXPORT_SYMBOL (dasd_set_normalized_cda); /* SECTION: Constant definitions to be used within this file */ #define PRINTK_HEADER DASD_NAME":" +#undef DASD_PROFILE /* fill profile information - used for */ + /* statistics and perfomance */ #define DASD_MIN_SIZE_FOR_QUEUE 32 #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE @@ -525,6 +527,8 @@ dasd_strtoul (char *str, char **stra, int* features) val = simple_strtoul (buffer, &buffer, 16); /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */ + *features = DASD_DEFAULT_FEATURES; + if (temp[i]=='(') { while (temp[i]!='\0' && temp[i]!=')'&&temp[i]!='-') { @@ -561,7 +565,7 @@ dasd_parse (char **str) { char *temp; int from, to; - int features = 0; + int features; int rc = 0; if (*str) { @@ -1008,6 +1012,7 @@ dasd_find_disc (dasd_device_t * device, dasd_discipline_t *d) static dasd_profile_info_t dasd_global_profile; +#ifdef DASD_PROFILE /* * macro: dasd_profile_add_counter * increments counter in global and local profiling structures @@ -1032,13 +1037,20 @@ static dasd_profile_info_t dasd_global_profile; void dasd_profile_add (ccw_req_t * cqr) { - long strtime, irqtime, endtime, tottime; + long strtime, irqtime, endtime, tottime; /* in microsecnds*/ long tottimeps, sectors; dasd_device_t *device = cqr->device; if (!cqr->req) /* safeguard against abnormal cqrs */ return; - sectors = ((struct request *) (cqr->req))->nr_sectors; + + if ((!cqr->buildclk) || + (!cqr->startclk) || + (!cqr->stopclk ) || + (!cqr->endclk ) || + (!(sectors = ((struct request *) (cqr->req))->nr_sectors))) + return; + strtime = ((cqr->startclk - cqr->buildclk) >> 12); irqtime = ((cqr->stopclk - cqr->startclk) >> 12); endtime = ((cqr->endclk - cqr->stopclk) >> 12); @@ -1064,7 +1076,7 @@ dasd_profile_add (ccw_req_t * cqr) dasd_profile_add_counter (irqtime / sectors, dasd_io_time2ps, device); dasd_profile_add_counter (endtime, dasd_io_time3, device); } - +#endif /* SECTION: All the gendisk stuff */ @@ -1506,6 +1518,11 @@ static request_queue_t * dasd_get_queue (kdev_t kdev) { dasd_device_t *device = dasd_device_from_kdev (kdev); + + if (!device) { + return NULL; + } + return device->request_queue; } @@ -1544,7 +1561,9 @@ dasd_finalize_request (ccw_req_t * cqr) asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->req) { +#ifdef DASD_PROFILE dasd_profile_add (cqr); +#endif dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE)); /* free request if nobody is waiting on it */ dasd_free_request (cqr, cqr->device); @@ -2294,18 +2313,6 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) rc = put_user(ver, (int *) data); break; } - case BLKGETSIZE:{ /* Return device size */ - unsigned long blocks = major_info->gendisk.sizes - [MINOR (inp->i_rdev)] << 1; - rc = put_user(blocks, (unsigned long *) data); - break; - } - case BLKGETSIZE64:{ - u64 blocks = major_info->gendisk.sizes - [MINOR (inp->i_rdev)]; - rc = put_user(blocks << 10, (u64 *) data); - break; - } case BLKRRPART:{ if (!capable (CAP_SYS_ADMIN)) { rc = -EACCES; @@ -2501,6 +2508,8 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) break; } #endif /* 0 */ + case BLKGETSIZE: + case BLKGETSIZE64: case BLKSSZGET: case BLKROSET: case BLKROGET: @@ -2577,7 +2586,7 @@ dasd_open (struct inode *inp, struct file *filp) } spin_lock_irqsave(&discipline_lock,flags); device = dasd_device_from_kdev (inp->i_rdev); - if (device == NULL ) { + if (!device) { printk (KERN_WARNING PRINTK_HEADER "No device registered as (%d:%d)\n", MAJOR (inp->i_rdev), @@ -2618,7 +2627,7 @@ dasd_release (struct inode *inp, struct file *filp) goto out; } device = dasd_device_from_kdev (inp->i_rdev); - if (device == NULL) { + if (!device) { printk (KERN_WARNING PRINTK_HEADER "No device registered as %d:%d\n", MAJOR (inp->i_rdev), @@ -2638,6 +2647,7 @@ dasd_release (struct inode *inp, struct file *filp) invalidate_buffers (inp->i_rdev); if ( device->discipline->owner ) __MOD_DEC_USE_COUNT(device->discipline->owner); + MOD_DEC_USE_COUNT; } else if ( count == -1 ) { /* paranoia only */ atomic_set (&device->open_count,0); printk (KERN_WARNING PRINTK_HEADER @@ -2661,7 +2671,11 @@ int dasd_fillgeo(int kdev,struct hd_geometry *geo) { dasd_device_t *device = dasd_device_from_kdev (kdev); - if (!device->discipline->fill_geometry) + + if (!device) + return -EINVAL; + + if (!device->discipline->fill_geometry) return -EINVAL; device->discipline->fill_geometry (device, geo); @@ -3094,8 +3108,10 @@ dasd_state_del_to_new (dasd_device_t **addr ) #endif } goto out; +#ifdef CONFIG_ARCH_S390X noidal: free_page ((long) device->lowmem_ccws); +#endif noccw: kfree(device); out: @@ -3308,16 +3324,16 @@ dasd_state_ready_to_accept (dasd_device_t *device ) int rc = 0; unsigned long flags; - if ( device->init_cqr != NULL ) { + s390irq_spin_lock_irqsave (device->devinfo.irq, flags); + if ( device->init_cqr != NULL && atomic_read(&dasd_init_pending) != 0 ) { if ( device->discipline->term_IO == NULL ) BUG(); - s390irq_spin_lock_irqsave (device->devinfo.irq, flags); device->discipline->term_IO (device->init_cqr); - s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags); atomic_dec (&dasd_init_pending); dasd_free_request (device->init_cqr, device); device->init_cqr = NULL; } + s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags); memset(&device->sizes,0,sizeof(dasd_sizes_t)); device->level = DASD_STATE_ACCEPT; return rc; @@ -3632,19 +3648,30 @@ dasd_devices_open (struct inode *inode, struct file *file) for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) { dasd_device_t *device; int devno = dasd_devno_from_devindex(index+i); + int features; + if ( devno == -ENODEV ) continue; + + features = dasd_features_from_devno(devno); + if (features < DASD_DEFAULT_FEATURES) + features = DASD_DEFAULT_FEATURES; + device = temp->dasd_device[i]; if (device) { + len += sprintf (info->data + len, - "%04x(%s) at (%3d:%3d) is %7s:", + "%04x(%s) at (%3d:%3d) is %-7s%4s: ", device->devinfo.devno, device->discipline ? device-> discipline->name : "none", temp->gendisk.major, i << DASD_PARTN_BITS, - device->name); + device->name, + (features & DASD_FEATURE_READONLY) ? + "(ro)" : " "); + switch (device->level) { case DASD_STATE_NEW: len += @@ -3709,10 +3736,12 @@ dasd_devices_open (struct inode *inode, struct file *file) "%04x",devno); } len += sprintf (info->data + len, - "(none) at (%3d:%3d) is %7s: unknown", + "(none) at (%3d:%3d) is %-7s%4s: unknown", temp->gendisk.major, i << DASD_PARTN_BITS, - buffer); + buffer, + (features & DASD_FEATURE_READONLY) ? + "(ro)" : " "); } if ( dasd_probeonly ) len += sprintf(info->data + len,"(probeonly)"); @@ -3753,7 +3782,7 @@ dasd_devices_write (struct file *file, const char *user_buf, int off = 0; char *temp; dasd_range_t range; - int features = 0; + int features; if (buffer == NULL) return -ENOMEM; @@ -3906,7 +3935,7 @@ dasd_statistics_open (struct inode *inode, struct file *file) } len += sprintf (info->data + len, "\n"); - len += sprintf (info->data + len, "Histogram of I/O times\n"); + len += sprintf (info->data + len, "Histogram of I/O times (microseconds)\n"); for (i = 0; i < 16; i++) { len += sprintf (info->data + len, "%7d ", dasd_global_profile.dasd_io_times[i] >> shift); diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 912cd2db5bac..4b1f1b140075 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -55,7 +55,7 @@ log_erp_chain (ccw_req_t *cqr, while (loop_cqr != NULL) { DASD_MESSAGE (KERN_ERR, device, - "(%s) ERP chain report for req: %p\n", + "(%s) ERP chain report for req: %p", caller == 0 ? "EXAMINE" : "ACTION", loop_cqr); @@ -66,7 +66,7 @@ log_erp_chain (ccw_req_t *cqr, DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -80,13 +80,13 @@ log_erp_chain (ccw_req_t *cqr, if (loop_cqr->cplength > 40) { /* log only parts of the CP */ DASD_MESSAGE (KERN_ERR, device, "%s", - "Start of channel program:\n"); + "Start of channel program:"); for (i = 0; i < 20; i += 2) { DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -97,7 +97,7 @@ log_erp_chain (ccw_req_t *cqr, } DASD_MESSAGE (KERN_ERR, device, "%s", - "End of channel program:\n"); + "End of channel program:"); nl = (char *) loop_cqr->cpaddr; nl += ((loop_cqr->cplength - 10) * 8); @@ -106,7 +106,7 @@ log_erp_chain (ccw_req_t *cqr, DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -119,13 +119,13 @@ log_erp_chain (ccw_req_t *cqr, } else { /* log the whole CP */ DASD_MESSAGE (KERN_ERR, device, "%s", - "Channel program (complete):\n"); + "Channel program (complete):"); for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -151,14 +151,14 @@ log_erp_chain (ccw_req_t *cqr, nl -= 10*8; /* start some bytes before */ DASD_MESSAGE (KERN_ERR, device, - "Failed CCW (%p) (area):\n", + "Failed CCW (%p) (area):", (void *)(long)cpa); for (i = 0; i < 20; i += 2) { DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -171,7 +171,7 @@ log_erp_chain (ccw_req_t *cqr, } else { DASD_MESSAGE (KERN_ERR, device, - "Failed CCW (%p) already logged\n", + "Failed CCW (%p) already logged", (void *)(long)cpa); } } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 416597a99b3b..610890d88619 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -631,7 +631,7 @@ dasd_eckd_do_analysis (struct dasd_device_t *device) } } if (device->sizes.bp_block == 0) { - DASD_MESSAGE (KERN_WARNING, device, "%s\n", + DASD_MESSAGE (KERN_WARNING, device, "%s", "Volume has incompatible disk layout"); return -EMEDIUMTYPE; } @@ -746,7 +746,7 @@ dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata) (fdata->start_unit / private->rdc_data.no_cyl) % (private->rdc_data.no_cyl / 20))) { DASD_MESSAGE (KERN_INFO, device, - "Format Cylinder: %d Flags: %d\n", + "Format Cylinder: %d Flags: %d", fdata->start_unit / private->rdc_data.trk_per_cyl, fdata->intensity); } if ((fdata->intensity & ~0x8) & 0x04) { diff --git a/drivers/s390/char/tape34xx.c b/drivers/s390/char/tape34xx.c index b62700a7f795..66efa86cc406 100644 --- a/drivers/s390/char/tape34xx.c +++ b/drivers/s390/char/tape34xx.c @@ -1631,7 +1631,7 @@ tape34xx_bsb_init_done (tape_info_t * ti) tapestate_set (ti, TS_DONE); ti->rc = 0; ti->wanna_wakeup=1; - wake_up_interruptible (&ti->wq); + wake_up (&ti->wq); } void @@ -2050,8 +2050,13 @@ tape34xx_error_recovery (tape_info_t* ti) return; case 0x38: // Physical end of tape. A read/write operation reached the physical end of tape. - if (tapestate_get(ti)==TS_WRI_INIT) { + if (tapestate_get(ti)==TS_WRI_INIT || + tapestate_get(ti)==TS_DSE_INIT || + tapestate_get(ti)==TS_EGA_INIT || + tapestate_get(ti)==TS_WTM_INIT){ tape34xx_error_recovery_has_failed(ti,ENOSPC); + } else { + tape34xx_error_recovery_has_failed(ti,EIO); } return; case 0x39: diff --git a/drivers/s390/char/tapechar.c b/drivers/s390/char/tapechar.c index 0a82699ae76d..0be3c435bf2e 100644 --- a/drivers/s390/char/tapechar.c +++ b/drivers/s390/char/tapechar.c @@ -704,7 +704,7 @@ tape_release (struct inode *inode, struct file *filp) long lockflags; tape_info_t *ti,*lastti; ccw_req_t *cqr = NULL; - int rc; + int rc = 0; ti = first_tape_info; while ((ti != NULL) && (ti->rew_minor != MINOR (inode->i_rdev)) && (ti->nor_minor != MINOR (inode->i_rdev))) @@ -718,13 +718,14 @@ tape_release (struct inode *inode, struct file *filp) lastti->next=ti->next; } kfree(ti); - return 0; + goto out; } if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) { #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:notidle!"); #endif - return -ENXIO; /* error in tape_release */ + rc = -ENXIO; /* error in tape_release */ + goto out; } #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:release:"); @@ -750,8 +751,9 @@ tape_release (struct inode *inode, struct file *filp) s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); tapestate_set (ti, TS_UNUSED); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); +out: #ifdef MODULE MOD_DEC_USE_COUNT; #endif /* MODULE */ - return 0; + return rc; } diff --git a/drivers/s390/misc/chandev.c b/drivers/s390/misc/chandev.c index 86bc96031d3e..e93b1b7232d5 100644 --- a/drivers/s390/misc/chandev.c +++ b/drivers/s390/misc/chandev.c @@ -2428,8 +2428,7 @@ static int chandev_setup(int in_read_conf,char *instr,char *errstr,int lineno) else if(ints[0]==2) ints[3]=ints[2]; chandev_add_parms(ints[1],ints[2],ints[3],currstr); -// currstr=currstr+strlen(currstr)+1; - continue; + goto NextOption; } else goto BadArgs; @@ -2696,6 +2695,7 @@ static int chandev_setup(int in_read_conf,char *instr,char *errstr,int lineno) } else goto BadArgs; + NextOption: if(cnt Modifications By: Joel Jacobson Arnaldo Carvalho de Melo + Brad Strand Copyright (C) 1999-2001 3ware Inc. @@ -100,6 +101,11 @@ Fix possible null pointer dereference in tw_aen_drain_queue() during initialization. Clear pci parity errors during initialization and during io. + 1.02.00.009 - Remove redundant increment in tw_state_request_start(). + Add ioctl support for direct ATA command passthru. + Add entire aen code string list. + 1.02.00.010 - Cleanup queueing code, fix jbod thoughput. + Fix get_param for specific units. */ #include @@ -147,7 +153,7 @@ static struct notifier_block tw_notifier = { }; /* Globals */ -char *tw_driver_version="1.02.00.008"; +char *tw_driver_version="1.02.00.010"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -169,23 +175,18 @@ int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen); /* Print some useful info when certain aen codes come out */ - switch (aen & 0x0ff) { - case TW_AEN_APORT_TIMEOUT: - printk(KERN_WARNING "3w-xxxx: scsi%d: Received drive timeout AEN on port %d, check drive and drive cables.\n", tw_dev->host->host_no, aen >> 8); - break; - case TW_AEN_DRIVE_ERROR: - printk(KERN_WARNING "3w-xxxx: scsi%d: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, aen >> 8); - break; - case TW_AEN_SMART_FAIL: - printk(KERN_WARNING "3w-xxxx: scsi%d: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", tw_dev->host->host_no, aen >> 8); - break; - case TW_AEN_SBUF_FAIL: - printk(KERN_WARNING "3w-xxxx: scsi%d: Received SBUF integrity check failure AEN, reseat card or bad card.\n", tw_dev->host->host_no); - break; - default: - printk(KERN_WARNING "3w-xxxx: Received AEN 0x%x\n", aen); + if (aen == 0x0ff) { + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: AEN queue overflow.\n", tw_dev->host->host_no); + } else { + if ((aen & 0x0ff) < TW_AEN_STRING_MAX) { + if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8); + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]); + } + } else + printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen); } - tw_dev->aen_count++; /* Now queue the code */ @@ -235,7 +236,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev) response_que_addr = tw_dev->registers.response_que_addr; if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count); + dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count); return 1; } @@ -291,7 +292,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev) mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -308,7 +309,8 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev) if (command_packet->status != 0) { if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) { /* Bad response */ - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } else { /* We know this is a 3w-1x00, and doesn't support aen's */ @@ -428,7 +430,7 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -525,11 +527,11 @@ int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, in int tw_check_bits(u32 status_reg_value) { if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) { - printk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value); + dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value); return 1; } if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) { - printk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value); + dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value); return 1; } @@ -633,8 +635,12 @@ void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned case 0x51: printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit); break; + default: + printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit); } break; + default: + printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit); } } /* End tw_decode_error() */ @@ -660,7 +666,7 @@ int tw_empty_response_que(TW_Device_Extension *tw_dev) status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -669,7 +675,7 @@ int tw_empty_response_que(TW_Device_Extension *tw_dev) response_que_value = inl(response_que_addr); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -817,9 +823,20 @@ int tw_findcards(Scsi_Host_Template *tw_host) continue; } - /* Calculate max cmds per lun */ - if (tw_dev->num_units > 0) - tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units; + /* Calculate max cmds per lun, and setup queues */ + if (tw_dev->num_units > 0) { + if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) { + tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-1)/tw_dev->num_units; + tw_dev->free_head = TW_Q_START; + tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1; + tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1; + } else { + tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units; + tw_dev->free_head = TW_Q_START; + tw_dev->free_tail = TW_Q_LENGTH - 1; + tw_dev->free_wrap = TW_Q_LENGTH - 1; + } + } /* Register the card with the kernel SCSI layer */ host = scsi_register(tw_host, sizeof(TW_Device_Extension)); @@ -889,7 +906,7 @@ int tw_findcards(Scsi_Host_Template *tw_host) } if (numcards == 0) - printk(KERN_WARNING "3w-xxxx: tw_findcards(): No cards found.\n"); + printk(KERN_WARNING "3w-xxxx: No cards with valid units found.\n"); else register_reboot_notifier(&tw_notifier); @@ -899,18 +916,19 @@ int tw_findcards(Scsi_Host_Template *tw_host) /* This function will free up device extension resources */ void tw_free_device_extension(TW_Device_Extension *tw_dev) { - int i, imax; - imax = TW_Q_LENGTH; + int i; dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n"); /* Free command packet and generic buffer memory */ - for (i=0;icommand_packet_virtual_address[i]) kfree(tw_dev->command_packet_virtual_address[i]); if (tw_dev->alignment_virtual_address[i]) kfree(tw_dev->alignment_virtual_address[i]); + } + for (i=0;ibounce_buffer[i]) kfree(tw_dev->bounce_buffer[i]); } @@ -922,7 +940,7 @@ static int tw_halt(struct notifier_block *nb, ulong event, void *buf) int i; for (i=0;istatus != 0) { /* bad response */ - printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } break; /* Response was okay, so we exit */ @@ -1043,8 +1062,6 @@ int tw_initialize_device_extension(TW_Device_Extension *tw_dev) tw_dev->num_units = 0; tw_dev->num_aborts = 0; tw_dev->num_resets = 0; - tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_LENGTH - 1; tw_dev->posted_request_count = 0; tw_dev->max_posted_request_count = 0; tw_dev->max_sgl_entries = 0; @@ -1135,7 +1152,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -1149,7 +1166,8 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) } if (command_packet->status != 0) { /* bad response */ - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } found = 1; @@ -1181,7 +1199,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) tw_dev->num_units = num_units; if (num_units == 0) { - printk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n"); return 1; } @@ -1238,7 +1256,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -1252,7 +1270,8 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) } if (command_packet->status != 0) { /* bad response */ - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } found = 1; @@ -1277,10 +1296,10 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) /* Now allocate raid5 bounce buffers */ if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) { - for (i=0;ibounce_buffer[i] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bounce buffer allocation failed.\n"); + printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n"); return 1; } memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_SECTORS); @@ -1342,7 +1361,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n"); + printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); } @@ -1354,7 +1373,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) while (tw_dev->pending_request_count > 0) { request_id = tw_dev->pending_queue[tw_dev->pending_head]; if (tw_dev->state[request_id] != TW_S_PENDING) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found request id that wasn't pending.\n"); + printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no); break; } if (tw_post_command_packet(tw_dev, request_id)==0) { @@ -1382,12 +1401,12 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; error = 0; if (command_packet->status != 0) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit); tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); error = 1; } if (tw_dev->state[request_id] != TW_S_POSTED) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode); + printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode); error = 1; } if (TW_STATUS_ERRORS(status_reg_value)) { @@ -1400,24 +1419,22 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n"); error = tw_aen_complete(tw_dev, request_id); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error completing aen.\n"); + printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no); } status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); } } else { switch (tw_dev->srb[request_id]->cmnd[0]) { case READ_10: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10\n"); case READ_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_6\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n"); break; case WRITE_10: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10\n"); case WRITE_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_6\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n"); break; case INQUIRY: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n"); @@ -1432,7 +1449,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) error = tw_ioctl_complete(tw_dev, request_id); break; default: - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unknown scsi opcode: 0x%x.\n", tw_dev->srb[request_id]->cmnd[0]); + printk(KERN_WARNING "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x.\n", tw_dev->host->host_no, tw_dev->srb[request_id]->cmnd[0]); tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); } @@ -1450,7 +1467,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); } } @@ -1471,6 +1488,7 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id) TW_Command *command_packet; u32 param_value; TW_Ioctl *ioctl = NULL; + TW_Passthru *passthru = NULL; int tw_aen_code; ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; @@ -1519,6 +1537,7 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id) case TW_OP_GET_PARAM: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_GET_PARAM.\n"); command_packet->byte0.opcode = TW_OP_GET_PARAM; + command_packet->byte3.unit = ioctl->unit_index; param->table_id = ioctl->table_id; param->parameter_id = ioctl->parameter_id; param->parameter_size_bytes = ioctl->parameter_size_bytes; @@ -1562,7 +1581,26 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id) tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; - case TW_CMD_PACKET: + case TW_ATA_PASSTHRU: + if (ioctl->data != NULL) { + memcpy(command_packet, ioctl->data, sizeof(TW_Command)); + command_packet->request_id = request_id; + } else { + printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n"); + return 1; + } + + passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id]; + passthru->sg_list[0].length = passthru->sector_count*512; + if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) { + printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length); + return 1; + } + passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]); + tw_post_command_packet(tw_dev, request_id); + return 0; + case TW_CMD_PACKET: + dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET.\n"); if (ioctl->data != NULL) { memcpy(command_packet, ioctl->data, sizeof(TW_Command)); command_packet->request_id = request_id; @@ -1596,7 +1634,6 @@ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id) command_packet->byte0.sgl_offset = 2; command_packet->size = 4; command_packet->request_id = request_id; - command_packet->byte3.unit = 0; command_packet->byte3.host_id = 0; command_packet->status = 0; command_packet->flags = 0; @@ -1614,7 +1651,10 @@ int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id) unsigned char *param_data; unsigned char *buff; TW_Param *param; + TW_Ioctl *ioctl = NULL; + TW_Passthru *passthru = NULL; + ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n"); buff = tw_dev->srb[request_id]->request_buffer; if (buff == NULL) { @@ -1622,16 +1662,23 @@ int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id) return 1; } dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen); - memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - if (param == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n"); - return 1; - } - param_data = &(param->data[0]); - - memcpy(buff, param_data, tw_dev->ioctl_size[request_id]); + ioctl = (TW_Ioctl *)buff; + switch (ioctl->opcode) { + case TW_ATA_PASSTHRU: + passthru = (TW_Passthru *)ioctl->data; + memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512); + break; + default: + memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; + if (param == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Bad alignment virtual address.\n"); + return 1; + } + param_data = &(param->data[0]); + memcpy(buff, param_data, tw_dev->ioctl_size[request_id]); + } return 0; } /* End tw_ioctl_complete() */ @@ -1659,7 +1706,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds) status_reg_value = inl(status_reg_addr); do_gettimeofday(&timeout); if (before.tv_sec + seconds < timeout.tv_sec) { - printk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag); + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag); return 1; } mdelay(1); @@ -1680,7 +1727,7 @@ int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id) status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); } @@ -1724,7 +1771,7 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev) imax = TW_Q_LENGTH; if (tw_reset_sequence(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_reset_device_extension(): Reset sequence failed for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no); return 1; } @@ -1772,14 +1819,14 @@ int tw_reset_sequence(TW_Device_Extension *tw_dev) error = tw_aen_drain_queue(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): No attention interrupt for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no); tries++; continue; } /* Check for controller errors */ if (tw_check_errors(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Controller errors found, soft resetting card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no); tries++; continue; } @@ -1787,7 +1834,7 @@ int tw_reset_sequence(TW_Device_Extension *tw_dev) /* Empty the response queue again */ error = tw_empty_response_que(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Couldn't empty response queue for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Couldn't empty response queue, retrying.\n", tw_dev->host->host_no); tries++; continue; } @@ -1797,13 +1844,13 @@ int tw_reset_sequence(TW_Device_Extension *tw_dev) } if (tries >= TW_MAX_RESET_TRIES) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Controller error or no attention interrupt: giving up for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no); return 1; } error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Couldn't initconnection for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no); return 1; } @@ -1893,14 +1940,14 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt) for (i=0;isrb[i] == SCpnt) { if (tw_dev->state[i] == TW_S_STARTED) { - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort succeeded for started Scsi_Cmnd 0x%x\n", (u32)tw_dev->srb[i]); + printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, (u32)SCpnt); tw_dev->state[i] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, i); spin_unlock(&tw_dev->tw_lock); return (SUCCESS); } if (tw_dev->state[i] == TW_S_PENDING) { - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort succeeded for pending Scsi_Cmnd 0x%x\n", (u32)tw_dev->srb[i]); + printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, (u32)SCpnt); if (tw_dev->pending_head == TW_Q_LENGTH-1) { tw_dev->pending_head = TW_Q_START; } else { @@ -1916,10 +1963,9 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt) } /* If the command has already been posted, we have to reset the card */ - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort failed for unknown Scsi_Cmnd 0x%x, resetting card %d.\n", (u32)SCpnt, tw_dev->host->host_no); - + printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt); if (tw_reset_device_extension(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); + dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (FAILED); } @@ -1956,11 +2002,11 @@ int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt) /* Now reset the card and some of the device extension data */ if (tw_reset_device_extension(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Reset failed for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (FAILED); } - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Reset succeeded for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Reset succeeded.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (SUCCESS); @@ -2073,13 +2119,10 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) switch (*command) { case READ_10: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_10.\n"); case READ_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_6.\n"); case WRITE_10: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught WRITE_10.\n"); case WRITE_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught WRITE_6.\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ/WRITE.\n"); error = tw_scsiop_read_write(tw_dev, request_id); break; case TEST_UNIT_READY: @@ -2103,7 +2146,7 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) error = tw_ioctl(tw_dev, request_id); break; default: - printk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): Unknown scsi opcode: 0x%x\n", *command); + printk(KERN_NOTICE "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x\n", tw_dev->host->host_no, *command); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); SCpnt->result = (DID_BAD_TARGET << 16); @@ -2569,7 +2612,7 @@ int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -2583,7 +2626,8 @@ int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, } if (command_packet->status != 0) { /* bad response */ - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } break; /* Response was okay, so we exit */ @@ -2603,7 +2647,7 @@ int tw_setup_irq(TW_Device_Extension *tw_dev) error = request_irq(tw_dev->tw_pci_dev->irq, tw_interrupt, SA_SHIRQ, device, tw_dev); if (error < 0) { - printk(KERN_WARNING "3w-xxxx: tw_setup_irq(): Error requesting IRQ: %d for card %d.\n", tw_dev->tw_pci_dev->irq, tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Error requesting IRQ: %d.\n", tw_dev->host->host_no, tw_dev->tw_pci_dev->irq); return 1; } return 0; @@ -2621,9 +2665,9 @@ int tw_shutdown_device(TW_Device_Extension *tw_dev) /* poke the board */ error = tw_initconnection(tw_dev, 1); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_shutdown_device(): Couldn't initconnection for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Connection shutdown failed.\n", tw_dev->host->host_no); } else { - printk(KERN_NOTICE "3w-xxxx shutdown succeeded\n"); + printk(KERN_NOTICE "3w-xxxx: Shutdown complete.\n"); } /* Re-enable interrupts */ @@ -2654,7 +2698,7 @@ int tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id) dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish()\n"); do { - if (tw_dev->free_tail == TW_Q_LENGTH-1) { + if (tw_dev->free_tail == tw_dev->free_wrap) { tw_dev->free_tail = TW_Q_START; } else { tw_dev->free_tail = tw_dev->free_tail + 1; @@ -2678,24 +2722,15 @@ int tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id) /* Obtain next free request_id */ do { - if (tw_dev->free_head == TW_Q_LENGTH - 1) { + if (tw_dev->free_head == tw_dev->free_wrap) { tw_dev->free_head = TW_Q_START; } else { tw_dev->free_head = tw_dev->free_head + 1; } - } while ((tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == TW_S_STARTED) || - (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == TW_S_POSTED) || - (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == TW_S_PENDING) || - (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == TW_S_COMPLETED)); + } while (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] & TW_START_MASK); id = tw_dev->free_queue[tw_dev->free_head]; - if (tw_dev->free_head == TW_Q_LENGTH - 1) { - tw_dev->free_head = TW_Q_START; - } else { - tw_dev->free_head = tw_dev->free_head + 1; - } - dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id); *request_id = id; tw_dev->state[id] = TW_S_STARTED; diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 8b0540db1055..44e5a499d581 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -4,6 +4,7 @@ Written By: Adam Radford Modifications By: Joel Jacobson Arnaldo Carvalho de Melo + Brad Strand Copyright (C) 1999-2001 3ware Inc. @@ -57,6 +58,43 @@ #include #include +/* AEN strings */ +static char *tw_aen_string[] = { + "AEN queue empty", // 0x000 + "Soft reset occurred", // 0x001 + "Mirorr degraded: Unit #", // 0x002 + "Controller error", // 0x003 + "Rebuild failed: Unit #", // 0x004 + "Rebuild complete: Unit #", // 0x005 + "Incomplete unit detected: Unit #", // 0x006 + "Initialization complete: Unit #", // 0x007 + "Unclean shutdown detected: Unit #", // 0x008 + "ATA port timeout: Port #", // 0x009 + "Drive error: Port #", // 0x00A + "Rebuild started: Unit #", // 0x00B + "Initialization started: Unit #", // 0x00C + "Logical unit deleted: Unit #", // 0x00D + NULL, // 0x00E unused + "SMART threshold exceeded: Port #", // 0x00F + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, // 0x010-0x020 unused + "ATA UDMA downgrade: Port #", // 0x021 + "ATA UDMA upgrade: Port #", // 0x022 + "Sector repair occurred: Port #", // 0x023 + "SBUF integrity check failure", // 0x024 + "Lost cached write: Port #", // 0x025 + "Drive ECC error detected: Port #", // 0x026 + "DCB checksum error: Port #", // 0x027 + "DCB unsupported version: Port #", // 0x028 + "Verify started: Unit #", // 0x029 + "Verify failed: Port #", // 0x02A + "Verify complete: Unit #" // 0x02B +}; + +#define TW_AEN_STRING_MAX 0x02C + /* Control register bit definitions */ #define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 #define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT 0x00040000 @@ -114,6 +152,7 @@ #define TW_OP_SECTOR_INFO 0x1a #define TW_OP_AEN_LISTEN 0x1c #define TW_CMD_PACKET 0x1d +#define TW_ATA_PASSTHRU 0x1e /* Asynchronous Event Notification (AEN) Codes */ #define TW_AEN_QUEUE_EMPTY 0x0000 @@ -137,7 +176,10 @@ #define TW_INIT_COMMAND_PACKET_SIZE 0x3 #define TW_POLL_MAX_RETRIES 20000 #define TW_MAX_SGL_LENGTH 62 -#define TW_Q_LENGTH 16 +#define TW_ATA_PASS_SGL_MAX 60 +#define TW_MAX_PASSTHRU_BYTES 4096 +#define TW_Q_LENGTH 256 +#define TW_MAX_BOUNCEBUF 16 #define TW_Q_START 0 #define TW_MAX_SLOT 32 #define TW_MAX_PCI_BUSES 255 @@ -225,6 +267,7 @@ typedef struct TAG_TW_Ioctl { unsigned short table_id; unsigned char parameter_id; unsigned char parameter_size_bytes; + unsigned char unit_index; unsigned char data[1]; } TW_Ioctl; @@ -261,14 +304,42 @@ typedef struct TAG_TW_Info { int position; } TW_Info; -typedef enum TAG_TW_Cmd_State { - TW_S_INITIAL, /* Initial state */ - TW_S_STARTED, /* Id in use */ - TW_S_POSTED, /* Posted to the controller */ - TW_S_PENDING, /* Waiting to be posted in isr */ - TW_S_COMPLETED, /* Completed by isr */ - TW_S_FINISHED, /* I/O completely done */ -} TW_Cmd_State; +typedef int TW_Cmd_State; + +#define TW_S_INITIAL 0x1 /* Initial state */ +#define TW_S_STARTED 0x2 /* Id in use */ +#define TW_S_POSTED 0x4 /* Posted to the controller */ +#define TW_S_PENDING 0x8 /* Waiting to be posted in isr */ +#define TW_S_COMPLETED 0x10 /* Completed by isr */ +#define TW_S_FINISHED 0x20 /* I/O completely done */ +#define TW_START_MASK (TW_S_STARTED | TW_S_POSTED | TW_S_PENDING | TW_S_COMPLETED) + +/* Command header for ATA pass-thru */ +typedef struct TAG_TW_Passthru +{ + struct { + unsigned char opcode:5; + unsigned char sgloff:3; + } byte0; + unsigned char size; + unsigned char request_id; + struct { + unsigned char aport:4; + unsigned char host_id:4; + } byte3; + unsigned char status; + unsigned char flags; + unsigned short param; + unsigned short features; + unsigned short sector_count; + unsigned short sector_num; + unsigned short cylinder_lo; + unsigned short cylinder_hi; + unsigned char drive_head; + unsigned char command; + TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX]; + unsigned char padding[12]; +} TW_Passthru; typedef struct TAG_TW_Device_Extension { TW_Registers registers; @@ -286,6 +357,7 @@ typedef struct TAG_TW_Device_Extension { unsigned char free_queue[TW_Q_LENGTH]; unsigned char free_head; unsigned char free_tail; + unsigned char free_wrap; unsigned char pending_queue[TW_Q_LENGTH]; unsigned char pending_head; unsigned char pending_tail; @@ -304,7 +376,7 @@ typedef struct TAG_TW_Device_Extension { u32 aen_count; struct Scsi_Host *host; spinlock_t tw_lock; - unsigned char ioctl_size[TW_Q_LENGTH]; + int ioctl_size[TW_Q_LENGTH]; unsigned short aen_queue[TW_Q_LENGTH]; unsigned char aen_head; unsigned char aen_tail; diff --git a/drivers/scsi/README.st b/drivers/scsi/README.st index 2c88ef4ad316..1fa617468ed2 100644 --- a/drivers/scsi/README.st +++ b/drivers/scsi/README.st @@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver. The driver is currently maintained by Kai M{kisara (email Kai.Makisara@metla.fi) -Last modified: Sat Aug 5 10:29:07 2000 by makisara@kai.makisara.local +Last modified: Thu Nov 1 22:41:59 2001 by makisara@kai.makisara.local BASICS @@ -312,6 +312,8 @@ MTSETDRVBUFFER this flag unless there are tapes using the device dependent (from the old times) (global) MT_ST_SYSV sets the SYSV sematics (mode) + MT_ST_NOWAIT enables immediate mode (i.e., don't wait for + the command to finish) for some commands (e.g., rewind) MT_ST_DEBUGGING debugging (global; debugging must be compiled into the driver) MT_ST_SETBOOLEANS @@ -341,6 +343,25 @@ MTSETDRVBUFFER known to take a long time. The default is 14000 seconds (3.9 hours). For erase this value is further multiplied by eight. + MT_ST_SET_CLN + Set the cleaning request interpretation parameters using + the lowest 24 bits of the argument. The driver can set the + generic status bit GMT_CLN if a cleaning request bit pattern + is found from the extended sense data. Many drives set one or + more bits in the extended sense data when the drive needs + cleaning. The bits are device-dependent. The driver is + given the number of the sense data byte (the lowest eight + bits of the argument; must be >= 18 (values 1 - 17 + reserved) and <= the maximum requested sense data sixe), + a mask to select the relevant bits (the bits 9-16), and the + bit pattern (bits 17-23). If the bit pattern is zero, one + or more bits under the mask indicate cleaning request. If + the pattern is non-zero, the pattern must match the masked + sense data byte. + + (The cleaning bit is set if the additional sense code and + qualifier 00h 17h are seen regardless of the setting of + MT_ST_SET_CLN.) The following ioctl uses the structure mtpos: MTIOCPOS Reads the current position from the drive. Uses diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 3495597b5d2c..080847a4ec46 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -18680,4 +18680,4 @@ AdvInquiryHandling( } } } -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index f3315fc04717..36f38350fd62 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -2956,7 +2956,11 @@ static void is_complete(struct Scsi_Host *shpnt) DO_LOCK(flags); if(HOSTDATA(shpnt)->in_intr!=0) + { + DO_UNLOCK(flags); + /* _error never returns.. */ aha152x_error(shpnt, "bottom-half already running!?"); + } HOSTDATA(shpnt)->in_intr++; DO_UNLOCK(flags); diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c b/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c index 69cf701af4a4..3889dd3e693b 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c @@ -89,7 +89,7 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev) * the free directly, but check our * list for extra sanity. */ - ahc = (struct ahc_softc *)pdev->driver_data; + ahc = pci_get_drvdata(pdev); TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { if (list_ahc == ahc) { ahc_free(ahc); @@ -176,7 +176,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return (-error); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - pdev->driver_data = ahc; + pci_set_drvdata(pdev, ahc); if (aic7xxx_detect_complete) ahc_linux_register_host(ahc, aic7xxx_driver_template); #endif diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index a4ce9bac2060..ccf9b9b36ee2 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -165,6 +165,13 @@ static u8 adpt_read_blink_led(adpt_hba* host) *============================================================================ */ +static struct pci_device_id dptids[] = { + { PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + { PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci,dptids); + static int adpt_detect(Scsi_Host_Template* sht) { struct pci_dev *pDev = NULL; diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index c7360c43c08a..1ce0fa803975 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -2077,4 +2077,4 @@ static Scsi_Host_Template driver_template = EATA; #ifndef MODULE __setup("eata=", option_setup); #endif /* end MODULE */ -MODULE_LICENSE("BSD"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index b07e32951e5e..8040de54c488 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -799,6 +799,17 @@ GDTH_INITFUNC(static int, gdth_search_pci(gdth_pci_str *pcistr)) return cnt; } +#if LINUX_VERSION_CODE >= 0x20363 +/* Vortex only makes RAID controllers. + * We do not really want to specify all 550 ids here, so wildcard match. + */ +static struct pci_device_id gdthtable[] = { + {PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID }, + {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID }, + {0} +}; +MODULE_DEVICE_TABLE(pci,gdthtable); +#endif GDTH_INITFUNC(static void, gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, ushort vendor, ushort device)) diff --git a/drivers/scsi/i60uscsi.c b/drivers/scsi/i60uscsi.c index b71f9ddfbd56..13699ad53eb3 100644 --- a/drivers/scsi/i60uscsi.c +++ b/drivers/scsi/i60uscsi.c @@ -68,10 +68,6 @@ * 08/08/99 bv - v1.02c Use waitForPause again. **************************************************************************/ -#ifndef CVT_LINUX_VERSION -#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) -#endif - #include #include #include @@ -161,12 +157,8 @@ static UCHAR dftNvRam[64] = static void waitForPause(unsigned amount) { ULONG the_time = jiffies + MS_TO_JIFFIES(amount); - -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) - while (time_before_eq(jiffies, the_time)); -#else - while (jiffies < the_time); -#endif + while (time_before_eq(jiffies, the_time)) + cpu_relax(); } /***************************************************************************/ @@ -564,33 +556,16 @@ int orc_reset_scsi_bus(ORC_HCS * pHCB) { /* I need Host Control Block Information */ ULONG flags; -#if 0 - printk("inia100: enter inia100_reset\n"); -#endif - -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); -#endif initAFlag(pHCB); /* reset scsi bus */ ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST); if (waitSCSIRSTdone(pHCB) == FALSE) { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return (SCSI_RESET_ERROR); } else { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return (SCSI_RESET_SUCCESS); } } @@ -611,16 +586,7 @@ int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned UCHAR i; ULONG flags; -#if 0 - printk("inia100: enter inia100_reset\n"); -#endif - -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); -#endif pScb = (ORC_SCB *) NULL; pVirEscb = (ESCB *) NULL; @@ -638,19 +604,11 @@ int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned if (i == orc_num_scb) { printk("Unable to Reset - No SCB Found\n"); -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return (SCSI_RESET_NOT_RUNNING); } if ((pScb = orc_alloc_scb(pHCB)) == NULL) { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return (SCSI_RESET_NOT_RUNNING); } pScb->SCB_Opcode = ORC_BUSDEVRST; @@ -669,17 +627,13 @@ int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned pVirEscb->SCB_Srb = (unsigned char *) SCpnt; } orc_exec_scb(pHCB, pScb); /* Start execute SCB */ -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return SCSI_RESET_PENDING; } /***************************************************************************/ -ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) +ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp) { ORC_SCB *pTmpScb; UCHAR Ch; @@ -688,12 +642,6 @@ ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) UCHAR i; ULONG flags; -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); -#endif Ch = hcsp->HCS_Index; for (i = 0; i < 8; i++) { for (index = 0; index < 32; index++) { @@ -704,21 +652,22 @@ ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) } idx = index + 32 * i; pTmpScb = (PVOID) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB))); -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (pTmpScb); } -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (NULL); } +ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) +{ + ORC_SCB *pTmpScb; + ULONG flags; + + spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); + pTmpScb = __orc_alloc_scb(hcsp); + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); + return (pTmpScb); +} + /***************************************************************************/ void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp) @@ -728,22 +677,13 @@ void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp) UCHAR i; UCHAR Ch; -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); -#endif Ch = hcsp->HCS_Index; Index = scbp->SCB_ScbIdx; i = Index / 32; Index %= 32; hcsp->BitAllocFlag[Ch][i] |= (1 << Index); -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif } @@ -872,15 +812,7 @@ int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt) UCHAR i; ULONG flags; -#if 0 - printk("inia100: abort SRB \n"); -#endif -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); -#endif pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray; @@ -888,37 +820,21 @@ int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt) pVirEscb = pVirScb->SCB_EScb; if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) { if (pVirScb->SCB_TagMsg == 0) { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (SCSI_ABORT_BUSY); } else { if (abort_SCB(hcsp, pVirScb)) { pVirEscb->SCB_Srb = NULL; -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (SCSI_ABORT_SUCCESS); } else { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (SCSI_ABORT_NOT_RUNNING); } } } } -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (SCSI_ABORT_NOT_RUNNING); } diff --git a/drivers/scsi/i60uscsi.h b/drivers/scsi/i60uscsi.h index 19235dedbe09..04dbe52f1778 100644 --- a/drivers/scsi/i60uscsi.h +++ b/drivers/scsi/i60uscsi.h @@ -342,14 +342,10 @@ typedef struct ORC_Ha_Ctrl_Struc { UBYTE ActiveTags[16][16]; /* 50 */ ORC_TCS HCS_Tcs[16]; /* 28 */ U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */ -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) spinlock_t BitAllocFlagLock; -#endif ULONG pSRB_head; ULONG pSRB_tail; -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) spinlock_t pSRB_lock; -#endif } ORC_HCS; /* Bit Definition for HCS_Flags */ diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 27beaa4713c7..04ffa14e6dd3 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -7566,8 +7566,10 @@ ips_verify_bios_memio(ips_ha_t *ha, char *buffer, u_int32_t buffersize, u_int32_ return (0); } +#if defined (MODULE) || (LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)) static Scsi_Host_Template driver_template = IPS; #include "scsi_module.c" +#endif /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index af3f40708bd3..88c4b4ee6b0e 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -858,7 +858,7 @@ int Pci2000_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[]) } -MODULE_LICENSE("BSD without advertisement clause"); +MODULE_LICENSE("Dual BSD/GPL"); /* Eventually this will go into an include file, but this will be later */ static Scsi_Host_Template driver_template = PCI2000; diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index 5130ae7f8495..1dddd5004652 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -2924,7 +2924,7 @@ int Pci2220i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[]) return 0; } -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); /* Eventually this will go into an include file, but this will be later */ static Scsi_Host_Template driver_template = PCI2220I; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 59eb00ae4375..aa7d5efb873c 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -96,17 +96,25 @@ static void scsi_dump_status(int level); /* Do not call reset on error if we just did a reset within 15 sec. */ #define MIN_RESET_PERIOD (15*HZ) +/* + * Macro to determine the size of SCSI command. This macro takes vendor + * unique commands into account. SCSI commands in groups 6 and 7 are + * vendor unique and we will depend upon the command length being + * supplied correctly in cmd_len. + */ +#define CDB_SIZE(SCpnt) ((((SCpnt->cmnd[0] >> 5) & 7) < 6) ? \ + COMMAND_SIZE(SCpnt->cmnd[0]) : SCpnt->cmd_len) /* * Data declarations. */ unsigned long scsi_pid; Scsi_Cmnd *last_cmnd; -/* Command groups 3 and 4 are reserved and should never be used. */ +/* Command group 3 is reserved and should never be used. */ const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, - 12, 12, 10, 10 + 16, 12, 10, 10 }; static unsigned long serial_number; static Scsi_Cmnd *scsi_bh_queue_head; @@ -679,18 +687,44 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) * passes a meaningful return value. */ if (host->hostt->use_new_eh_code) { - spin_lock_irqsave(&io_request_lock, flags); - rtn = host->hostt->queuecommand(SCpnt, scsi_done); - spin_unlock_irqrestore(&io_request_lock, flags); - if (rtn != 0) { - scsi_delete_timer(SCpnt); - scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); - SCSI_LOG_MLQUEUE(3, printk("queuecommand : request rejected\n")); + /* + * Before we queue this command, check if the command + * length exceeds what the host adapter can handle. + */ + if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { + spin_lock_irqsave(&io_request_lock, flags); + rtn = host->hostt->queuecommand(SCpnt, scsi_done); + spin_unlock_irqrestore(&io_request_lock, flags); + if (rtn != 0) { + scsi_delete_timer(SCpnt); + scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); + SCSI_LOG_MLQUEUE(3, printk("queuecommand : request rejected\n")); + } + } else { + SCSI_LOG_MLQUEUE(3, printk("queuecommand : command too long.\n")); + SCpnt->result = (DID_ABORT << 16); + spin_lock_irqsave(&io_request_lock, flags); + scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + rtn = 1; } } else { - spin_lock_irqsave(&io_request_lock, flags); - host->hostt->queuecommand(SCpnt, scsi_old_done); - spin_unlock_irqrestore(&io_request_lock, flags); + /* + * Before we queue this command, check if the command + * length exceeds what the host adapter can handle. + */ + if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { + spin_lock_irqsave(&io_request_lock, flags); + host->hostt->queuecommand(SCpnt, scsi_old_done); + spin_unlock_irqrestore(&io_request_lock, flags); + } else { + SCSI_LOG_MLQUEUE(3, printk("queuecommand : command too long.\n")); + SCpnt->result = (DID_ABORT << 16); + spin_lock_irqsave(&io_request_lock, flags); + scsi_old_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + rtn = 1; + } } } else { int temp; @@ -702,8 +736,10 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt) #ifdef DEBUG_DELAY spin_unlock_irqrestore(&io_request_lock, flags); clock = jiffies + 4 * HZ; - while (time_before(jiffies, clock)) + while (time_before(jiffies, clock)) { barrier(); + cpu_relax(); + } printk("done(host = %d, result = %04x) : routine at %p\n", host->host_no, temp, host->hostt->command); spin_lock_irqsave(&io_request_lock, flags); @@ -787,14 +823,15 @@ void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd, { int i; int target = SDpnt->id; + int size = COMMAND_SIZE(((const unsigned char *)cmnd)[0]); printk("scsi_do_req (host = %d, channel = %d target = %d, " "buffer =%p, bufflen = %d, done = %p, timeout = %d, " "retries = %d)\n" "command : ", host->host_no, SDpnt->channel, target, buffer, bufflen, done, timeout, retries); - for (i = 0; i < 10; ++i) - printk("%02x ", ((unsigned char *) cmnd)[i]); - printk("\n"); + for (i = 0; i < size; ++i) + printk("%02x ", ((unsigned char *) cmnd)[i]); + printk("\n"); }); if (!host) { @@ -976,14 +1013,15 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd, { int i; int target = SCpnt->target; + int size = COMMAND_SIZE(((const unsigned char *)cmnd)[0]); printk("scsi_do_cmd (host = %d, channel = %d target = %d, " "buffer =%p, bufflen = %d, done = %p, timeout = %d, " "retries = %d)\n" "command : ", host->host_no, SCpnt->channel, target, buffer, bufflen, done, timeout, retries); - for (i = 0; i < 10; ++i) - printk("%02x ", ((unsigned char *) cmnd)[i]); - printk("\n"); + for (i = 0; i < size; ++i) + printk("%02x ", ((unsigned char *) cmnd)[i]); + printk("\n"); }); if (!host) { @@ -1477,9 +1515,6 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt) spin_unlock_irqrestore(&device_request_lock, flags); } -static int proc_scsi_gen_write(struct file * file, const char * buf, - unsigned long length, void *data); - void __init scsi_host_no_insert(char *str, int n) { Scsi_Host_Name *shn, *shn2; diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index c1b59f2d530a..7b434522f3ea 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -61,7 +61,7 @@ extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir) #endif #endif -#if defined(CONFIG_SBUS) && !defined(CONFIG_SUN3) +#if defined(CONFIG_SBUS) && !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) #include #if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE)) #define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) @@ -351,7 +351,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; #define DRIVER_MASK 0x0f #define SUGGEST_MASK 0xf0 -#define MAX_COMMAND_SIZE 12 +#define MAX_COMMAND_SIZE 16 #define SCSI_SENSE_BUFFERSIZE 64 /* diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5b268aa564dd..f2392578f992 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -230,11 +230,8 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, return -EFAULT; return 0; } - case BLKGETSIZE: /* Return device size */ - return put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects, (unsigned long *) arg); + case BLKGETSIZE: case BLKGETSIZE64: - return put_user((u64)sd[SD_PARTITION(inode->i_rdev)].nr_sects << 9, (u64 *)arg); - case BLKROSET: case BLKROGET: case BLKRASET: @@ -459,8 +456,10 @@ static int sd_open(struct inode *inode, struct file *filp) * is being re-read. */ - while (rscsi_disks[target].device->busy) + while (rscsi_disks[target].device->busy) { barrier(); + cpu_relax(); + } /* * The following code can sleep. * Module unloading must be prevented diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index cc049d3a4332..51eed48a42b1 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -12,7 +12,7 @@ Copyright 1992 - 2001 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Wed Oct 3 22:17:59 2001 by makisara@kai.makisara.local + Last modified: Sat Nov 3 19:30:55 2001 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support @@ -21,7 +21,7 @@ error handling will be discarded. */ -static char *verstr = "20011003"; +static char *verstr = "20011103"; #include @@ -276,6 +276,17 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt) driver_byte(result) & DRIVER_MASK, host_byte(result)); } + if (STp->cln_mode >= EXTENDED_SENSE_START) { + if (STp->cln_sense_value) + STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] & + STp->cln_sense_mask) == STp->cln_sense_value); + else + STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] & + STp->cln_sense_mask) != 0); + } + if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */ + STp->cleaning_req = 1; + if ((sense[0] & 0x70) == 0x70 && scode == RECOVERED_ERROR #if ST_RECOVERED_WRITE_FATAL @@ -414,15 +425,6 @@ static void write_behind_check(Scsi_Tape * STp) (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt); scsi_release_request((STp->buffer)->last_SRpnt); - if (STbuffer->writing < STbuffer->buffer_bytes) -#if 0 - memcpy(STbuffer->b_data, - STbuffer->b_data + STbuffer->writing, - STbuffer->buffer_bytes - STbuffer->writing); -#else - printk(KERN_WARNING - "st: write_behind_check: something left in buffer!\n"); -#endif STbuffer->buffer_bytes -= STbuffer->writing; STps = &(STp->ps[STp->partition]); if (STps->drv_block >= 0) { @@ -636,47 +638,27 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm) return 0; } - -/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host - module count. */ -static int st_open(struct inode *inode, struct file *filp) +/* See if the drive is ready and gather information about the tape. Return values: + < 0 negative error code from errno.h + 0 drive ready + 1 drive not ready (possibly no tape) +*/ +#define CHKRES_READY 0 +#define CHKRES_NOT_READY 1 + +static int check_tape(Scsi_Tape *STp, struct file *filp) { - unsigned short st_flags; - int i, need_dma_buffer, new_session = FALSE; - int retval; - unsigned char cmd[MAX_COMMAND_SIZE]; + int i, retval, new_session = FALSE; + unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning; + unsigned short st_flags = filp->f_flags; Scsi_Request *SRpnt; - Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; - int dev = TAPE_NR(inode->i_rdev); + int dev = TAPE_NR(STp->devt); + struct inode *inode = filp->f_dentry->d_inode; int mode = TAPE_MODE(inode->i_rdev); - unsigned long flags; - - write_lock_irqsave(&st_dev_arr_lock, flags); - STp = scsi_tapes[dev]; - if (dev >= st_template.dev_max || STp == NULL) { - write_unlock_irqrestore(&st_dev_arr_lock, flags); - return (-ENXIO); - } - - if (STp->in_use) { - write_unlock_irqrestore(&st_dev_arr_lock, flags); - DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); ) - return (-EBUSY); - } - STp->in_use = 1; - write_unlock_irqrestore(&st_dev_arr_lock, flags); - STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0; - if (STp->device->host->hostt->module) - __MOD_INC_USE_COUNT(STp->device->host->hostt->module); - STp->device->access_count++; - - if (!scsi_block_when_processing_errors(STp->device)) { - retval = (-ENXIO); - goto err_out; - } + STp->ready = ST_READY; if (mode != STp->current_mode) { DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", @@ -686,54 +668,11 @@ static int st_open(struct inode *inode, struct file *filp) } STm = &(STp->modes[STp->current_mode]); - /* Allocate a buffer for this user */ - need_dma_buffer = STp->restr_dma; - write_lock_irqsave(&st_dev_arr_lock, flags); - for (i = 0; i < st_nbr_buffers; i++) - if (!st_buffers[i]->in_use && - (!need_dma_buffer || st_buffers[i]->dma)) { - STp->buffer = st_buffers[i]; - (STp->buffer)->in_use = 1; - break; - } - write_unlock_irqrestore(&st_dev_arr_lock, flags); - if (i >= st_nbr_buffers) { - STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE); - if (STp->buffer == NULL) { - printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); - retval = (-EBUSY); - goto err_out; - } - } - - (STp->buffer)->writing = 0; - (STp->buffer)->syscall_result = 0; - (STp->buffer)->use_sg = STp->device->host->sg_tablesize; - - /* Compute the usable buffer size for this SCSI adapter */ - if (!(STp->buffer)->use_sg) - (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length; - else { - for (i = 0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg && - i < (STp->buffer)->sg_segs; i++) - (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; - } - - st_flags = filp->f_flags; - STp->write_prot = ((st_flags & O_ACCMODE) == O_RDONLY); - - STp->dirty = 0; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - } - STp->ready = ST_READY; - STp->recover_count = 0; - DEB( STp->nbr_waits = STp->nbr_finished = 0; ) - memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; + saved_cleaning = STp->cleaning_req; + STp->cleaning_req = 0; SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout, MAX_READY_RETRIES, TRUE); if (!SRpnt) { @@ -742,7 +681,7 @@ static int st_open(struct inode *inode, struct file *filp) } if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && - (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ + (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ /* Flush the queued UNIT ATTENTION sense data */ for (i=0; i < 10; i++) { @@ -771,6 +710,8 @@ static int st_open(struct inode *inode, struct file *filp) } new_session = TRUE; } + else + STp->cleaning_req |= saved_cleaning; if ((STp->buffer)->syscall_result != 0) { if ((STp->device)->scsi_level >= SCSI_2 && @@ -788,7 +729,7 @@ static int st_open(struct inode *inode, struct file *filp) STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); STp->partition = STp->new_partition = 0; STp->door_locked = ST_UNLOCKED; - return 0; + return CHKRES_NOT_READY; } if (STp->omit_blklims) @@ -869,7 +810,8 @@ static int st_open(struct inode *inode, struct file *filp) DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev)); - if ((st_flags & O_ACCMODE) == O_WRONLY || (st_flags & O_ACCMODE) == O_RDWR) { + if ((st_flags & O_ACCMODE) == O_WRONLY || + (st_flags & O_ACCMODE) == O_RDWR) { retval = (-EROFS); goto err_out; } @@ -904,6 +846,95 @@ static int st_open(struct inode *inode, struct file *filp) } } + return CHKRES_READY; + + err_out: + return retval; +} + + + /* Open the device. Needs to be called with BKL only because of incrementing the SCSI host + module count. */ +static int st_open(struct inode *inode, struct file *filp) +{ + int i, need_dma_buffer; + int retval = (-EIO); + Scsi_Tape *STp; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + unsigned long flags; + + write_lock_irqsave(&st_dev_arr_lock, flags); + STp = scsi_tapes[dev]; + if (dev >= st_template.dev_max || STp == NULL) { + write_unlock_irqrestore(&st_dev_arr_lock, flags); + return (-ENXIO); + } + + if (STp->in_use) { + write_unlock_irqrestore(&st_dev_arr_lock, flags); + DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); ) + return (-EBUSY); + } + STp->in_use = 1; + write_unlock_irqrestore(&st_dev_arr_lock, flags); + STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0; + + if (STp->device->host->hostt->module) + __MOD_INC_USE_COUNT(STp->device->host->hostt->module); + STp->device->access_count++; + + if (!scsi_block_when_processing_errors(STp->device)) { + retval = (-ENXIO); + goto err_out; + } + + /* Allocate a buffer for this user */ + need_dma_buffer = STp->restr_dma; + write_lock_irqsave(&st_dev_arr_lock, flags); + for (i = 0; i < st_nbr_buffers; i++) + if (!st_buffers[i]->in_use && + (!need_dma_buffer || st_buffers[i]->dma)) { + STp->buffer = st_buffers[i]; + (STp->buffer)->in_use = 1; + break; + } + write_unlock_irqrestore(&st_dev_arr_lock, flags); + if (i >= st_nbr_buffers) { + STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE); + if (STp->buffer == NULL) { + printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); + retval = (-EBUSY); + goto err_out; + } + } + + (STp->buffer)->writing = 0; + (STp->buffer)->syscall_result = 0; + (STp->buffer)->use_sg = STp->device->host->sg_tablesize; + + /* Compute the usable buffer size for this SCSI adapter */ + if (!(STp->buffer)->use_sg) + (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length; + else { + for (i = 0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg && + i < (STp->buffer)->sg_segs; i++) + (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; + } + + STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY); + + STp->dirty = 0; + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + } + STp->recover_count = 0; + DEB( STp->nbr_waits = STp->nbr_finished = 0; ) + + retval = check_tape(STp, filp); + if (retval < 0) + goto err_out; return 0; err_out: @@ -1819,7 +1850,7 @@ static void st_log_options(Scsi_Tape * STp, ST_mode * STm, int dev) dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO - "st%d: sysv: %d\n", dev, STm->sysv); + "st%d: sysv: %d nowait: %d\n", dev, STm->sysv, STp->immediate); DEB(printk(KERN_INFO "st%d: debugging: %d\n", dev, debugging);) @@ -1856,6 +1887,7 @@ static int st_set_options(Scsi_Tape *STp, long options) if ((STp->device)->scsi_level >= SCSI_2) STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; + STp->immediate = (options & MT_ST_NOWAIT) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; DEB( debugging = (options & MT_ST_DEBUGGING) != 0; ) st_log_options(STp, STm, dev); @@ -1884,6 +1916,8 @@ static int st_set_options(Scsi_Tape *STp, long options) STp->can_partitions = value; if ((options & MT_ST_SCSI2LOGICAL) != 0) STp->scsi2_logical = value; + if ((options & MT_ST_NOWAIT) != 0) + STp->immediate = value; if ((options & MT_ST_SYSV) != 0) STm->sysv = value; DEB( @@ -1922,6 +1956,17 @@ static int st_set_options(Scsi_Tape *STp, long options) printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev, value); } + } else if (code == MT_ST_SET_CLN) { + value = (options & ~MT_ST_OPTIONS) & 0xff; + if (value != 0 && + value < EXTENDED_SENSE_START && value >= SCSI_SENSE_BUFFERSIZE) + return (-EINVAL); + STp->cln_mode = value; + STp->cln_sense_mask = (options >> 8) & 0xff; + STp->cln_sense_value = (options >> 16) & 0xff; + printk(KERN_INFO + "st%d: Cleaning request mode %d, mask %02x, value %02x\n", + dev, value, STp->cln_sense_mask, STp->cln_sense_value); } else if (code == MT_ST_DEF_OPTIONS) { code = (options & ~MT_ST_CLEAR_DEFAULT); value = (options & MT_ST_CLEAR_DEFAULT); @@ -2099,6 +2144,78 @@ static int st_compression(Scsi_Tape * STp, int state) STp->compression_changed = TRUE; return 0; } + + +/* Process the load and unload commands (does unload if the load code is zero) */ +static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code) +{ + int retval = (-EIO), timeout; + DEB(int dev = TAPE_NR(STp->devt);) + unsigned char cmd[MAX_COMMAND_SIZE]; + ST_partstat *STps; + Scsi_Request *SRpnt; + + if (STp->ready != ST_READY && !load_code) { + if (STp->ready == ST_NO_TAPE) + return (-ENOMEDIUM); + else + return (-EIO); + } + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = START_STOP; + if (load_code) + cmd[4] |= 1; + /* + * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A + */ + if (load_code >= 1 + MT_ST_HPLOADER_OFFSET + && load_code <= 6 + MT_ST_HPLOADER_OFFSET) { + DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", + dev, (cmd[4]) ? "" : "un", + load_code - MT_ST_HPLOADER_OFFSET)); + cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ + } + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; + } + else + timeout = STp->long_timeout; + + DEBC( + if (!load_code) + printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); + else + printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); + ); + + SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, + timeout, MAX_RETRIES, TRUE); + if (!SRpnt) + return (STp->buffer)->syscall_result; + + retval = (STp->buffer)->syscall_result; + scsi_release_request(SRpnt); + + if (!retval) { /* SCSI command successful */ + + if (!load_code) + STp->rew_at_close = 0; + else + STp->rew_at_close = STp->autorew_dev; + + retval = check_tape(STp, filp); + if (retval > 0) + retval = 0; + } + else { + STps = &(STp->ps[STp->partition]); + STps->drv_file = STps->drv_block = (-1); + } + + return retval; +} /* Internal ioctl function */ @@ -2106,7 +2223,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg) { int timeout; long ltmp; - int i, ioctl_result; + int ioctl_result; int chg_eof = TRUE; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; @@ -2115,7 +2232,7 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg) int datalen = 0, direction = SCSI_DATA_NONE; int dev = TAPE_NR(STp->devt); - if (STp->ready != ST_READY && cmd_in != MTLOAD) { + if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) return (-ENOMEDIUM); else @@ -2254,54 +2371,23 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg) break; case MTREW: cmd[0] = REZERO_UNIT; -#if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; -#endif + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; + } DEBC(printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev)); fileno = blkno = at_sm = 0; break; - case MTOFFL: - case MTLOAD: - case MTUNLOAD: - cmd[0] = START_STOP; - if (cmd_in == MTLOAD) - cmd[4] |= 1; - /* - * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A - */ - if (cmd_in != MTOFFL && - arg >= 1 + MT_ST_HPLOADER_OFFSET - && arg <= 6 + MT_ST_HPLOADER_OFFSET) { - DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", - dev, (cmd[4]) ? "" : "un", - arg - MT_ST_HPLOADER_OFFSET)); - cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ - } -#if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; -#else - timeout = STp->long_timeout; -#endif - DEBC( - if (cmd_in != MTLOAD) - printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); - else - printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); - ) - fileno = blkno = at_sm = 0; - break; case MTNOP: DEBC(printk(ST_DEB_MSG "st%d: No op on tape.\n", dev)); return 0; /* Should do something ? */ break; case MTRETEN: cmd[0] = START_STOP; -#if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; -#endif + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; + } cmd[4] = 3; DEBC(printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev)); fileno = blkno = at_sm = 0; @@ -2331,12 +2417,13 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg) return (-EACCES); cmd[0] = ERASE; cmd[1] = 1; /* To the end of tape */ -#if ST_NOWAIT - cmd[1] |= 2; /* Don't wait for completion */ - timeout = STp->timeout; -#else - timeout = STp->long_timeout * 8; -#endif + if (STp->immediate) { + cmd[1] |= 2; /* Don't wait for completion */ + timeout = STp->timeout; + } + else + timeout = STp->long_timeout * 8; + DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev)); fileno = blkno = at_sm = 0; break; @@ -2462,17 +2549,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg) else if (chg_eof) STps->eof = ST_NOEOF; - - if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) - STp->rew_at_close = 0; - else if (cmd_in == MTLOAD) { - STp->rew_at_close = STp->autorew_dev; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].last_block_valid = FALSE; - } - STp->partition = 0; - } } else { /* SCSI command was not completely successful. Don't return from this block without releasing the SCSI command block! */ @@ -2692,10 +2768,10 @@ static int set_location(Scsi_Tape *STp, unsigned int block, int partition, dev, STp->partition, partition)); } } -#if ST_NOWAIT - scmd[1] |= 1; /* Don't wait for completion */ - timeout = STp->timeout; -#endif + if (STp->immediate) { + scmd[1] |= 1; /* Don't wait for completion */ + timeout = STp->timeout; + } SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE, timeout, MAX_READY_RETRIES, TRUE); @@ -3073,6 +3149,16 @@ static int st_ioctl(struct inode *inode, struct file *file, goto out; } + if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) { + retval = do_load_unload(STp, file, 0); + goto out; + } + + if (mtc.mt_op == MTLOAD) { + retval = do_load_unload(STp, file, max(1, mtc.mt_count)); + goto out; + } + if (STp->can_partitions && STp->ready == ST_READY && (i = update_partition(STp)) < 0) { retval = i; @@ -3155,6 +3241,8 @@ static int st_ioctl(struct inode *inode, struct file *file, (STm->do_buffer_writes && STp->block_size != 0) || STp->drv_buffer != 0) mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); + if (STp->cleaning_req) + mt_status.mt_gstat |= GMT_CLN(0xffffffff); i = copy_to_user((char *) arg, (char *) &(mt_status), sizeof(struct mtget)); @@ -3642,6 +3730,7 @@ static int st_attach(Scsi_Device * SDp) tpnt->two_fm = ST_TWO_FM; tpnt->fast_mteom = ST_FAST_MTEOM; tpnt->scsi2_logical = ST_SCSI2LOGICAL; + tpnt->immediate = ST_NOWAIT; tpnt->write_threshold = st_write_threshold; tpnt->default_drvbuffer = 0xff; /* No forced buffering */ tpnt->partition = 0; diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 12ee5a7e991c..2ffb381fcb08 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -1,9 +1,6 @@ #ifndef _ST_H #define _ST_H -/* - $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $ - */ #ifndef _SCSI_H #include "scsi.h" @@ -78,9 +75,13 @@ typedef struct { unsigned char can_partitions; unsigned char two_fm; unsigned char fast_mteom; + unsigned char immediate; unsigned char restr_dma; unsigned char scsi2_logical; unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ + unsigned char cln_mode; /* 0 = none, otherwise sense byte nbr */ + unsigned char cln_sense_value; + unsigned char cln_sense_mask; unsigned char use_pf; /* Set Page Format bit in all mode selects? */ int tape_type; int write_threshold; @@ -112,6 +113,7 @@ typedef struct { unsigned char autorew_dev; /* auto-rewind device */ unsigned char rew_at_close; /* rewind necessary at close */ unsigned char inited; + unsigned char cleaning_req; /* cleaning requested? */ int block_size; int min_block; int max_block; @@ -168,4 +170,6 @@ typedef struct { #define ST_NO 1 #define ST_YES 2 +#define EXTENDED_SENSE_START 18 + #endif diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c index ffd330877e6d..b467e1e8c9b2 100644 --- a/drivers/sound/ac97_codec.c +++ b/drivers/sound/ac97_codec.c @@ -130,7 +130,7 @@ static const struct { {0x54524103, "TriTech TR28023", &null_ops}, {0x54524106, "TriTech TR28026", &null_ops}, {0x54524108, "TriTech TR28028", &tritech_ops}, - {0x54524123, "TriTech TR?????", &null_ops}, + {0x54524123, "TriTech TR A5", &null_ops}, {0x574D4C00, "Wolfson WM9704", &wolfson_ops}, {0x574D4C03, "Wolfson WM9703/9704", &wolfson_ops}, {0x574D4C04, "Wolfson WM9704 (quad)", &wolfson_ops}, @@ -143,7 +143,6 @@ static const struct { {0x83847656, "SigmaTel STAC9756/57", &sigmatel_9744_ops}, {0x83847684, "SigmaTel STAC9783/84?", &null_ops}, {0x57454301, "Winbond 83971D", &null_ops}, - {0,} }; static const char *ac97_stereo_enhancements[] = diff --git a/drivers/sound/aci.c b/drivers/sound/aci.c index 97be26ef7e5e..ef1c4ef86ae7 100644 --- a/drivers/sound/aci.c +++ b/drivers/sound/aci.c @@ -47,6 +47,8 @@ * changed param aci_reset to reset, new params: ide, wss. * 2001-04-20 Robert Siemer * even more cleanups... + * 2001-10-08 Arnaldo Carvalho de Melo + * Get rid of check_region, .bss optimizations, use set_current_state */ #include @@ -70,9 +72,9 @@ EXPORT_SYMBOL(aci_version); #include "aci.h" -static int aci_solo=0; /* status bit of the card that can't be * +static int aci_solo; /* status bit of the card that can't be * * checked with ACI versions prior to 0xb0 */ -static int aci_amp=0; /* status bit for power-amp/line-out level +static int aci_amp; /* status bit for power-amp/line-out level but I have no docs about what is what... */ static int aci_micpreamp=3; /* microphone preamp-level that can't be * * checked with ACI versions prior to 0xb0 */ @@ -81,7 +83,7 @@ static int mixer_device; static struct semaphore aci_sem; #ifdef MODULE -static int reset = 0; +static int reset; MODULE_PARM(reset,"i"); MODULE_PARM_DESC(reset,"When set to 1, reset aci mixer."); #else @@ -146,7 +148,7 @@ static int busy_wait(void) case 20 ... 30: out /= 10; default: - current->state=TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(out); break; } @@ -209,28 +211,25 @@ static inline int aci_rawread(void) int aci_rw_cmd(int write1, int write2, int write3) { int write[] = {write1, write2, write3}; - int read, i; + int read = -EINTR, i; if (down_interruptible(&aci_sem)) - return -EINTR; + goto out; for (i=0; i<3; i++) { if (write[i]< 0 || write[i] > 255) break; - else - if (aci_rawwrite(write[i])<0) { - up(&aci_sem); - return -EBUSY; - } + else { + read = aci_rawwrite(write[i]); + if (read < 0) + goto out_up; + } + } - if ((read=aci_rawread())<0) { - up(&aci_sem); - return -EBUSY; - } - - up(&aci_sem); - return read; + read = aci_rawread(); +out_up: up(&aci_sem); +out: return read; } EXPORT_SYMBOL(aci_rw_cmd); @@ -602,7 +601,7 @@ static struct mixer_operations aci_mixer_operations = static int __init attach_aci(void) { char *boardname; - int i; + int i, rc = -EBUSY; init_MUTEX(&aci_sem); @@ -610,27 +609,32 @@ static int __init attach_aci(void) aci_port = (inb(0xf90) & 0x10) ? 0x344: 0x354; /* Get aci_port from MC4_PORT */ - if (check_region(aci_port, 3)) { - printk(KERN_NOTICE "aci: I/O area 0x%03x-0x%03x already used.\n", + if (!request_region(aci_port, 3, "sound mixer (ACI)")) { + printk(KERN_NOTICE + "aci: I/O area 0x%03x-0x%03x already used.\n", aci_port, aci_port+2); - return -EBUSY; + goto out; } /* force ACI into a known state */ + rc = -EFAULT; for (i=0; i<3; i++) if (aci_rw_cmd(ACI_ERROR_OP, -1, -1)<0) - return -EFAULT; + goto out_release_region; /* official this is one aci read call: */ + rc = -EFAULT; if ((aci_idcode[0]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0 || (aci_idcode[1]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0) { - printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", aci_port); - return -EFAULT; + printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", + aci_port); + goto out_release_region; } if ((aci_version=aci_rw_cmd(ACI_READ_VERSION, -1, -1))<0) { - printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", aci_port); - return -EFAULT; + printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", + aci_port); + goto out_release_region; } if (aci_idcode[0] == 'm') { @@ -660,42 +664,40 @@ static int __init attach_aci(void) aci_idcode[0], aci_idcode[1], boardname, aci_port); + rc = -EBUSY; if (reset) { /* first write()s after reset fail with my PCM20 */ if (aci_rw_cmd(ACI_INIT, -1, -1)<0 || aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0 || aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0) - return -EBUSY; + goto out_release_region; } /* the PCM20 is muted after reset (and reboot) */ if (aci_rw_cmd(ACI_SET_MUTE, 0x00, -1)<0) - return -EBUSY; + goto out_release_region; if (ide>=0) if (aci_rw_cmd(ACI_SET_IDE, !ide, -1)<0) - return -EBUSY; + goto out_release_region; if (wss>=0 && aci_idcode[1]=='A') if (aci_rw_cmd(ACI_SET_WSS, !!wss, -1)<0) - return -EBUSY; - - if (!request_region(aci_port, 3, "sound mixer (ACI)")) - return -ENOMEM; + goto out_release_region; - if ((mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION, - boardname, - &aci_mixer_operations, - sizeof(aci_mixer_operations), - NULL)) >= 0) { - /* Maybe initialize the CS4231A mixer here... */ - } else { + mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION, boardname, + &aci_mixer_operations, + sizeof(aci_mixer_operations), NULL); + rc = 0; + if (mixer_device < 0) { printk(KERN_ERR "aci: Failed to install mixer.\n"); - release_region(aci_port, 3); - return mixer_device; - } - - return 0; + rc = mixer_device; + goto out_release_region; + } /* else Maybe initialize the CS4231A mixer here... */ +out: return rc; +out_release_region: + release_region(aci_port, 3); + goto out; } static void __exit unload_aci(void) diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c index 07133ec491d2..fe910899660a 100644 --- a/drivers/sound/cmpci.c +++ b/drivers/sound/cmpci.c @@ -884,9 +884,9 @@ static int set_dac_channels(struct cm_state *s, int channels) spin_unlock_irqrestore(&s->lock, flags); ret = prog_dmabuf(s, 1); + if (ret) return ret; spin_lock_irqsave(&s->lock, flags); - if (ret) return ret; // copy the hw state fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT); fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT); @@ -2847,6 +2847,17 @@ MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out"); MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center"); MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver"); +static struct pci_device_id cmpci_pci_tbl[] = { + { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cmpci_pci_tbl); + void initialize_chip(struct pci_dev *pcidev) { struct cm_state *s; diff --git a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c index e7ea3a8b153e..84165efc07f9 100644 --- a/drivers/sound/i810_audio.c +++ b/drivers/sound/i810_audio.c @@ -2478,6 +2478,10 @@ static int __init i810_ac97_init(struct i810_card *card) for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + /* Assume codec isn't available until we go through the + * gauntlet below */ + card->ac97_codec[num_ac97] = NULL; + /* The ICH programmer's reference says you should */ /* check the ready status before probing. So we chk */ /* What do we do if it's not ready? Wait and try */ @@ -2485,7 +2489,6 @@ static int __init i810_ac97_init(struct i810_card *card) if (!i810_ac97_exists(card,num_ac97)) { if(num_ac97 == 0) printk(KERN_ERR "i810_audio: Primary codec not ready.\n"); - card->ac97_codec[num_ac97] = 0; break; /* I think this works, if not ready stop */ } @@ -2503,6 +2506,7 @@ static int __init i810_ac97_init(struct i810_card *card) if(!i810_ac97_probe_and_powerup(card,codec)) { printk("i810_audio: timed out waiting for codec %d analog ready", num_ac97); + kfree(codec); break; /* it didn't work */ } /* Store state information about S/PDIF transmitter */ @@ -2750,7 +2754,7 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id kfree(card); return -ENODEV; } - pci_dev->driver_data = card; + pci_set_drvdata(pci_dev, card); if(clocking == 48000) { i810_configure_clocking(); @@ -2778,7 +2782,7 @@ static int __init i810_probe(struct pci_dev *pci_dev, const struct pci_device_id static void __exit i810_remove(struct pci_dev *pci_dev) { int i; - struct i810_card *card = pci_dev->driver_data; + struct i810_card *card = pci_get_drvdata(pci_dev); /* free hardware resources */ free_irq(card->irq, devs); release_region(card->iobase, 64); @@ -2797,7 +2801,7 @@ static void __exit i810_remove(struct pci_dev *pci_dev) #ifdef CONFIG_PM static int i810_pm_suspend(struct pci_dev *dev, u32 pm_state) { - struct i810_card *card = dev->driver_data; + struct i810_card *card = pci_get_drvdata(dev); struct i810_state *state; unsigned long flags; struct dmabuf *dmabuf; @@ -2856,7 +2860,7 @@ static int i810_pm_suspend(struct pci_dev *dev, u32 pm_state) static int i810_pm_resume(struct pci_dev *dev) { int num_ac97,i=0; - struct i810_card *card=(struct i810_card *)dev->driver_data; + struct i810_card *card=pci_get_drvdata(dev); pci_enable_device(dev); pci_restore_state (dev,card->pm_save_state); @@ -2870,7 +2874,7 @@ static int i810_pm_resume(struct pci_dev *dev) struct ac97_codec *codec = card->ac97_codec[num_ac97]; /* check they haven't stolen the hardware while we were away */ - if(!i810_ac97_exists(card,num_ac97)) { + if(!codec || !i810_ac97_exists(card,num_ac97)) { if(num_ac97) continue; else BUG(); } diff --git a/drivers/sound/maestro3.c b/drivers/sound/maestro3.c index 1ed8cc63892d..26fe7a67ba25 100644 --- a/drivers/sound/maestro3.c +++ b/drivers/sound/maestro3.c @@ -2693,7 +2693,7 @@ static int __init m3_probe(struct pci_dev *pci_dev, const struct pci_device_id * goto out; } - pci_dev->driver_data = card; + pci_set_drvdata(pci_dev, card); m3_enable_ints(card); m3_assp_continue(card); @@ -2773,7 +2773,7 @@ static int m3_suspend(struct pci_dev *pci_dev, u32 state) { unsigned long flags; int i; - struct m3_card *card = pci_dev->driver_data; + struct m3_card *card = pci_get_drvdata(pci_dev); /* must be a better way.. */ save_flags(flags); @@ -2825,7 +2825,7 @@ static int m3_resume(struct pci_dev *pci_dev) unsigned long flags; int index; int i; - struct m3_card *card = pci_dev->driver_data; + struct m3_card *card = pci_get_drvdata(pci_dev); save_flags(flags); /* paranoia */ cli(); diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index 80e28d9c9bd4..89a376dd9605 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -640,13 +640,21 @@ static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *c static void trident_free_pcm_channel(struct trident_card *card, unsigned int channel) { int bank; + unsigned char b; if (channel < 31 || channel > 63) return; + if (card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_DX || + card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) { + b = inb (TRID_REG(card, T4D_REC_CH)); + if ((b & ~0x80) == channel) + outb(0x0, TRID_REG(card, T4D_REC_CH)); + } + bank = channel >> 5; channel = channel & 0x1f; - + card->banks[bank].bitmap &= ~(1 << (channel)); } diff --git a/drivers/sound/trident.h b/drivers/sound/trident.h index 656cc7cfd2e9..de192b5fa5c7 100644 --- a/drivers/sound/trident.h +++ b/drivers/sound/trident.h @@ -29,7 +29,7 @@ #endif #ifndef PCI_VENDOR_ID_SI -#define PCI_VENDOR_ID_SI 0x0139 +#define PCI_VENDOR_ID_SI 0x1039 #endif #ifndef PCI_VENDOR_ID_ALI diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c index 854175122a28..d338c35beea0 100644 --- a/drivers/sound/via82cxxx_audio.c +++ b/drivers/sound/via82cxxx_audio.c @@ -15,7 +15,7 @@ */ -#define VIA_VERSION "1.1.14b" +#define VIA_VERSION "1.9.1" #include @@ -88,9 +88,10 @@ #define VIA_MAX_FRAG_SIZE PAGE_SIZE #define VIA_MIN_FRAG_SIZE 64 -#define VIA_MIN_FRAG_NUMBER 2 +#define VIA_MIN_FRAG_NUMBER 2 /* 82C686 function 5 (audio codec) PCI configuration registers */ +#define VIA_ACLINK_STATUS 0x40 #define VIA_ACLINK_CTRL 0x41 #define VIA_FUNC_ENABLE 0x42 #define VIA_PNP_CONTROL 0x43 @@ -188,6 +189,7 @@ /* controller base 0 register bitmasks */ #define VIA_INT_DISABLE_MASK (~(0x01|0x02)) #define VIA_SGD_STOPPED (1 << 2) +#define VIA_SGD_PAUSED (1 << 6) #define VIA_SGD_ACTIVE (1 << 7) #define VIA_SGD_TERMINATE (1 << 6) #define VIA_SGD_FLAG (1 << 0) @@ -353,7 +355,10 @@ static inline void via_card_cleanup_proc (struct via_info *card) {} static struct pci_device_id via_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, + PCI_ANY_ID, PCI_ANY_ID, }, { 0, } }; MODULE_DEVICE_TABLE(pci,via_pci_tbl); @@ -387,7 +392,7 @@ static struct pci_driver via_driver = { * */ -static inline void via_chan_stop (int iobase) +static inline void via_chan_stop (long iobase) { if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE) outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL); @@ -408,7 +413,7 @@ static inline void via_chan_stop (int iobase) * */ -static inline void via_chan_status_clear (int iobase) +static inline void via_chan_status_clear (long iobase) { u8 tmp = inb (iobase + VIA_PCM_STATUS); @@ -431,6 +436,19 @@ static inline void sg_begin (struct via_channel *chan) } +static int sg_active (long iobase) +{ + u8 tmp = inb (iobase + VIA_PCM_STATUS); + if ((tmp & VIA_SGD_STOPPED) || (tmp & VIA_SGD_PAUSED)) { + printk(KERN_WARNING "via82cxxx warning: SG stopped or paused\n"); + return 0; + } + if (tmp & VIA_SGD_ACTIVE) + return 1; + return 0; +} + + /**************************************************************** * * Miscellaneous debris @@ -451,6 +469,14 @@ static inline void sg_begin (struct via_channel *chan) static inline int via_syscall_down (struct via_info *card, int nonblock) { + /* Thomas Sailer: + * EAGAIN is supposed to be used if IO is pending, + * not if there is contention on some internal + * synchronization primitive which should be + * held only for a short time anyway + */ + nonblock = 0; + if (nonblock) { if (down_trylock (&card->syscall_sem)) return -EAGAIN; @@ -473,6 +499,8 @@ static inline int via_syscall_down (struct via_info *card, int nonblock) static void via_stop_everything (struct via_info *card) { + u8 tmp, new_tmp; + DPRINTK ("ENTER\n"); assert (card != NULL); @@ -492,11 +520,32 @@ static void via_stop_everything (struct via_info *card) via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN); /* - * clear any enabled interrupt bits, reset to 8-bit mono PCM mode + * clear any enabled interrupt bits */ - outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); - outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); - outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); + tmp = inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); + new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); + if (tmp != new_tmp) + outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); + + tmp = inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); + new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); + if (tmp != new_tmp) + outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); + + tmp = inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); + new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); + if (tmp != new_tmp) + outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); + + udelay(10); + + /* + * clear any existing flags + */ + via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN); + via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN); + via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN); + DPRINTK ("EXIT\n"); } @@ -521,6 +570,8 @@ static int via_set_rate (struct ac97_codec *ac97, DPRINTK ("ENTER, rate = %d\n", rate); + if (chan->rate == rate) + goto out; if (card->locked_rate) { chan->rate = 48000; goto out; @@ -614,7 +665,7 @@ static void via_chan_init_defaults (struct via_info *card, struct via_channel *c * Performs some of the preparations necessary to begin * using a PCM channel. * - * Currently the preparations consist in + * Currently the preparations consist in * setting the * PCM channel to a known state. */ @@ -682,7 +733,7 @@ static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan /* alloc DMA-able memory for scatter-gather buffers */ - chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE + + chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE + (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0); for (i = 0; i < chan->page_number; i++) { @@ -719,7 +770,7 @@ static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan i, (long)chan->sgtable[i].addr); #endif - } + } /* overwrite the last buffer information */ chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL); @@ -766,17 +817,17 @@ static void via_chan_free (struct via_info *card, struct via_channel *chan) { DPRINTK ("ENTER\n"); - synchronize_irq(); - spin_lock_irq (&card->lock); /* stop any existing channel output */ + via_chan_status_clear (chan->iobase); via_chan_stop (chan->iobase); via_chan_status_clear (chan->iobase); - via_chan_pcm_fmt (chan, 1); spin_unlock_irq (&card->lock); + synchronize_irq(); + DPRINTK ("EXIT\n"); } @@ -844,7 +895,7 @@ static void via_chan_pcm_fmt (struct via_channel *chan, int reset) /* if we are recording, enable recording fifo bit */ if (chan->is_record) chan->pcm_fmt |= VIA_PCM_REC_FIFO; - /* set interrupt select bits where applicable (PCM & FM out channels) */ + /* set interrupt select bits where applicable (PCM in & out channels) */ if (!chan->is_record) chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT; @@ -1017,7 +1068,7 @@ static int via_chan_set_buffering (struct via_info *card, DPRINTK ("ENTER\n"); /* in both cases the buffer cannot be changed */ - if (chan->is_active || chan->is_mapped) { + if (chan->is_active || chan->is_mapped) { DPRINTK ("EXIT\n"); return -EINVAL; } @@ -1147,6 +1198,8 @@ static void via_chan_flush_frag (struct via_channel *chan) static inline void via_chan_maybe_start (struct via_channel *chan) { + assert (chan->is_active == sg_active(chan->iobase)); + if (!chan->is_active && chan->is_enabled) { chan->is_active = 1; sg_begin (chan); @@ -1227,10 +1280,12 @@ static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg) data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID; outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL); + udelay (20); + for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) { - udelay (1); - if ((((data = inl(card->baseaddr + 0x80)) & - (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID)) + udelay (1); + if ((((data = inl(card->baseaddr + VIA_BASE0_AC97_CTRL)) & + (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID)) goto out; } @@ -1240,9 +1295,11 @@ static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg) out: /* Once the valid bit has become set, we must wait a complete AC97 frame before the data has settled. */ - udelay(25); - data = (unsigned long) inl (card->baseaddr + 0x80); - + udelay(25); + data = (unsigned long) inl (card->baseaddr + VIA_BASE0_AC97_CTRL); + + outb (0x02, card->baseaddr + 0x83); + if (((data & 0x007F0000) >> 16) == reg) { DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n", data, data & 0x0000FFFF); @@ -1370,6 +1427,7 @@ static struct file_operations via_mixer_fops = { static int __init via_ac97_reset (struct via_info *card) { struct pci_dev *pdev = card->pdev; + u8 tmp8; u16 tmp16; DPRINTK ("ENTER\n"); @@ -1403,20 +1461,43 @@ static int __init via_ac97_reset (struct via_info *card) #endif /* - * reset AC97 controller: enable, disable, enable - * pause after each command for good luck + * Reset AC97 controller: enable, disable, enable, + * pausing after each command for good luck. Only + * do this if the codec is not ready, because it causes + * loud pops and such due to such a hard codec reset. */ - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, VIA_CR41_AC97_ENABLE | - VIA_CR41_AC97_RESET | VIA_CR41_AC97_WAKEUP); - udelay (100); - - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0); - udelay (100); - - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, - VIA_CR41_AC97_ENABLE | VIA_CR41_PCM_ENABLE | - VIA_CR41_VRA | VIA_CR41_AC97_RESET); - udelay (100); + pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8); + if ((tmp8 & VIA_CR40_AC97_READY) == 0) { + pci_write_config_byte (pdev, VIA_ACLINK_CTRL, + VIA_CR41_AC97_ENABLE | + VIA_CR41_AC97_RESET | + VIA_CR41_AC97_WAKEUP); + udelay (100); + + pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0); + udelay (100); + + pci_write_config_byte (pdev, VIA_ACLINK_CTRL, + VIA_CR41_AC97_ENABLE | + VIA_CR41_PCM_ENABLE | + VIA_CR41_VRA | VIA_CR41_AC97_RESET); + udelay (100); + } + + /* Make sure VRA is enabled, in case we didn't do a + * complete codec reset, above + */ + pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8); + if (((tmp8 & VIA_CR41_VRA) == 0) || + ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) || + ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) || + ((tmp8 & VIA_CR41_AC97_RESET) == 0)) { + pci_write_config_byte (pdev, VIA_ACLINK_CTRL, + VIA_CR41_AC97_ENABLE | + VIA_CR41_PCM_ENABLE | + VIA_CR41_VRA | VIA_CR41_AC97_RESET); + udelay (100); + } #if 0 /* this breaks on K7M */ /* disable legacy stuff */ @@ -1433,20 +1514,10 @@ static int __init via_ac97_reset (struct via_info *card) /* WARNING: this line is magic. Remove this * and things break. */ - /* enable variable rate, variable rate MIC ADC */ - /* - * If we cannot enable VRA, we have a locked-rate codec. - * We try again to enable VRA before assuming so, however. - */ + /* enable variable rate */ tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); - if ((tmp16 & 1) == 0) { + if ((tmp16 & 1) == 0) via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); - tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); - if ((tmp16 & 1) == 0) { - card->locked_rate = 1; - printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); - } - } DPRINTK ("EXIT, returning 0\n"); return 0; @@ -1494,10 +1565,24 @@ static int __init via_ac97_init (struct via_info *card) goto err_out; } - /* enable variable rate, variable rate MIC ADC */ + /* enable variable rate */ tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); + /* + * If we cannot enable VRA, we have a locked-rate codec. + * We try again to enable VRA before assuming so, however. + */ + tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); + if ((tmp16 & 1) == 0) { + via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); + tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); + if ((tmp16 & 1) == 0) { + card->locked_rate = 1; + printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); + } + } + DPRINTK ("EXIT, returning 0\n"); return 0; @@ -1632,7 +1717,7 @@ static void via_interrupt(int irq, void *dev_id, struct pt_regs *regs) uart401intr(irq, card->midi_devc, regs); #endif return; - } + } DPRINTK ("intr, status32 == 0x%08X\n", status32); /* synchronize interrupt handling under SMP. this spinlock @@ -1651,47 +1736,6 @@ static void via_interrupt(int irq, void *dev_id, struct pt_regs *regs) } -/** - * via_interrupt_disable - Disable all interrupt-generating sources - * @card: Private info for specified board - * - * Disables all interrupt-generation flags in the Via - * audio hardware registers. - */ - -static void via_interrupt_disable (struct via_info *card) -{ - u8 tmp8; - unsigned long flags; - - DPRINTK ("ENTER\n"); - - assert (card != NULL); - - spin_lock_irqsave (&card->lock, flags); - - pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8); - if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) { - tmp8 |= VIA_CR48_FM_TRAP_TO_NMI; - pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8); - } - - outb (inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE) & - VIA_INT_DISABLE_MASK, - card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); - outb (inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE) & - VIA_INT_DISABLE_MASK, - card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); - outb (inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE) & - VIA_INT_DISABLE_MASK, - card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); - - spin_unlock_irqrestore (&card->lock, flags); - - DPRINTK ("EXIT\n"); -} - - /** * via_interrupt_init - Initialize interrupt handling * @card: Private info for specified board @@ -1703,6 +1747,8 @@ static void via_interrupt_disable (struct via_info *card) static int via_interrupt_init (struct via_info *card) { + u8 tmp8; + DPRINTK ("ENTER\n"); assert (card != NULL); @@ -1716,6 +1762,13 @@ static int via_interrupt_init (struct via_info *card) return -EIO; } + /* make sure FM irq is not routed to us */ + pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8); + if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) { + tmp8 |= VIA_CR48_FM_TRAP_TO_NMI; + pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8); + } + if (request_irq (card->pdev->irq, via_interrupt, SA_SHIRQ, VIA_MODULE_NAME, card)) { printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n", card->pdev->irq); @@ -1723,38 +1776,11 @@ static int via_interrupt_init (struct via_info *card) return -EBUSY; } - /* we don't want interrupts until we're opened */ - via_interrupt_disable (card); - DPRINTK ("EXIT, returning 0\n"); return 0; } -/** - * via_interrupt_cleanup - Shutdown driver interrupt handling - * @card: Private info for specified board - * - * Disable any potential interrupt sources in the Via audio - * hardware, and then release (un-reserve) the IRQ line - * in the kernel core. - */ - -static void via_interrupt_cleanup (struct via_info *card) -{ - DPRINTK ("ENTER\n"); - - assert (card != NULL); - assert (card->pdev != NULL); - - via_interrupt_disable (card); - - free_irq (card->pdev->irq, card); - - DPRINTK ("EXIT\n"); -} - - /**************************************************************** * * OSS DSP device @@ -1958,18 +1984,27 @@ static ssize_t via_dsp_do_read (struct via_info *card, char *userbuf, size_t count, int nonblock) { + DECLARE_WAITQUEUE(wait, current); const char *orig_userbuf = userbuf; struct via_channel *chan = &card->ch_in; size_t size; int n, tmp; + ssize_t ret = 0; /* if SGD has not yet been started, start it */ via_chan_maybe_start (chan); handle_one_block: /* just to be a nice neighbor */ - if (current->need_resched) + /* Thomas Sailer: + * But also to ourselves, release semaphore if we do so */ + if (current->need_resched) { + up(&card->syscall_sem); schedule (); + ret = via_syscall_down (card, nonblock); + if (ret) + goto out; + } /* grab current channel software pointer. In the case of * recording, this is pointing to the next buffer that @@ -1981,33 +2016,53 @@ handle_one_block: * to be copied to userland. sleep until at least * one buffer has been read from the audio hardware. */ - tmp = atomic_read (&chan->n_frags); - assert (tmp >= 0); - assert (tmp <= chan->frag_number); - while (tmp == 0) { - if (nonblock || !chan->is_active) - return -EAGAIN; + add_wait_queue(&chan->wait, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + tmp = atomic_read (&chan->n_frags); + assert (tmp >= 0); + assert (tmp <= chan->frag_number); + if (tmp) + break; + if (nonblock || !chan->is_active) { + ret = -EAGAIN; + break; + } + + up(&card->syscall_sem); DPRINTK ("Sleeping on block %d\n", n); - interruptible_sleep_on (&chan->wait); + schedule(); - if (signal_pending (current)) - return -ERESTARTSYS; + ret = via_syscall_down (card, nonblock); + if (ret) + break; - tmp = atomic_read (&chan->n_frags); + if (signal_pending (current)) { + ret = -ERESTARTSYS; + break; + } } + set_current_state(TASK_RUNNING); + remove_wait_queue(&chan->wait, &wait); + if (ret) + goto out; /* Now that we have a buffer we can read from, send * as much as sample data possible to userspace. */ while ((count > 0) && (chan->slop_len < chan->frag_size)) { size_t slop_left = chan->frag_size - chan->slop_len; + void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr; + unsigned ofs = n % (PAGE_SIZE / chan->frag_size); size = (count < slop_left) ? count : slop_left; if (copy_to_user (userbuf, - chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + n % (PAGE_SIZE / chan->frag_size) + chan->slop_len, - size)) - return -EFAULT; + base + ofs + chan->slop_len, + size)) { + ret = -EFAULT; + goto out; + } count -= size; chan->slop_len += size; @@ -2056,7 +2111,7 @@ handle_one_block: goto handle_one_block; out: - return userbuf - orig_userbuf; + return (userbuf != orig_userbuf) ? (userbuf - orig_userbuf) : ret; } @@ -2107,16 +2162,25 @@ static ssize_t via_dsp_do_write (struct via_info *card, const char *userbuf, size_t count, int nonblock) { + DECLARE_WAITQUEUE(wait, current); const char *orig_userbuf = userbuf; struct via_channel *chan = &card->ch_out; volatile struct via_sgd_table *sgtable = chan->sgtable; size_t size; int n, tmp; + ssize_t ret = 0; handle_one_block: /* just to be a nice neighbor */ - if (current->need_resched) + /* Thomas Sailer: + * But also to ourselves, release semaphore if we do so */ + if (current->need_resched) { + up(&card->syscall_sem); schedule (); + ret = via_syscall_down (card, nonblock); + if (ret) + goto out; + } /* grab current channel fragment pointer. In the case of * playback, this is pointing to the next fragment that @@ -2128,21 +2192,37 @@ handle_one_block: * to be filled by userspace. Sleep until * at least one fragment is available for our use. */ - tmp = atomic_read (&chan->n_frags); - assert (tmp >= 0); - assert (tmp <= chan->frag_number); - while (tmp == 0) { - if (nonblock || !chan->is_enabled) - return -EAGAIN; + add_wait_queue(&chan->wait, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + tmp = atomic_read (&chan->n_frags); + assert (tmp >= 0); + assert (tmp <= chan->frag_number); + if (tmp) + break; + if (nonblock || !chan->is_active) { + ret = -EAGAIN; + break; + } + + up(&card->syscall_sem); DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record); - interruptible_sleep_on (&chan->wait); + schedule(); - if (signal_pending (current)) - return -ERESTARTSYS; + ret = via_syscall_down (card, nonblock); + if (ret) + break; - tmp = atomic_read (&chan->n_frags); + if (signal_pending (current)) { + ret = -ERESTARTSYS; + break; + } } + set_current_state(TASK_RUNNING); + remove_wait_queue(&chan->wait, &wait); + if (ret) + goto out; /* Now that we have at least one fragment we can write to, fill the buffer * as much as possible with data from userspace. @@ -2152,8 +2232,10 @@ handle_one_block: size = (count < slop_left) ? count : slop_left; if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len, - userbuf, size)) - return -EFAULT; + userbuf, size)) { + ret = -EFAULT; + goto out; + } count -= size; chan->slop_len += size; @@ -2264,7 +2346,8 @@ out: static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait) { struct via_info *card; - unsigned int mask = 0, rd, wr; + struct via_channel *chan; + unsigned int mask = 0; DPRINTK ("ENTER\n"); @@ -2272,28 +2355,21 @@ static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wa card = file->private_data; assert (card != NULL); - rd = (file->f_mode & FMODE_READ); - wr = (file->f_mode & FMODE_WRITE); - - if (wr && (atomic_read (&card->ch_out.n_frags) == 0)) { - assert (card->ch_out.is_active); - poll_wait(file, &card->ch_out.wait, wait); - } - if (rd) { - /* XXX is it ok, spec-wise, to start DMA here? */ - if (!card->ch_in.is_active) { - via_chan_set_buffering(card, &card->ch_in, -1); - via_chan_buffer_init(card, &card->ch_in); - } - via_chan_maybe_start (&card->ch_in); - if (atomic_read (&card->ch_in.n_frags) == 0) - poll_wait(file, &card->ch_in.wait, wait); + if (file->f_mode & FMODE_READ) { + chan = &card->ch_in; + if (sg_active (chan->iobase)) + poll_wait(file, &chan->wait, wait); + if (atomic_read (&chan->n_frags) > 0) + mask |= POLLIN | POLLRDNORM; } - if (wr && ((atomic_read (&card->ch_out.n_frags) > 0) || !card->ch_out.is_active)) - mask |= POLLOUT | POLLWRNORM; - if (rd && (atomic_read (&card->ch_in.n_frags) > 0)) - mask |= POLLIN | POLLRDNORM; + if (file->f_mode & FMODE_WRITE) { + chan = &card->ch_out; + if (sg_active (chan->iobase)) + poll_wait(file, &chan->wait, wait); + if (atomic_read (&chan->n_frags) > 0) + mask |= POLLOUT | POLLWRNORM; + } DPRINTK ("EXIT, returning %u\n", mask); return mask; @@ -2315,6 +2391,9 @@ static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wa static int via_dsp_drain_playback (struct via_info *card, struct via_channel *chan, int nonblock) { + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + DPRINTK ("ENTER, nonblock = %d\n", nonblock); if (chan->slop_len > 0) @@ -2325,10 +2404,16 @@ static int via_dsp_drain_playback (struct via_info *card, via_chan_maybe_start (chan); - while (atomic_read (&chan->n_frags) < chan->frag_number) { + add_wait_queue(&chan->wait, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + if (atomic_read (&chan->n_frags) >= chan->frag_number) + break; + if (nonblock) { DPRINTK ("EXIT, returning -EAGAIN\n"); - return -EAGAIN; + ret = -EAGAIN; + break; } #ifdef VIA_DEBUG @@ -2357,14 +2442,22 @@ static int via_dsp_drain_playback (struct via_info *card, printk (KERN_ERR "sleeping but not active\n"); #endif + up(&card->syscall_sem); + DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags)); - interruptible_sleep_on (&chan->wait); + schedule(); + + if ((ret = via_syscall_down (card, nonblock))) + break; if (signal_pending (current)) { DPRINTK ("EXIT, returning -ERESTARTSYS\n"); - return -ERESTARTSYS; + ret = -ERESTARTSYS; + break; } } + set_current_state(TASK_RUNNING); + remove_wait_queue(&chan->wait, &wait); #ifdef VIA_DEBUG { @@ -2392,8 +2485,8 @@ static int via_dsp_drain_playback (struct via_info *card, #endif out: - DPRINTK ("EXIT, returning 0\n"); - return 0; + DPRINTK ("EXIT, returning %d\n", ret); + return ret; } @@ -2695,7 +2788,6 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, DPRINTK ("DSP_RESET\n"); if (rd) { via_chan_clear (card, &card->ch_in); - via_chan_pcm_fmt (&card->ch_in, 1); card->ch_in.frag_number = 0; card->ch_in.frag_size = 0; atomic_set(&card->ch_in.n_frags, 0); @@ -2703,7 +2795,6 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, if (wr) { via_chan_clear (card, &card->ch_out); - via_chan_pcm_fmt (&card->ch_out, 1); card->ch_out.frag_number = 0; card->ch_out.frag_size = 0; atomic_set(&card->ch_out.n_frags, 0); @@ -2712,6 +2803,11 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, rc = 0; break; + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + rc = 0; + break; + /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */ case SNDCTL_DSP_GETCAPS: DPRINTK ("DSP_GETCAPS\n"); @@ -2812,6 +2908,15 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, break; + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if ((file->f_mode & FMODE_READ) && card->ch_in.is_enabled) + val |= PCM_ENABLE_INPUT; + if ((file->f_mode & FMODE_WRITE) && card->ch_out.is_enabled) + val |= PCM_ENABLE_OUTPUT; + rc = put_user(val, (int *)arg); + break; + /* Enable full duplex. Since we do this as soon as we are opened * with O_RDWR, this is mainly a no-op that always returns success. */ @@ -2834,7 +2939,7 @@ static int via_dsp_ioctl (struct inode *inode, struct file *file, rc = via_chan_set_buffering(card, &card->ch_in, val); if (wr) - rc = via_chan_set_buffering(card, &card->ch_out, val); + rc = via_chan_set_buffering(card, &card->ch_out, val); DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n", val & 0xFFFF, @@ -2952,7 +3057,7 @@ match: via_chan_pcm_fmt (chan, 0); via_set_rate (&card->ac97, chan, 44100); } else { - via_chan_pcm_fmt (chan, 0); + via_chan_pcm_fmt (chan, 1); via_set_rate (&card->ac97, chan, 8000); } } @@ -3127,7 +3232,7 @@ static int __init via_init_one (struct pci_dev *pdev, const struct pci_device_id pci_read_config_byte (pdev, 0x43, &r43); card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2); } - + card->midi_info.irq = -pdev->irq; if (probe_uart401(& card->midi_info, THIS_MODULE)) { @@ -3181,10 +3286,10 @@ static void __exit via_remove_one (struct pci_dev *pdev) #ifdef CONFIG_MIDI_VIA82CXXX if (card->midi_info.io_base) - unload_uart401(&card->midi_info); + unload_uart401(&card->midi_info); #endif - via_interrupt_cleanup (card); + free_irq (card->pdev->irq, card); via_card_cleanup_proc (card); via_dsp_cleanup (card); via_ac97_cleanup (card); @@ -3197,8 +3302,8 @@ static void __exit via_remove_one (struct pci_dev *pdev) pci_set_drvdata (pdev, NULL); pci_release_regions (pdev); - pci_set_power_state (pdev, 3); /* ...zzzzzz */ pci_disable_device (pdev); + pci_set_power_state (pdev, 3); /* ...zzzzzz */ DPRINTK ("EXIT\n"); return; diff --git a/drivers/sound/vwsnd.c b/drivers/sound/vwsnd.c index 54737d825a7a..ab128f68357b 100644 --- a/drivers/sound/vwsnd.c +++ b/drivers/sound/vwsnd.c @@ -3449,6 +3449,7 @@ static struct address_info the_hw_config = { MODULE_DESCRIPTION("SGI Visual Workstation sound module"); MODULE_AUTHOR("Bob Miller "); +MODULE_LICENSE("GPL"); static int __init init_vwsnd(void) { diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index a43dc3543c29..2ab9a0917135 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -1,6 +1,6 @@ /* Driver for Freecom USB/IDE adaptor * - * $Id: freecom.c,v 1.15 2001/06/27 23:50:28 mdharm Exp $ + * $Id: freecom.c,v 1.18 2001/11/04 13:01:17 mdharm Exp $ * * Freecom v0.1: * @@ -132,6 +132,12 @@ static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { + US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred); + + /* End this if we're done */ + if (transfer_amount == total_transferred) + break; + /* transfer the lesser of the next buffer or the * remaining data */ if (transfer_amount - total_transferred >= @@ -139,10 +145,12 @@ static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer result = usb_stor_transfer_partial(us, sg[i].address, sg[i].length); total_transferred += sg[i].length; - } else + } else { result = usb_stor_transfer_partial(us, sg[i].address, transfer_amount - total_transferred); + total_transferred += transfer_amount - total_transferred; + } /* if we get an error, end the loop here */ if (result) @@ -158,7 +166,7 @@ static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer srb->result = result; } - +#if 0 /* Write a value to an ide register. */ static int freecom_ide_write (struct us_data *us, int reg, int value) @@ -255,6 +263,7 @@ freecom_ide_read (struct us_data *us, int reg, int *value) return USB_STOR_TRANSPORT_GOOD; } +#endif static int freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, @@ -470,13 +479,15 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP("Device indicates that it has %d bytes available\n", le16_to_cpu (fst->Count)); - /* Find the length we desire to read. It is the lesser of the SCSI - * layer's requested length, and the length the device claims to - * have available. */ + /* Find the length we desire to read. */ length = usb_stor_transfer_length (srb); US_DEBUGP("SCSI requested %d\n", length); - if (length > le16_to_cpu (fst->Count)) - length = le16_to_cpu (fst->Count); + + /* verify that this amount is legal */ + if (length > srb->request_bufflen) { + length = srb->request_bufflen; + US_DEBUGP("Truncating request to match buffer length: %d\n", length); + } /* What we do now depends on what direction the data is supposed to * move in. */ @@ -522,7 +533,6 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) if (result != USB_STOR_TRANSPORT_GOOD) return result; -#if 1 US_DEBUGP("FCM: Waiting for status\n"); result = usb_stor_bulk_msg (us, fst, ipipe, FCM_PACKET_LENGTH, &partial); @@ -540,7 +550,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP("Drive seems still hungry\n"); return USB_STOR_TRANSPORT_FAILED; } -#endif + US_DEBUGP("Transfer happy\n"); break; @@ -570,8 +580,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) int freecom_init (struct us_data *us) { - int result, value; - int counter; + int result; char buffer[33]; /* Allocate a buffer for us. The upper usb transport code will @@ -591,42 +600,29 @@ freecom_init (struct us_data *us) buffer[32] = '\0'; US_DEBUGP("String returned from FC init is: %s\n", buffer); - result = freecom_ide_write (us, 0x06, 0xA0); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - result = freecom_ide_write (us, 0x01, 0x00); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + /* Special thanks to the people at Freecom for providing me with + * this "magic sequence", which they use in their Windows and MacOS + * drivers to make sure that all the attached perhiperals are + * properly reset. + */ - counter = 50; - do { - result = freecom_ide_read (us, 0x07, &value); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - if (counter-- < 0) { - US_DEBUGP("Timeout in freecom"); - return USB_STOR_TRANSPORT_ERROR; - } - } while ((value & 0x80) != 0); + /* send reset */ + result = usb_control_msg(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, 0), + 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); + US_DEBUGP("result from activate reset is %d\n", result); - result = freecom_ide_write (us, 0x07, 0x08); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + /* wait 250ms */ + mdelay(250); - counter = 50; - do { - result = freecom_ide_read (us, 0x07, &value); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - if (counter-- < 0) { - US_DEBUGP("Timeout in freecom"); - return USB_STOR_TRANSPORT_ERROR; - } - } while ((value & 0x80) != 0); + /* clear reset */ + result = usb_control_msg(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, 0), + 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); + US_DEBUGP("result from clear reset is %d\n", result); - result = freecom_ide_write (us, 0x08, 0x08); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + /* wait 3 seconds */ + mdelay(3 * 1000); return USB_STOR_TRANSPORT_GOOD; } diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 3d8a52aa675f..75d7a8ff3064 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * SCSI layer glue code * - * $Id: scsiglue.c,v 1.22 2001/09/02 04:29:27 mdharm Exp $ + * $Id: scsiglue.c,v 1.23 2001/10/15 07:02:32 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 07c061bd7d8c..7235400dd89c 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -1,6 +1,6 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * - * $Id: sddr09.c,v 1.19 2001/09/02 06:07:20 mdharm Exp $ + * $Id: sddr09.c,v 1.21 2001/11/06 03:18:36 mdharm Exp $ * * SDDR09 driver v0.1: * diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 34564297e152..4b6dd33be9ed 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.40 2001/08/18 08:37:46 mdharm Exp $ + * $Id: transport.c,v 1.41 2001/10/15 07:02:32 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index a1751f196fcf..dc6a5ca72766 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.67 2001/07/29 23:41:52 mdharm Exp $ + * $Id: usb.c,v 1.68 2001/10/15 07:02:33 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index 88b087622dee..a3556dfe7a2c 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -2623,7 +2623,7 @@ static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io uhci->dev = dev; uhci->io_addr = io_addr; uhci->io_size = io_size; - dev->driver_data = uhci; + pci_set_drvdata(dev, uhci); #ifdef CONFIG_PROC_FS uhci->num = uhci_num++; @@ -2931,7 +2931,7 @@ static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device static void __devexit uhci_pci_remove(struct pci_dev *dev) { - struct uhci *uhci = dev->driver_data; + struct uhci *uhci = pci_get_drvdata(dev); if (uhci->bus->root_hub) usb_disconnect(&uhci->bus->root_hub); @@ -2956,14 +2956,14 @@ static void __devexit uhci_pci_remove(struct pci_dev *dev) #ifdef CONFIG_PM static int uhci_pci_suspend(struct pci_dev *dev, u32 state) { - suspend_hc((struct uhci *) dev->driver_data); + suspend_hc((struct uhci *) pci_get_drvdata(dev)); return 0; } static int uhci_pci_resume(struct pci_dev *dev) { - reset_hc((struct uhci *) dev->driver_data); - start_hc((struct uhci *) dev->driver_data); + reset_hc((struct uhci *) pci_get_drvdata(dev)); + start_hc((struct uhci *) pci_get_drvdata(dev)); return 0; } #endif diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index eff3386b94bf..96787e4a3972 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -2372,7 +2372,7 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base) ohci->regs = mem_base; ohci->ohci_dev = dev; - dev->driver_data = ohci; + pci_set_drvdata(dev, ohci); INIT_LIST_HEAD (&ohci->ohci_hcd_list); list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); @@ -2411,7 +2411,7 @@ static void hc_release_ohci (ohci_t * ohci) free_irq (ohci->irq, ohci); ohci->irq = -1; } - ohci->ohci_dev->driver_data = 0; + pci_set_drvdata(ohci->ohci_dev, NULL); usb_deregister_bus (ohci->bus); usb_free_bus (ohci->bus); @@ -2600,7 +2600,7 @@ ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) static void __devexit ohci_pci_remove (struct pci_dev *dev) { - ohci_t *ohci = (ohci_t *) dev->driver_data; + ohci_t *ohci = pci_get_drvdata(dev); dbg ("remove %s controller usb-%s%s%s", hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), @@ -2636,7 +2636,7 @@ ohci_pci_remove (struct pci_dev *dev) static int ohci_pci_suspend (struct pci_dev *dev, u32 state) { - ohci_t *ohci = (ohci_t *) dev->driver_data; + ohci_t *ohci = pci_get_drvdata(dev); unsigned long flags; u16 cmd; @@ -2715,7 +2715,7 @@ ohci_pci_suspend (struct pci_dev *dev, u32 state) static int ohci_pci_resume (struct pci_dev *dev) { - ohci_t *ohci = (ohci_t *) dev->driver_data; + ohci_t *ohci = pci_get_drvdata(dev); int temp; unsigned long flags; diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c index 73524b31c253..f7df533226ef 100644 --- a/drivers/usb/usb-uhci.c +++ b/drivers/usb/usb-uhci.c @@ -2848,7 +2848,7 @@ _static void start_hc (uhci_t *s) _static void __devexit uhci_pci_remove (struct pci_dev *dev) { - uhci_t *s = (uhci_t*) dev->driver_data; + uhci_t *s = pci_get_drvdata(dev); struct usb_device *root_hub = s->bus->root_hub; s->running = 0; // Don't allow submit_urb @@ -2895,14 +2895,14 @@ _static int __init uhci_start_usb (uhci_t *s) _static int uhci_pci_suspend (struct pci_dev *dev, u32 state) { - reset_hc((uhci_t *) dev->driver_data); + reset_hc((uhci_t *) pci_get_drvdata(dev)); return 0; } _static int uhci_pci_resume (struct pci_dev *dev) { - start_hc((uhci_t *) dev->driver_data); + start_hc((uhci_t *) pci_get_drvdata(dev)); return 0; } #endif @@ -3006,7 +3006,7 @@ _static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_ } //chain new uhci device into global list - dev->driver_data = s; + pci_set_drvdata(dev, s); devs=s; return 0; diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index c0c2d1361622..266e2bf810f3 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -312,10 +312,10 @@ static void hga_blank(int blank_mode) static int __init hga_card_detect(void) { int count=0; - u16 *p, p_save; - u16 *q, q_save; + unsigned char p, p_save; + unsigned char q, q_save; - hga_vram_base = VGA_MAP_MEM(0xb0000); + hga_vram_base = 0xb0000; hga_vram_len = 0x08000; if (request_region(0x3b0, 12, "hgafb")) @@ -325,14 +325,14 @@ static int __init hga_card_detect(void) /* do a memory check */ - p = (u16 *) hga_vram_base; - q = (u16 *) (hga_vram_base + 0x01000); + p = hga_vram_base; + q = hga_vram_base + 0x01000; - p_save = scr_readw(p); q_save = scr_readw(q); + p_save = isa_readw(p); q_save = isa_readw(q); - scr_writew(0xaa55, p); if (scr_readw(p) == 0xaa55) count++; - scr_writew(0x55aa, p); if (scr_readw(p) == 0x55aa) count++; - scr_writew(p_save, p); + isa_writew(0xaa55, p); if (isa_readw(p) == 0xaa55) count++; + isa_writew(0x55aa, p); if (isa_readw(p) == 0x55aa) count++; + isa_writew(p_save, p); if (count != 2) { return 0; @@ -717,7 +717,7 @@ int __init hgafb_init(void) if (!nologo) hga_show_logo(); #endif /* MODULE */ - hga_fix.smem_start = hga_vram_base; + hga_fix.smem_start = VGA_MAP_MEM(hga_vram_base); hga_fix.smem_len = hga_vram_len; disp.var = hga_default_var; @@ -795,7 +795,7 @@ int __init hgafb_setup(char *options) if (!options || !*options) return 0; - while (this_opt = strsep(&options, ",")) { + while ((this_opt = strsep(&options, ","))) { if (!strncmp(this_opt, "font:", 5)) strcpy(fb_info.fontname, this_opt+5); } diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 315ff4fd620f..6f7c697adc20 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -1950,7 +1950,7 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) init_imstt(p); - pdev->driver_data = p; + pci_set_drvdata(pdev, p); return 0; } @@ -1958,7 +1958,7 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static void __devexit imsttfb_remove(struct pci_dev *pdev) { - struct fb_info_imstt *p = (struct fb_info_imstt *)pdev->driver_data; + struct fb_info_imstt *p = pci_get_drvdata(pdev); unregister_framebuffer(&p->info); iounmap(p->cmap_regs); diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index 27ee97cc7740..59fe2b984710 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -1,3 +1,15 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2001 Petr Vandrovec + * + * Version: 1.51 2001/01/19 + * + * See matroxfb_base.c for contributors. + * + */ + #include "matroxfb_base.h" #include "matroxfb_maven.h" #include @@ -282,8 +294,8 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) { return NULL; matroxfb_DAC_lock_irqsave(flags); - matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00); - matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0xFF); + matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0xFF); + matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0x00); matroxfb_DAC_unlock_irqrestore(flags); memset(m2info, 0, sizeof(*m2info)); @@ -343,7 +355,7 @@ static void __exit i2c_matroxfb_exit(void) { matroxfb_unregister_driver(&i2c_matroxfb); } -MODULE_AUTHOR("(c) 1999 Petr Vandrovec "); +MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec "); MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards"); module_init(i2c_matroxfb_init); diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index c8578f7efac0..b0a12c07e1eb 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -321,7 +321,8 @@ void DAC1064_global_restore(CPMINFO const struct matrox_hw_state* hw) { outDAC1064(PMINFO 0x20, 0x04); outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type)); if (ACCESS_FBINFO(devflags.g450dac)) { - outDAC1064(PMINFO M1064_X8B, 0xCC); /* only matrox know... */ + outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC); /* only matrox know... */ + outDAC1064(PMINFO M1064_XPWRCTRL, 0x1F); /* powerup everything */ outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]); } } diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h index e072657b3b1e..62cde7919e9d 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.h +++ b/drivers/video/matrox/matroxfb_DAC1064.h @@ -138,12 +138,14 @@ void DAC1064_global_restore(CPMINFO const struct matrox_hw_state*); #define M1064_XTVO_DATA 0x88 #define M1064_XOUTPUTCONN 0x8A -#define M1064_X8B 0x8B +#define M1064_XSYNCCTRL 0x8B #define M1064_XPIXPLL2STAT 0x8C #define M1064_XPIXPLL2P 0x8D #define M1064_XPIXPLL2N 0x8E #define M1064_XPIXPLL2M 0x8F +#define M1064_XPWRCTRL 0xA0 + enum POS1064 { POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL, POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE, diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 3e4a7c6e4a0e..ec543f5728ce 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -988,8 +988,6 @@ static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, #undef minfo } -static int matroxfb_switch(int con, struct fb_info *info); - static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank) { unsigned int sts1; @@ -1183,7 +1181,7 @@ static struct fb_ops matroxfb_ops = { fb_ioctl: matroxfb_ioctl, }; -static int matroxfb_switch(int con, struct fb_info *info) +int matroxfb_switch(int con, struct fb_info *info) { #define minfo ((struct matrox_fb_info*)info) struct fb_cmap* cmap; @@ -1414,11 +1412,11 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4 #define DEVF_VIDEO64BIT 0x0001 #define DEVF_SWAPS 0x0002 #define DEVF_SRCORG 0x0004 -/* #define DEVF_recycled 0x0008 */ +#define DEVF_BOTHDACS 0x0008 /* put CRTC1 on both outputs by default */ #define DEVF_CROSS4MB 0x0010 #define DEVF_TEXT4B 0x0020 #define DEVF_DDC_8_2 0x0040 -/* #define DEVF_recycled 0x0080 */ +#define DEVF_G550DAC 0x0080 #define DEVF_SUPPORT32MB 0x0100 #define DEVF_ANY_VXRES 0x0200 #define DEVF_TEXT16B 0x0400 @@ -1434,6 +1432,7 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4 #define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2) /* if you'll find how to drive DFP... */ #define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG) +#define DEVF_G550 (DEVF_G450 | DEVF_G550DAC | DEVF_BOTHDACS) static struct board { unsigned short vendor, device, rev, svid, sid; @@ -1477,13 +1476,13 @@ static struct board { "Mystique 220 (PCI)"}, #endif #ifdef CONFIG_FB_MATROX_G100 - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI, DEVF_G100, 230000, &vbG100, "MGA-G100 (PCI)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, 0, 0, DEVF_G100, 230000, @@ -1561,24 +1560,30 @@ static struct board { 230000, &vbG200, "G200 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0x80, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP, DEVF_G400, 360000, &vbG400, "Millennium G400 MAX (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0x80, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, 0, 0, DEVF_G400, 300000, &vbG400, "G400 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0xFF, 0, 0, DEVF_G450, 500000, /* ??? vco goes up to 900MHz... */ &vbG400, - "G450 (AGP)"}, + "G450"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, 0xFF, + 0, 0, + DEVF_G550, + 500000, + &vbG400, + "G550"}, #endif {0, 0, 0xFF, 0, 0, @@ -1641,8 +1646,18 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){ if (dfp) ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP; } + if (b->flags & DEVF_BOTHDACS) { +#ifdef CONFIG_FB_MATROX_G450 + ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; + ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_SECONDARY; +#else + printk(KERN_INFO "Only digital output of G550 is now working (in analog mode). Enable G450 support in\n"); + printk(KERN_INFO "kernel configuration if you have analog monitor connected to G550 analog output.\n"); +#endif + } ACCESS_FBINFO(devflags.dfp_type) = dfp_type; ACCESS_FBINFO(devflags.g450dac) = b->flags & DEVF_G450DAC; + ACCESS_FBINFO(devflags.g550dac) = b->flags & DEVF_G550DAC; ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode); ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode); @@ -2060,7 +2075,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm ACCESS_FBINFO(pcidev) = pdev; ACCESS_FBINFO(dead) = 0; ACCESS_FBINFO(usecount) = 0; - pdev->driver_data = MINFO; + pci_set_drvdata(pdev, MINFO); /* CMDLINE */ memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname))); /* DEVFLAGS */ @@ -2122,7 +2137,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm static void pci_remove_matrox(struct pci_dev* pdev) { struct matrox_fb_info* minfo; - minfo = pdev->driver_data; + minfo = pci_get_drvdata(pdev); matroxfb_remove(PMINFO 1); } @@ -2140,7 +2155,7 @@ static struct pci_device_id matroxfb_devices[] __devinitdata = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, #endif #ifdef CONFIG_FB_MATROX_G100 - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -2148,7 +2163,9 @@ static struct pci_device_id matroxfb_devices[] __devinitdata = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, #endif {0, 0, @@ -2638,6 +2655,7 @@ int __init init_module(void){ module_exit(matrox_done); EXPORT_SYMBOL(matroxfb_register_driver); EXPORT_SYMBOL(matroxfb_unregister_driver); +EXPORT_SYMBOL(matroxfb_switch); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index b402d17fb09c..75323dcabe3a 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -146,21 +146,6 @@ #ifndef PCI_SS_VENDOR_ID_MATROX #define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX #endif -#ifndef PCI_DEVICE_ID_MATROX_G200_PCI -#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G200_AGP -#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G100 -#define PCI_DEVICE_ID_MATROX_G100 0x1000 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G100_AGP -#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G400_AGP -#define PCI_DEVICE_ID_MATROX_G400_AGP 0x0525 -#endif #ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP #define PCI_SS_ID_MATROX_GENERIC 0xFF00 @@ -533,6 +518,7 @@ struct matrox_fb_info { /* 0 except for 6MB Millenium */ int memtype; int g450dac; + int g550dac; int dfp_type; } devflags; struct display_switch dispsw; diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 415deeb3b4c6..ac17dbb5d226 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -130,14 +130,31 @@ static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) tmp |= 0x00100000; /* connect CRTC2 to DAC */ } + if (mt->interlaced) { + tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */ + mt->VDisplay >>= 1; + mt->VSyncStart >>= 1; + mt->VSyncEnd >>= 1; + mt->VTotal >>= 1; + } mga_outl(0x3C10, tmp | 0x10000000); /* depth and so on... 0x10000000 is VIDRST polarity */ mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8)); mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8)); mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1)); mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1)); mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */ - mga_outl(0x3C28, pos); /* vmemory start */ - mga_outl(0x3C40, p->var.xres_virtual * (p->var.bits_per_pixel >> 3)); + { + u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3); + if (mt->interlaced) { + /* field #0 is smaller, so... */ + mga_outl(0x3C2C, pos); /* field #1 vmemory start */ + mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */ + linelen <<= 1; + } else { + mga_outl(0x3C28, pos); /* vmemory start */ + } + mga_outl(0x3C40, linelen); + } tmp = 0x0FFF0000; /* line compare */ if (mt->sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x00000100; @@ -155,11 +172,20 @@ static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info, static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, struct fb_var_screeninfo* var) { unsigned int pos; + unsigned int linelen; + unsigned int pixelsize; #define minfo (m2info->primary_dev) - pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3; + pixelsize = var->bits_per_pixel >> 3; + linelen = var->xres_virtual * pixelsize; + pos = var->yoffset * linelen + var->xoffset * pixelsize; pos += m2info->video.offbase; - mga_outl(0x3C28, pos); + if (var->vmode & FB_VMODE_INTERLACED) { + mga_outl(0x3C2C, pos); + mga_outl(0x3C28, pos + linelen); + } else { + mga_outl(0x3C28, pos); + } #undef minfo } @@ -700,15 +726,13 @@ static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) { m2info->mmio.len = ACCESS_FBINFO(mmio.len); /* - * If we have two outputs, connect CRTC2 to it... + * If we have unused output, connect CRTC2 to it... */ - if (ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) { + if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && + !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) && + !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) { ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY; - ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY; - if (ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP) { - ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP; - ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_DFP; - } + ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP; } matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon); @@ -815,6 +839,7 @@ static void matroxfb_crtc2_exit(void) { MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec "); MODULE_DESCRIPTION("Matrox G400 CRTC2 driver"); +MODULE_LICENSE("GPL"); module_init(matroxfb_crtc2_init); module_exit(matroxfb_crtc2_exit); /* we do not have __setup() yet */ diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c index c05be34212a4..f3705bf6fca2 100644 --- a/drivers/video/matrox/matroxfb_g450.c +++ b/drivers/video/matrox/matroxfb_g450.c @@ -1,3 +1,15 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2001 Petr Vandrovec + * + * Version: 1.51 2001/01/19 + * + * See matroxfb_base.c for contributors. + * + */ + #include "matroxfb_g450.h" #include "matroxfb_misc.h" #include "matroxfb_DAC1064.h" @@ -31,36 +43,53 @@ static const struct matrox_pll_features maven_pll = { 3 }; +static const struct matrox_pll_features g550_pll = { + 135000, + 27000, + 4, 127, + 0, 9, + 3 +}; + static void DAC1064_calcclock(unsigned int freq, unsigned int fmax, - unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int timmings) { unsigned int fvco; unsigned int p; - fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); - /* 0 => 100 ... 275 MHz - 1 => 243 ... 367 MHz - 2 => 320 ... 475 MHz - 3 => 453 ... 556 MHz - 4 => 540 ... 594 MHz - 5 => 588 ... 621 MHz - 6 => 626 ... 637 MHz - 7 => 631 ... 642 MHz - - As you can see, never choose frequency > 621 MHz, there is unavailable gap... - Just to be sure, currently driver uses 110 ... 500 MHz range. - */ - if (fvco <= 260000) - ; - else if (fvco <= 350000) - p |= 0x08; - else if (fvco <= 460000) - p |= 0x10; - else if (fvco <= 550000) - p |= 0x18; - else if (fvco <= 590000) - p |= 0x20; - else - p |= 0x28; + switch (timmings) { + default: + fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); + /* 0 => 100 ... 275 MHz + 1 => 243 ... 367 MHz + 2 => 320 ... 475 MHz + 3 => 453 ... 556 MHz + 4 => 540 ... 594 MHz + 5 => 588 ... 621 MHz + 6 => 626 ... 637 MHz + 7 => 631 ... 642 MHz + + As you can see, never choose frequency > 621 MHz, there is unavailable gap... + Just to be sure, currently driver uses 110 ... 500 MHz range. + */ + if (fvco <= 260000) + ; + else if (fvco <= 350000) + p |= 0x08; + else if (fvco <= 460000) + p |= 0x10; + else if (fvco <= 550000) + p |= 0x18; + else if (fvco <= 590000) + p |= 0x20; + else + p |= 0x28; + break; + case 1: + fvco = matroxfb_PLL_calcclock(&g550_pll, freq, fmax, in, feed, &p); + /* p |= 0x00; */ + break; + } *post = p; return; } @@ -70,7 +99,7 @@ static inline int matroxfb_g450_compute_timming(struct matroxfb_g450_info* m2inf struct mavenregs* m) { unsigned int a, b, c; - DAC1064_calcclock(mt->pixclock, 500000, &a, &b, &c); + DAC1064_calcclock(mt->pixclock, 300000, &a, &b, &c, m2info->timmings); m->regs[0x80] = a; m->regs[0x81] = b; m->regs[0x82] = c; @@ -139,6 +168,7 @@ static int matroxfb_g450_connect(struct matroxfb_g450_info* m2info) { ACCESS_FBINFO(altout.output) = &matroxfb_g450_altout; up_write(&ACCESS_FBINFO(altout.lock)); ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; + matroxfb_switch(ACCESS_FBINFO(currcon), (struct fb_info*)MINFO); return 0; } @@ -171,6 +201,11 @@ static void* matroxfb_g450_probe(struct matrox_fb_info* minfo) { } memset(m2info, 0, sizeof(*m2info)); m2info->primary_dev = MINFO; + if (ACCESS_FBINFO(devflags.g550dac)) { + m2info->timmings = 1; + } else { + m2info->timmings = 0; + } if (matroxfb_g450_connect(m2info)) { kfree(m2info); printk(KERN_ERR "matroxfb_g450: G450 DAC failed to initialize\n"); @@ -198,7 +233,8 @@ static void matroxfb_g450_exit(void) { matroxfb_unregister_driver(&g450); } -MODULE_AUTHOR("(c) 2000 Petr Vandrovec "); +MODULE_AUTHOR("(c) 2000-2001 Petr Vandrovec "); MODULE_DESCRIPTION("Matrox G450 secondary output driver"); +MODULE_LICENSE("GPL"); module_init(matroxfb_g450_init); module_exit(matroxfb_g450_exit); diff --git a/drivers/video/matrox/matroxfb_g450.h b/drivers/video/matrox/matroxfb_g450.h index 51aefca7e1eb..e9e4acc1ef30 100644 --- a/drivers/video/matrox/matroxfb_g450.h +++ b/drivers/video/matrox/matroxfb_g450.h @@ -6,6 +6,7 @@ struct matroxfb_g450_info { struct matrox_fb_info* primary_dev; + unsigned int timmings; }; #endif /* __MATROXFB_MAVEN_H__ */ diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 57b8222936b7..cfee9249decc 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -1,3 +1,15 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2001 Petr Vandrovec + * + * Version: 1.51 2001/01/19 + * + * See matroxfb_base.c for contributors. + * + */ + #include "matroxfb_maven.h" #include "matroxfb_misc.h" #include "matroxfb_DAC1064.h" @@ -1030,8 +1042,9 @@ static void matroxfb_maven_exit(void) { i2c_del_driver(&maven_driver); } -MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec "); +MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec "); MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); +MODULE_LICENSE("GPL"); module_init(matroxfb_maven_init); module_exit(matroxfb_maven_exit); /* we do not have __setup() yet */ diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index 8669fb7fcf9c..1c46f42157d7 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -657,3 +657,7 @@ EXPORT_SYMBOL(matroxfb_fastfont_tryset); /* accel */ EXPORT_SYMBOL(matroxfb_fastfont_init); /* DAC1064, Ti3026 */ EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */ EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */ + +MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec "); +MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c index 162f60a4c090..27c32ae6a1c0 100644 --- a/drivers/video/radeonfb.c +++ b/drivers/video/radeonfb.c @@ -889,7 +889,7 @@ static int radeonfb_pci_register (struct pci_dev *pdev, rinfo->palette[i].blue = default_blu[j]; } - pdev->driver_data = rinfo; + pci_set_drvdata(pdev, rinfo); if (register_framebuffer ((struct fb_info *) rinfo) < 0) { printk ("radeonfb: could not register framebuffer\n"); @@ -930,7 +930,7 @@ static int radeonfb_pci_register (struct pci_dev *pdev, static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) { - struct radeonfb_info *rinfo = pdev->driver_data; + struct radeonfb_info *rinfo = pci_get_drvdata(pdev); if (!rinfo) return; diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index c9c1fe6581e3..524c8e3d850a 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c @@ -660,6 +660,7 @@ static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con, /* XXX FIXME - should try to pick best refresh rate */ /* for now, pick closest dot-clock within 3MHz*/ +#error "Floating point not allowed in kernel" req_dot = (int)((1.0e3/1.0e6) / (1.0e-12 * (float)var->pixclock)); printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n", var->pixclock, req_dot); @@ -954,6 +955,8 @@ static void sgivwfbcon_blank(int blank, struct fb_info *info) } #ifdef MODULE +MODULE_LICENSE("GPL"); + int init_module(void) { return sgivwfb_init(); diff --git a/drivers/video/sis/300vtbl.h b/drivers/video/sis/300vtbl.h new file mode 100644 index 000000000000..8103ec200c08 --- /dev/null +++ b/drivers/video/sis/300vtbl.h @@ -0,0 +1,1522 @@ +typedef struct _SiS300_StStruct { + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; +} SiS300_StStruct; + +SiS300_StStruct SiS300_SModeIDTable[] = +{ + {0x01, 0x9208, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x1210, 0x14, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x01, 0x1010, 0x17, 0x02, 0x02, 0x00, 0x00, 0x00}, + {0x03, 0x8208, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x03, 0x0210, 0x16, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x00, 0x00}, + {0x05, 0x9209, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x06, 0x8209, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x07, 0x0000, 0x07, 0x03, 0x03, 0x00, 0x00, 0x00}, + {0x07, 0x0000, 0x19, 0x02, 0x02, 0x00, 0x00, 0x00}, + {0x0d, 0x920a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x0e, 0x820a, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x0f, 0x0202, 0x11, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x10, 0x0212, 0x12, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x11, 0x0212, 0x1a, 0x04, 0x04, 0x00, 0x00, 0x00}, + {0x12, 0x0212, 0x1b, 0x04, 0x04, 0x00, 0x00, 0x00}, + {0x13, 0x021b, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x12, 0x0210, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x12, 0x0210, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0xff, 0, 0, 0, 0, 0, 0, 0} +}; + +typedef struct _SiS300_StandTableStruct { + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} SiS300_StandTableStruct; + +SiS300_StandTableStruct SiS300_StandTable[] = { + {0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff}}, + {0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff}}, + {0x50, 0x18, 0x08, 0x4000, + {0x01, 0x01, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, + 0xff}, + {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x01, 0x00, 0x01, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0xff}}, + {0x50, 0x18, 0x0e, 0x1000, + {0x00, 0x03, 0x00, 0x03}, + 0xa6, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff}}, +/* MDA_DAC*/ + {0x00, 0x00, 0x00, 0x0000, + {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}}, +/* CGA_DAC*/ + {0x00, 0x10, 0x04, 0x0114, + {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}}, +/* EGA_DAC*/ + {0x00, 0x10, 0x04, 0x0114, + {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}}, +/* VGA_DAC*/ + {0x00, 0x10, 0x04, 0x0114, + {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, 0x0a08, + {0x0c, 0x0e, 0x10, 0x0b}, + 0x0c, + {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, + 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00, + 0x06}, + {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08, + 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}}, + {0x28, 0x18, 0x08, 0x2000, + {0x09, 0x0f, 0x00, 0x06}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff}}, + {0x50, 0x18, 0x08, 0x4000, + {0x01, 0x0f, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff}}, + {0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff}}, + {0x4a, 0x36, 0x00, 0x00c0, + {0x00, 0x00, 0x00, 0x00}, + 0x00, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3a, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0x00, 0x57, 0x39, 0x00, 0xc0, + 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}}, + {0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa2, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x0b, 0x00, 0x05, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, + 0xff}}, + {0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff}}, + {0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x28, 0x18, 0x10, 0x0800, + {0x08, 0x03, 0x00, 0x02}, + 0x67, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x66, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff}}, + {0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3, + 0xff}, + {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, + 0xff}}, + {0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff}}, + {0x28, 0x18, 0x08, 0x2000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x41, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff}} +}; + +typedef struct _SiS300_ExtStruct { + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_ModeInfo; + USHORT Ext_Point; + USHORT Ext_VESAID; + UCHAR Ext_VESAMEMSize; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR REFindex; +} SiS300_ExtStruct; +SiS300_ExtStruct SiS300_EModeIDTable[] = { + {0x6a, 0x2212, 0x47, 0x3563, 0x0102, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x2e, 0x0a1b, 0x36, 0x3539, 0x0101, 0x08, 0x06, 0x00, 0x00, 0x00, 0x08}, + {0x2f, 0x021b, 0x35, 0x3532, 0x0100, 0x08, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0x30, 0x2a1b, 0x47, 0x3563, 0x0103, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x31, 0x0a1b, 0xad, 0x3630, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x11}, + {0x32, 0x2a1b, 0xae, 0x3637, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x12}, + {0x33, 0x0a1d, 0xad, 0x3630, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x11}, + {0x34, 0x2a1d, 0xae, 0x3637, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x12}, + {0x35, 0x0a1f, 0xad, 0x3630, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x11}, + {0x36, 0x2a1f, 0xae, 0x3637, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x12}, + {0x37, 0x0212, 0x58, 0x358d, 0x0104, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x38, 0x0a1b, 0x58, 0x358d, 0x0105, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x3a, 0x0e3b, 0x69, 0x35be, 0x0107, 0x08, 0x09, 0x00, 0x00, 0x00, 0x1a}, + {0x3c, 0x063b, 0x7a, 0x35d4, 0x0130, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x1e}, + {0x3d, 0x067d, 0x7a, 0x35d4, 0x0131, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x1e}, + {0x40, 0x921c, 0x00, 0x3516, 0x010d, 0x08, 0x00, 0x00, 0x00, 0x00, 0x23}, + {0x41, 0x921d, 0x00, 0x3516, 0x010e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x23}, + {0x43, 0x0a1c, 0x36, 0x3539, 0x0110, 0x08, 0x06, 0x00, 0x00, 0x00, 0x08}, + {0x44, 0x0a1d, 0x36, 0x3539, 0x0111, 0x08, 0x06, 0x00, 0x00, 0x00, 0x08}, + {0x46, 0x2a1c, 0x47, 0x3563, 0x0113, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x47, 0x2a1d, 0x47, 0x3563, 0x0114, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x49, 0x0a3c, 0x58, 0x358d, 0x0116, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x4a, 0x0a3d, 0x58, 0x358d, 0x0117, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x4c, 0x0e7c, 0x69, 0x35be, 0x0119, 0x08, 0x09, 0x00, 0x00, 0x00, 0x1a}, + {0x4d, 0x0e7d, 0x69, 0x35be, 0x011a, 0x08, 0x09, 0x00, 0x00, 0x00, 0x1a}, + {0x50, 0x921b, 0x01, 0x351d, 0x0132, 0x08, 0x01, 0x00, 0x00, 0x00, 0x24}, + {0x51, 0x921b, 0x13, 0x3524, 0x0133, 0x08, 0x03, 0x00, 0x00, 0x00, 0x25}, + {0x52, 0x921b, 0x24, 0x352b, 0x0134, 0x08, 0x04, 0x00, 0x00, 0x00, 0x26}, + {0x56, 0x921d, 0x01, 0x351d, 0x0135, 0x08, 0x01, 0x00, 0x00, 0x00, 0x24}, + {0x57, 0x921d, 0x13, 0x3524, 0x0136, 0x08, 0x03, 0x00, 0x00, 0x00, 0x25}, + {0x58, 0x921d, 0x24, 0x352b, 0x0137, 0x08, 0x04, 0x00, 0x00, 0x00, 0x26}, + {0x59, 0x921b, 0x00, 0x3516, 0x0138, 0x08, 0x00, 0x00, 0x00, 0x00, 0x23}, + {0x5d, 0x021d, 0x35, 0x3532, 0x0139, 0x08, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0x62, 0x0a3f, 0x36, 0x3539, 0x013a, 0x08, 0x06, 0x00, 0x00, 0x00, 0x08}, + {0x63, 0x2a3f, 0x47, 0x3563, 0x013b, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x64, 0x0a7f, 0x58, 0x358d, 0x013c, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x65, 0x0eff, 0x69, 0x35be, 0x013d, 0x08, 0x09, 0x00, 0x00, 0x00, 0x1a}, + {0x66, 0x06ff, 0x7a, 0x35d4, 0x013e, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x1e}, + {0x68, 0x067b, 0x8b, 0x35ef, 0x013f, 0x08, 0x0b, 0x00, 0x00, 0x00, 0x27}, + {0x69, 0x06fd, 0x8b, 0x35ef, 0x0140, 0x08, 0x0b, 0x00, 0x00, 0x00, 0x27}, + {0x6b, 0x07ff, 0x8b, 0x35ef, 0x0000, 0x10, 0x0b, 0x00, 0x00, 0x00, 0x27}, + {0x6c, 0x067b, 0x9c, 0x35f6, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x28}, + {0x6d, 0x06fd, 0x9c, 0x35f6, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x28}, + {0x6e, 0x0e3b, 0x6f, 0x35b2, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x00, 0x29}, + {0x6f, 0x0e7d, 0x6f, 0x35b2, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x00, 0x29}, + {0x7b, 0x0eff, 0x6f, 0x35b2, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x00, 0x29}, + {0x7c, 0x221b, 0xb3, 0x363e, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x2b}, + {0x7d, 0x221d, 0xb3, 0x363e, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x2b}, + {0x7e, 0x223f, 0xb3, 0x363e, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x2b}, + {0xff, 0x0000, 0x00, 0x0000, 0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +typedef struct _SiS300_Ext2Struct { + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + USHORT ROM_OFFSET; +} SiS300_Ext2Struct; +SiS300_Ext2Struct SiS300_RefIndex[] = { + {0x085f, 0x0d, 0x03, 0x05, 0x6a, 800, 600, 0x3563}, + {0x0467, 0x0e, 0x44, 0x05, 0x6a, 800, 600, 0x3568}, + {0x0067, 0x4f, 0x07, 0x48, 0x6a, 800, 600, 0x356d}, + {0x0067, 0x10, 0x06, 0x8b, 0x6a, 800, 600, 0x3572}, + {0x0147, 0x11, 0x08, 0x00, 0x6a, 800, 600, 0x3577}, + {0x0147, 0x12, 0x0c, 0x00, 0x6a, 800, 600, 0x357c}, + {0x0047, 0x51, 0x4e, 0x00, 0x6a, 800, 600, 0x3581}, + {0x0047, 0x11, 0x13, 0x00, 0x6a, 800, 600, 0x3586}, + {0xc85f, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x3539}, + {0xc067, 0x06, 0x02, 0x04, 0x2e, 640, 480, 0x353e}, + {0xc067, 0x07, 0x02, 0x47, 0x2e, 640, 480, 0x3543}, + {0xc067, 0x08, 0x03, 0x8a, 0x2e, 640, 480, 0x3548}, + {0xc047, 0x09, 0x05, 0x00, 0x2e, 640, 480, 0x354d}, + {0xc047, 0x0a, 0x08, 0x00, 0x2e, 640, 480, 0x3552}, + {0xc047, 0x0b, 0x0a, 0x00, 0x2e, 640, 480, 0x3557}, + {0xc047, 0x0c, 0x10, 0x00, 0x2e, 640, 480, 0x355c}, + {0x487f, 0x04, 0x00, 0x00, 0x2f, 640, 400, 0x3532}, + {0xc00f, 0x31, 0x01, 0x06, 0x31, 2048, 1536, 0x3630}, + {0x000f, 0x32, 0x03, 0x06, 0x32, 720, 480, 0x3637}, + {0x0187, 0x15, 0x05, 0x00, 0x37, 1024, 768, 0x358d}, + {0xc877, 0x16, 0x09, 0x06, 0x37, 1024, 768, 0x3592}, + {0xc067, 0x97, 0x0b, 0x49, 0x37, 1024, 768, 0x3597}, + {0x0267, 0x18, 0x0d, 0x00, 0x37, 1024, 768, 0x359c}, + {0x0047, 0x59, 0x11, 0x8c, 0x37, 1024, 768, 0x35a1}, + {0x0047, 0x1a, 0x52, 0x00, 0x37, 1024, 768, 0x35a6}, + {0x0047, 0x5b, 0x16, 0x00, 0x37, 1024, 768, 0x35ab}, + {0x0387, 0x5c, 0x4d, 0x00, 0x3a, 1280, 1024, 0x35be}, + {0x0077, 0x1d, 0x14, 0x07, 0x3a, 1280, 1024, 0x35c3}, + {0x0047, 0x1e, 0x17, 0x00, 0x3a, 1280, 1024, 0x35c8}, + {0x0007, 0x1f, 0x98, 0x00, 0x3a, 1280, 1024, 0x35cd}, + {0x0007, 0x60, 0x59, 0x00, 0x3c, 1600, 1200, 0x35d4}, + {0x0007, 0x21, 0x5a, 0x00, 0x3c, 1600, 1200, 0x35d9}, + {0x0007, 0x22, 0x1b, 0x00, 0x3c, 1600, 1200, 0x35de}, + {0x0007, 0x63, 0x1d, 0x00, 0x3c, 1600, 1200, 0x35e3}, + {0x0007, 0x24, 0x1e, 0x00, 0x3c, 1600, 1200, 0x35e8}, + {0x407f, 0x00, 0x00, 0x00, 0x40, 320, 200, 0x3516}, + {0xc07f, 0x01, 0x00, 0x04, 0x50, 320, 240, 0x351d}, + {0x0077, 0x02, 0x04, 0x05, 0x51, 400, 300, 0x3524}, + {0xc077, 0x03, 0x09, 0x06, 0x52, 512, 384, 0x352b}, + {0x8207, 0x25, 0x1f, 0x00, 0x68, 1920, 1440, 0x35ef}, + {0x0007, 0x26, 0x20, 0x00, 0x6c, 2048, 1536, 0x35f6}, + {0x0027, 0x27, 0x14, 0x08, 0x6e, 720, 576, 0x35b2}, + {0x0027, 0x27, 0x14, 0x08, 0x6e, 720, 576, 0x35b7}, + {0x00df, 0x33, 0x28, 0x00, 0x7c, 1280, 960, 0x363e}, + {0xc05f, 0x34, 0x28, 0x00, 0x7c, 1280, 960, 0x3643}, + {0xffff, 0, 0, 0, 0, 0, 0, 0} +}; + +/*add for 300 oem util*/ +typedef struct _SiS_VBModeIDTableStruct { + UCHAR ModeID; + UCHAR VB_TVDelayIndex; + UCHAR VB_TVFlickerIndex; + UCHAR VB_TVPhaseIndex; + UCHAR VB_TVYFilterIndex; + UCHAR VB_LCDDelayIndex; + UCHAR _VB_LCDHIndex; + UCHAR _VB_LCDVIndex; +} SiS_VBModeIDTableStruct; +SiS_VBModeIDTableStruct SiS300_VBModeIDTable[] = { + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02}, + {0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00}, + {0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x01}, + {0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x02}, + {0x05, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00}, + {0x06, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x00}, + {0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x01}, + {0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x02}, + {0x0d, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00}, + {0x0e, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x00}, + {0x0f, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x01}, + {0x10, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x01}, + {0x11, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x03}, + {0x12, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x03}, + {0x13, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00}, + {0x6a, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x2e, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x08}, + {0x2f, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x06}, + {0x30, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x31, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00}, + {0x32, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00}, + {0x37, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x38, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x3a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x40, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x05}, + {0x41, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x05}, + {0x43, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x08}, + {0x44, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x08}, + {0x46, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x47, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x49, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x4a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x4c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x4d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x50, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x07}, + {0x51, 0x00, 0x00, 0x01, 0x07, 0x00, 0x07, 0x09}, + {0x52, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0x0b}, + {0x56, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x07}, + {0x57, 0x00, 0x00, 0x01, 0x07, 0x00, 0x07, 0x09}, + {0x58, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0x0b}, + {0x59, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x05}, + {0x5d, 0x00, 0x00, 0x01, 0x07, 0x00, 0x06, 0x06}, + {0x62, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x08}, + {0x63, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x64, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x65, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x6e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x6f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x7b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d} +}; +/*end*/ + +typedef struct _SiS300_CRT1TableStruct { + UCHAR CR[17]; +} SiS300_CRT1TableStruct; +SiS300_CRT1TableStruct SiS300_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x04, + 0x00}}, + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, + {{0x63, 0x4f, 0x50, 0x86, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8b, 0xdf, 0xe7, 0xff, 0x10, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, + {{0x66, 0x4f, 0x4f, 0x86, 0x56, 0x9e, 0x03, 0x3e, + 0xe4, 0x87, 0xdf, 0xdf, 0x04, 0x00, 0x00, 0x01, + 0x00}}, + {{0x6c, 0x4f, 0x4f, 0x83, 0x59, 0x9e, 0x00, 0x3e, + 0xe5, 0x8d, 0xdf, 0xdf, 0x01, 0x00, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9d, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, + 0x00}}, + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xe5, 0xe5, 0xfc, 0x00, 0x00, 0x01, + 0x00}}, + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, + {{0x8c, 0x63, 0x63, 0x87, 0x72, 0x16, 0x7e, 0xf0, + 0x59, 0x8d, 0x57, 0x57, 0x7f, 0x00, 0x00, 0x06, + 0x01}}, + {{0x7e, 0x63, 0x63, 0x82, 0x6c, 0x14, 0x75, 0xe0, + 0x58, 0x0b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, + {{0x7e, 0x63, 0x63, 0x82, 0x6c, 0x14, 0x75, 0xe0, + 0x58, 0x0b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, + {{0x9f, 0x7f, 0x7f, 0x83, 0x83, 0x93, 0x1e, 0xf5, + 0x00, 0x84, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, + {{0xa2, 0x7f, 0x7f, 0x86, 0x84, 0x94, 0x37, 0xf5, + 0x0b, 0x82, 0xff, 0xff, 0x38, 0x10, 0x00, 0x02, + 0x01}}, + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x3f, 0xef, 0xef, 0x83, 0xfd, 0x1a, 0xda, 0x1f, + 0xa0, 0x84, 0x9f, 0x9f, 0xdb, 0x1f, 0x01, 0x01, + 0x00}}, + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, + {{0xdc, 0x9f, 0x9f, 0x00, 0xab, 0x19, 0xe6, 0xef, + 0xc0, 0xc3, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x15, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, + {{0x7b, 0x59, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x3f, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, + {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, + 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, + 0x00}}, + {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, + 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, + 0x00}} +}; + +typedef struct _SiS300_MCLKDataStruct { + UCHAR SR28, SR29, SR2A; + USHORT CLOCK; +} SiS300_MCLKDataStruct; +SiS300_MCLKDataStruct SiS300_MCLKData[] = { + {0x5a, 0x64, 0x80, 66}, + {0xb3, 0x45, 0x80, 83}, + {0x37, 0x61, 0x80, 100}, + {0x37, 0x22, 0x80, 133}, + {0x37, 0x61, 0x80, 100}, + {0x37, 0x61, 0x80, 100}, + {0x37, 0x61, 0x80, 100}, + {0x37, 0x61, 0x80, 100} +}; + +typedef struct _SiS300_ECLKDataStruct { + UCHAR SR2E, SR2F, SR30; + USHORT CLOCK; +} SiS300_ECLKDataStruct; +SiS300_ECLKDataStruct SiS300_ECLKData[] = { + {0x54, 0x43, 0x80, 100}, + {0x53, 0x43, 0x80, 100}, + {0x55, 0x43, 0x80, 100}, + {0x52, 0x43, 0x80, 100}, + {0x3f, 0x42, 0x80, 100}, + {0x54, 0x43, 0x80, 100}, + {0x54, 0x43, 0x80, 100}, + {0x54, 0x43, 0x80, 100} +}; + +typedef struct _SiS300_VCLKDataStruct { + UCHAR SR2B, SR2C; + USHORT CLOCK; +} SiS300_VCLKDataStruct; +SiS300_VCLKDataStruct SiS300_VCLKData[] = { + {0x1b, 0xe1, 25}, + {0x4e, 0xe4, 28}, + {0x57, 0xe4, 32}, + {0xc3, 0xc8, 36}, + {0x42, 0xc3, 40}, + {0x5d, 0xc4, 45}, + {0x52, 0x65, 50}, + {0x53, 0x65, 50}, + {0x6d, 0x66, 56}, + {0x5a, 0x64, 65}, + {0x46, 0x44, 68}, + {0x3e, 0x43, 75}, + {0x6d, 0x46, 76}, + {0x41, 0x43, 79}, + {0x31, 0x42, 79}, + {0x46, 0x25, 85}, + {0x78, 0x29, 87}, + {0x62, 0x44, 95}, + {0x2b, 0x22, 105}, + {0x49, 0x24, 106}, + {0xc3, 0x28, 108}, + {0x3c, 0x23, 109}, + {0xf7, 0x2c, 132}, + {0xd4, 0x28, 136}, + {0x41, 0x05, 158}, + {0x43, 0x05, 162}, + {0xe1, 0x0f, 175}, + {0xfc, 0x12, 189}, + {0xde, 0x26, 194}, + {0x54, 0x05, 203}, + {0x3f, 0x03, 230}, + {0x30, 0x02, 234}, + {0x24, 0x01, 266}, + {0x52, 0x2a, 54}, + {0x52, 0x6a, 27}, + {0x62, 0x24, 70}, + {0x62, 0x64, 70}, + {0xa8, 0x4c, 30}, + {0x20, 0x26, 33}, + {0x31, 0xc2, 39}, + {0xbf, 0xc8, 35}, + {0x60, 0x36, 30}, + {0x40, 0x4a, 28}, + {0x9f, 0x46, 44}, + {0x97, 0x2c, 26}, + {0x44, 0xe4, 25}, + {0x7e, 0x32, 47}, + {0x8a, 0x24, 31}, + {0x97, 0x2c, 26}, + {0xce, 0x3c, 39}, + {0x52, 0x4a, 36}, + {0x34, 0x61, 95}, + {0x78, 0x27, 108}, + {0xff, 0x1b, 6625} +}; + +UCHAR SiS300_ScreenOffset[] = + { 0x14, 0x19, 0x20, 0x28, 0x32, 0x40, 0x50, 0x64, 0x78, 0x80, 0x2d, 0x35, + 0xff }; + +typedef struct _SiS300_StResInfoStruct { + USHORT HTotal; + USHORT VTotal; +} SiS300_StResInfoStruct; +SiS300_StResInfoStruct SiS300_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} +}; + +typedef struct _SiS300_ModeResInfoStruct { + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} SiS300_ModeResInfoStruct; +SiS300_ModeResInfoStruct SiS300_ModeResInfo[] = { + {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} +}; + +UCHAR SiS300_OutputSelect = 0x40; +UCHAR SiS300_SoftSetting = 30; +UCHAR SiS300_SR07 = 0x10; +UCHAR SiS300_SR15[8][4] = { + {0x1, 0x9, 0xa3, 0x0}, + {0x43, 0x43, 0x43, 0x0}, + {0x1e, 0x1e, 0x1e, 0x0}, + {0x2a, 0x2a, 0x2a, 0x0}, + {0x6, 0x6, 0x6, 0x0}, + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0x0, 0x0, 0x0} +}; +UCHAR SiS300_SR1F = 0x0; +UCHAR SiS300_SR21 = 0x16; +UCHAR SiS300_SR22 = 0xb2; +UCHAR SiS300_SR23 = 0xf6; +UCHAR SiS300_SR24 = 0xd; +UCHAR SiS300_SR25[] = { 0x0, 0x0 }; +UCHAR SiS300_SR31 = 0x0; +UCHAR SiS300_SR32 = 0x11; +UCHAR SiS300_SR33 = 0x0; +UCHAR SiS300_CRT2Data_1_2 = 0x40; +UCHAR SiS300_CRT2Data_4_D = 0x0; +UCHAR SiS300_CRT2Data_4_E = 0x0; +UCHAR SiS300_CRT2Data_4_10 = 0x80; +USHORT SiS300_RGBSenseData = 0xd1; +USHORT SiS300_VideoSenseData = 0xb3; +USHORT SiS300_YCSenseData = 0xb9; +USHORT SiS300_RGBSenseData2 = 0x0190; /*301b */ +USHORT SiS300_VideoSenseData2 = 0x0174; +USHORT SiS300_YCSenseData2 = 0x016b; + +UCHAR SiS300_CR40[5][4]; +UCHAR SiS300_CR49[2]; +UCHAR SiS300_NTSCPhase[] = { 0x21, 0xed, 0x8a, 0x8 }; +UCHAR SiS300_PALPhase[] = { 0x2a, 0x5, 0xd3, 0x0 }; +UCHAR SiS300_NTSCPhase2[] = { 0x21, 0xF0, 0x7B, 0xD6 }; /*301b */ +UCHAR SiS300_PALPhase2[] = { 0x2a, 0x09, 0x86, 0xe9 }; +UCHAR SiS300_PALMPhase[] = { 0x21, 0xE4, 0x2E, 0x9B }; /*palmn */ +UCHAR SiS300_PALNPhase[] = { 0x21, 0xF4, 0x3E, 0xBA }; + +typedef struct _SiS300_PanelDelayTblStruct { + UCHAR timer[2]; +} SiS300_PanelDelayTblStruct; +SiS300_PanelDelayTblStruct SiS300_PanelDelayTbl[] = { + {{0x05, 0xaa}}, + {{0x05, 0x14}}, + {{0x05, 0x36}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x90}}, + {{0x05, 0x90}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x64}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x14}} +}; + +typedef struct _SiS300_LCDDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS300_LCDDataStruct; +SiS300_LCDDataStruct SiS300_StLCD1024x768Data[] = { + {66, 31, 992, 510, 1320, 816}, + {66, 31, 992, 510, 1320, 816}, + {176, 75, 900, 510, 1320, 816}, + {176, 75, 900, 510, 1320, 816}, + {66, 31, 992, 510, 1320, 816}, + {27, 16, 1024, 650, 1350, 832}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS300_LCDDataStruct SiS300_ExtLCD1024x768Data[] = { + {12, 5, 896, 512, 1344, 806}, + {12, 5, 896, 510, 1344, 806}, + {32, 15, 1008, 505, 1344, 806}, + {32, 15, 1008, 514, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS300_LCDDataStruct SiS300_St2LCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS300_LCDDataStruct SiS300_StLCD1280x1024Data[] = { + {4, 1, 880, 510, 1650, 1088}, + {4, 1, 880, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {4, 1, 880, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS300_LCDDataStruct SiS300_ExtLCD1280x1024Data[] = { + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 500, 1688, 1066}, + {211, 75, 1024, 625, 1688, 1066}, + {211, 120, 1280, 798, 1688, 1066}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS300_LCDDataStruct SiS300_St2LCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS300_LCDDataStruct SiS300_NoScaleData[] = { + {1, 1, 800, 449, 800, 449}, + {1, 1, 800, 449, 800, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 800, 525, 800, 525}, + {1, 1, 1056, 628, 1056, 628}, + {1, 1, 1344, 806, 1344, 806}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS300_LCDDataStruct SiS300_LCD1280x960Data[] = { + {9, 2, 800, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {30, 11, 1056, 625, 1800, 1000}, + {5, 3, 1350, 800, 1800, 1000}, + {1, 1, 1576, 1050, 1576, 1050}, + {1, 1, 1800, 1000, 1800, 1000} +}; + +typedef struct _SiS300_TVDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} SiS300_TVDataStruct; +SiS300_TVDataStruct SiS300_StPALData[] = { + {1, 1, 864, 525, 1270, 400, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 350, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 864, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 864, 525, 1270, 480, 50, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 600, 50, 0, 0, 0xf4, 0xff, 0x1c, 0x22} +}; + +SiS300_TVDataStruct SiS300_ExtPALData[] = { + {27, 10, 848, 448, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {108, 35, 848, 398, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {12, 5, 954, 448, 1270, 530, 50, 0, 50, 0xf1, 0x04, 0x1f, 0x18}, + {9, 4, 960, 463, 1644, 438, 50, 0, 50, 0xf4, 0x0b, 0x1c, 0x0a}, + {9, 4, 848, 528, 1270, 530, 0, 0, 50, 0xf5, 0xfb, 0x1b, 0x2a}, + {36, 25, 1060, 648, 1316, 530, 438, 0, 438, 0xeb, 0x05, 0x25, 0x16}, + {3, 2, 1080, 619, 1270, 540, 438, 0, 438, 0xf3, 0x00, 0x1d, 0x20}, + {1, 1, 1170, 821, 1270, 520, 686, 0, 686, 0xF3, 0x00, 0x1D, 0x20} /*301b */ + +}; + +SiS300_TVDataStruct SiS300_StNTSCData[] = { + {1, 1, 858, 525, 1270, 400, 50, 0, 760, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 50, 0, 640, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 858, 525, 1270, 480, 0, 0, 760, 0xf1, 0x04, 0x1f, 0x18} +}; + +SiS300_TVDataStruct SiS300_ExtNTSCData[] = { + {143, 65, 858, 443, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {88, 35, 858, 393, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 443, 1270, 440, 92, 0, 92, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 393, 1270, 440, 92, 0, 92, 0xf4, 0x0b, 0x1c, 0x0a}, + {143, 76, 836, 523, 1270, 440, 224, 0, 0, 0xf1, 0x05, 0x1f, 0x16}, + {143, 120, 1056, 643, 1270, 440, 0, 128, 0, 0xf4, 0x10, 0x1c, 0x00}, + {143, 76, 836, 523, 1270, 440, 0, 128, 0, 0xee, 0x0c, 0x22, 0x08}, + {65, 64, 1056, 791, 1270, 480, 638, 0, 0, 0xf1, 0x04, 0x1f, 0x18} /*301b */ +}; + +SiS_TVDataStruct SiS300_St1HiTVData[] = { + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00} +}; + +SiS_TVDataStruct SiS300_St2HiTVData[] = { + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00} +}; + +SiS_TVDataStruct SiS300_ExtHiTVData[] = { + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00} +}; + +UCHAR SiS300_NTSCTiming[] = { + 0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c, + 0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a, + 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b, + 0x0c, 0x50, 0x00, 0x97, 0x00, 0xda, 0x4a, 0x17, + 0x7d, 0x05, 0x4b, 0x00, 0x00, 0xe2, 0x00, 0x02, + 0x03, 0x0a, 0x65, 0x9d, 0x08, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x50, + 0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00 +}; + +UCHAR SiS300_PALTiming[] = { + 0x19, 0x52, 0x35, 0x6e, 0x04, 0x38, 0x3d, 0x70, + 0x94, 0x49, 0x01, 0x12, 0x06, 0x3e, 0x35, 0x6d, + 0x06, 0x14, 0x3e, 0x35, 0x6d, 0x00, 0x45, 0x2b, + 0x70, 0x50, 0x00, 0x9b, 0x00, 0xd9, 0x5d, 0x17, + 0x7d, 0x05, 0x45, 0x00, 0x00, 0xe8, 0x00, 0x02, + 0x0d, 0x00, 0x68, 0xb0, 0x0b, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x63, + 0x00, 0x40, 0x3e, 0x00, 0xe1, 0x02, 0x28, 0x00 +}; + +UCHAR SiS300_HiTVExtTiming[] = { 0x00 }; + +UCHAR SiS300_HiTVSt1Timing[] = { 0x00 }; + +UCHAR SiS300_HiTVSt2Timing[] = { 0x00 }; + +UCHAR SiS300_HiTVTextTiming[] = { 0x00 }; + +UCHAR SiS300_HiTVGroup3Data[] = { 0x00 }; + +UCHAR SiS300_HiTVGroup3Simu[] = { 0x00 }; + +UCHAR SiS300_HiTVGroup3Text[] = { 0x00 }; + +typedef struct _SiS300_LVDSDataStruct { + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS300_LVDSDataStruct; +SiS300_LVDSDataStruct SiS300_LVDS800x600Data_1[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS800x600Data_2[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS1024x768Data_1[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS1024x768Data_2[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS1280x1024Data_1[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS1280x1024Data_2[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS640x480Data_1[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_CHTVUNTSCData[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_CHTVONTSCData[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_CHTVUPALData[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_CHTVOPALData[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +typedef struct _SiS300_LVDSDesStruct { + USHORT LCDHDES; + USHORT LCDVDES; +} SiS300_LVDSDesStruct; +SiS300_LVDSDesStruct SiS300_PanelType00_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType01_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType02_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType03_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType04_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType05_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType06_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType07_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType08_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType09_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0a_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0b_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0c_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0d_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0e_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0f_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType00_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType01_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType02_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType03_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType04_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType05_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType06_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType07_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType08_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType09_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0a_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0b_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0c_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0d_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0e_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0f_2[] = { + {0x00, 0x00} +}; + +/*301b*/ +SiS300_LVDSDesStruct SiS300_PanelType1076_1[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1210_1[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1296_1[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1076_2[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1210_2[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1296_2[] = { + {0x00, 0x00} +}; +/*end 301b*/ + +SiS300_LVDSDesStruct SiS300_CHTVUNTSCDesData[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_CHTVONTSCDesData[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_CHTVUPALDesData[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_CHTVOPALDesData[] = { + {0x00, 0x00} +}; + +typedef struct _SiS300_LVDSCRT1DataStruct { + UCHAR CR[15]; +} SiS300_LVDSCRT1DataStruct; +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1UNTSC[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1ONTSC[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1UPAL[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1OPAL[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +typedef struct _SiS300_CHTVRegDataStruct { + UCHAR Reg[5]; +} SiS300_CHTVRegDataStruct; +SiS300_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +UCHAR SiS300_CHTVVCLKUNTSC[] = { 0x00 }; + +UCHAR SiS300_CHTVVCLKONTSC[] = { 0x00 }; + +UCHAR SiS300_CHTVVCLKUPAL[] = { 0x00 }; + +UCHAR SiS300_CHTVVCLKOPAL[] = { 0x00 }; diff --git a/drivers/video/sis/310vtbl.h b/drivers/video/sis/310vtbl.h new file mode 100644 index 000000000000..2f3a1fc9e4b9 --- /dev/null +++ b/drivers/video/sis/310vtbl.h @@ -0,0 +1,2604 @@ +typedef struct _SiS310_StStruct { + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; +} SiS310_StStruct; + +SiS310_StStruct SiS310_SModeIDTable[] = +{ + {0x01, 0x9208, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, + {0x01, 0x1210, 0x14, 0x01, 0x01, 0x00, 0x01, 0x00}, + {0x01, 0x1010, 0x17, 0x02, 0x02, 0x00, 0x01, 0x01}, + {0x03, 0x8208, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02}, + {0x03, 0x0210, 0x16, 0x01, 0x01, 0x00, 0x01, 0x02}, + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03}, + {0x05, 0x9209, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x06, 0x8209, 0x06, 0x00, 0x00, 0x00, 0x00, 0x05}, + {0x07, 0x0000, 0x07, 0x03, 0x03, 0x00, 0x01, 0x03}, + {0x07, 0x0000, 0x19, 0x02, 0x02, 0x00, 0x01, 0x03}, + {0x0d, 0x920a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x0e, 0x820a, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x05}, + {0x0f, 0x0202, 0x11, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0x10, 0x0212, 0x12, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0x11, 0x0212, 0x1a, 0x04, 0x04, 0x00, 0x00, 0x05}, + {0x12, 0x0212, 0x1b, 0x04, 0x04, 0x00, 0x00, 0x05}, + {0x13, 0x021b, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x12, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x00, 0x05}, + {0x12, 0x0210, 0x18, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +typedef struct _SiS310_StandTableStruct { + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} SiS310_StandTableStruct; + +SiS310_StandTableStruct SiS310_StandTable[] = { +/* MD_0_200 */ + { + 0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_1_200 */ + { + 0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_200 */ + { + 0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_3_200 */ + { + 0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_4 */ + { + 0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff} + }, +/* MD_5 */ + { + 0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff} + }, +/* MD_6 */ + { + 0x50, 0x18, 0x08, 0x4000, + {0x01, 0x01, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, + 0xff}, + {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x01, 0x00, 0x01, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0xff} + }, +/* MD_7 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x00, 0x03, 0x00, 0x03}, + 0xa6, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff} + }, +/* MDA_DAC */ + { + 0x00, 0x00, 0x00, 0x0000, + {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} + }, +/* CGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {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} + }, +/* EGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {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} + }, +/* VGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {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, 0x0a08, + {0x0c, 0x0e, 0x10, 0x0b}, + 0x0c, + {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, + 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00, + 0x06}, + {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08, + 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} + }, +/* MD_D */ + { + 0x28, 0x18, 0x08, 0x2000, + {0x09, 0x0f, 0x00, 0x06}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_E */ + { + 0x50, 0x18, 0x08, 0x4000, + {0x01, 0x0f, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* ExtVGATable */ + { + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} + }, +/* ROM_SAVEPTR */ + { + 0x9f, 0x3b, 0x00, 0x00c0, + {0x00, 0x00, 0x00, 0x00}, + 0x00, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x3f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0x00, 0xac, 0x3e, 0x00, 0xc0, + 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} + }, +/* MD_F */ + { + 0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa2, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x0b, 0x00, 0x05, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, + 0xff} + }, +/* MD_10 */ + { + 0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_0_350 */ + { + 0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_1_350 */ + { + 0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_350 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_3_350 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_0_1_400 */ + { + 0x28, 0x18, 0x10, 0x0800, + {0x08, 0x03, 0x00, 0x02}, + 0x67, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_3_400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_7_400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x66, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff} + }, +/* MD_11 */ + { + 0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3, + 0xff}, + {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, + 0xff} + }, +/* ExtEGATable */ + { + 0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_13 */ + { + 0x28, 0x18, 0x08, 0x2000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x41, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} + } +}; + +typedef struct _SiS310_ExtStruct { + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_ModeInfo; + USHORT Ext_Point; + USHORT Ext_VESAID; + UCHAR Ext_VESAMEMSize; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR REFindex; +} SiS310_ExtStruct; +SiS310_ExtStruct SiS310_EModeIDTable[] = { + + {0x6a, 0x2212, 0x0407, 0x3a81, 0x0102, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x2e, 0x0a1b, 0x0306, 0x3a57, 0x0101, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x2f, 0x0a1b, 0x0305, 0x3a50, 0x0100, 0x08, 0x05, 0x00, 0x00, 0x05, + 0x10}, + {0x30, 0x2a1b, 0x0407, 0x3a81, 0x0103, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x31, 0x0a1b, 0x030d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x32, 0x0a1b, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x33, 0x0a1d, 0x0a0d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x34, 0x2a1d, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x35, 0x0a1f, 0x0a0d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x36, 0x2a1f, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x37, 0x0212, 0x0508, 0x3aab, 0x0104, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x38, 0x0a1b, 0x0508, 0x3aab, 0x0105, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x3a, 0x0e3b, 0x0609, 0x3adc, 0x0107, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x3c, 0x063b, 0x070a, 0x3af2, 0x0130, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x3d, 0x067d, 0x070a, 0x3af2, 0x0131, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x40, 0x9a1c, 0x0000, 0x3a34, 0x010d, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x41, 0x9a1d, 0x0000, 0x3a34, 0x010e, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x43, 0x0a1c, 0x0306, 0x3a57, 0x0110, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x44, 0x0a1d, 0x0306, 0x3a57, 0x0111, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x46, 0x2a1c, 0x0407, 0x3a81, 0x0113, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x47, 0x2a1d, 0x0407, 0x3a81, 0x0114, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x49, 0x0a3c, 0x0508, 0x3aab, 0x0116, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x4a, 0x0a3d, 0x0508, 0x3aab, 0x0117, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x4c, 0x0e7c, 0x0609, 0x3adc, 0x0119, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x4d, 0x0e7d, 0x0609, 0x3adc, 0x011a, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x50, 0x9a1b, 0x0001, 0x3a3b, 0x0132, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x26}, + {0x51, 0xba1b, 0x0103, 0x3a42, 0x0133, 0x08, 0x03, 0x00, 0x00, 0x07, + 0x27}, + {0x52, 0x9a1b, 0x0204, 0x3a49, 0x0134, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x28}, + {0x56, 0x9a1d, 0x0001, 0x3a3b, 0x0135, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x26}, + {0x57, 0xba1d, 0x0103, 0x3a42, 0x0136, 0x08, 0x03, 0x00, 0x00, 0x07, + 0x27}, + {0x58, 0x9a1d, 0x0204, 0x3a49, 0x0137, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x28}, + {0x59, 0x9a1b, 0x0000, 0x3a34, 0x0138, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x5d, 0x0a1d, 0x0305, 0x3a50, 0x0139, 0x08, 0x05, 0x00, 0x00, 0x07, + 0x10}, + {0x62, 0x0a3f, 0x0306, 0x3a57, 0x013a, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x63, 0x2a3f, 0x0407, 0x3a81, 0x013b, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x64, 0x0a7f, 0x0508, 0x3aab, 0x013c, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x65, 0x0eff, 0x0609, 0x3adc, 0x013d, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x66, 0x06ff, 0x070a, 0x3af2, 0x013e, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x68, 0x067b, 0x080b, 0x3b17, 0x013f, 0x08, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x69, 0x06fd, 0x080b, 0x3b17, 0x0140, 0x08, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x6b, 0x07ff, 0x080b, 0x3b17, 0x0141, 0x10, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x6c, 0x067b, 0x090c, 0x3b37, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x6d, 0x06fd, 0x090c, 0x3b37, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x6e, 0x07ff, 0x090c, 0x3b37, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x70, 0x2a1b, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x71, 0x0a1b, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x74, 0x0a1d, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x75, 0x0a3d, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x76, 0x2a1f, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x77, 0x0a1f, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x78, 0x0a3f, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x79, 0x0a3b, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x7a, 0x2a1d, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x7b, 0x0e3b, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0x7c, 0x0e7d, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0x7d, 0x0eff, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0xff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} +}; + +typedef struct _SiS310_Ext2Struct { + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + USHORT ROM_OFFSET; +} SiS310_Ext2Struct; +SiS310_Ext2Struct SiS310_RefIndex[] = { + {0x005f, 0x0d, 0x03, 0x05, 0x6a, 800, 600, 0x3a81}, /* 0x0 */ + {0x0467, 0x0e, 0x04, 0x05, 0x6a, 800, 600, 0x3a86}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x6a, 800, 600, 0x3a8b}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x6a, 800, 600, 0x3a90}, /* 0x3 */ + {0x0147, 0x11, 0x0a, 0x00, 0x6a, 800, 600, 0x3a95}, /* 0x4 */ + {0x4147, 0x12, 0x0d, 0x00, 0x6a, 800, 600, 0x3a9a}, /* 0x5 */ + {0x4047, 0x13, 0x13, 0x00, 0x6a, 800, 600, 0x3a9f}, /* 0x6 */ + {0x4047, 0x14, 0x1c, 0x00, 0x6a, 800, 600, 0x3aa4}, /* 0x7 */ + {0xc05f, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x3a57}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x2e, 640, 480, 0x3a5c}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x2e, 640, 480, 0x3a61}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x2e, 640, 480, 0x3a66}, /* 0xb */ + {0x4047, 0x09, 0x05, 0x00, 0x2e, 640, 480, 0x3a6b}, /* 0xc */ + {0x4047, 0x0a, 0x09, 0x00, 0x2e, 640, 480, 0x3a70}, /* 0xd */ + {0x4047, 0x0b, 0x0e, 0x00, 0x2e, 640, 480, 0x3a75}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x2e, 640, 480, 0x3a7a}, /* 0xf */ + {0x407f, 0x04, 0x00, 0x00, 0x2f, 640, 400, 0x3a50}, /* 0x10 */ + {0xc00f, 0x3c, 0x01, 0x06, 0x31, 720, 480, 0x3b85}, /* 0x11 */ + {0x000f, 0x3d, 0x03, 0x06, 0x32, 720, 576, 0x3b8c}, /* 0x12 */ + {0x0187, 0x15, 0x06, 0x00, 0x37, 1024, 768, 0x3aab}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x37, 1024, 768, 0x3ab0}, /* 0x14 301b TV1024x768 */ + {0xc067, 0x17, 0x0f, 0x49, 0x37, 1024, 768, 0x3ab5}, /* 0x15 */ + {0x0267, 0x18, 0x11, 0x00, 0x37, 1024, 768, 0x3aba}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x37, 1024, 768, 0x3abf}, /* 0x17 */ + {0x4047, 0x1a, 0x1b, 0x00, 0x37, 1024, 768, 0x3ac4}, /* 0x18 */ + {0x4047, 0x1b, 0x1f, 0x00, 0x37, 1024, 768, 0x3ac9}, /* 0x19 */ + {0x0387, 0x1c, 0x11, 0x00, 0x3a, 1280, 1024, 0x3adc}, /* 0x1a */ + {0x0077, 0x1d, 0x19, 0x07, 0x3a, 1280, 1024, 0x3ae1}, /* 0x1b */ + {0x0047, 0x1e, 0x1e, 0x00, 0x3a, 1280, 1024, 0x3ae6}, /* 0x1c */ + {0x0007, 0x1f, 0x20, 0x00, 0x3a, 1280, 1024, 0x3aeb}, /* 0x1d */ + {0x0007, 0x20, 0x21, 0x00, 0x3c, 1600, 1200, 0x3af2}, /* 0x1e */ + {0x0007, 0x21, 0x22, 0x00, 0x3c, 1600, 1200, 0x3af7}, /* 0x1f */ + {0x0007, 0x22, 0x23, 0x00, 0x3c, 1600, 1200, 0x3afc}, /* 0x20 */ + {0x0007, 0x23, 0x25, 0x00, 0x3c, 1600, 1200, 0x3b01}, /* 0x21 */ + {0x0007, 0x24, 0x26, 0x00, 0x3c, 1600, 1200, 0x3b06}, /* 0x22 */ + {0x0007, 0x25, 0x2c, 0x00, 0x3c, 1600, 1200, 0x3b0b}, /* 0x23 */ + {0x0007, 0x26, 0x34, 0x00, 0x3c, 1600, 1200, 0x3b10}, /* 0x24 */ + {0x407f, 0x00, 0x00, 0x00, 0x40, 320, 200, 0x3a34}, /* 0x25 */ + {0xc07f, 0x01, 0x00, 0x04, 0x50, 320, 240, 0x3a3b}, /* 0x26 */ + {0x007f, 0x02, 0x04, 0x05, 0x51, 400, 300, 0x3a42}, /* 0x27 */ + {0xc077, 0x03, 0x0b, 0x06, 0x52, 512, 384, 0x3a49}, /* 0x28 */ + {0x8007, 0x27, 0x27, 0x00, 0x68, 1920, 1440, 0x3b17}, /* 0x29 */ + {0x4007, 0x28, 0x29, 0x00, 0x68, 1920, 1440, 0x3b1c}, /* 0x2a */ + {0x4007, 0x29, 0x2e, 0x00, 0x68, 1920, 1440, 0x3b21}, /* 0x2b */ + {0x4007, 0x2a, 0x30, 0x00, 0x68, 1920, 1440, 0x3b26}, /* 0x2c */ + {0x4007, 0x2b, 0x35, 0x00, 0x68, 1920, 1440, 0x3b2b}, /* 0x2d */ + {0x4005, 0x2c, 0x39, 0x00, 0x68, 1920, 1440, 0x3b30}, /* 0x2e */ + {0x4007, 0x2d, 0x2b, 0x00, 0x6c, 2048, 1536, 0x3b37}, /* 0x2f */ + {0x4007, 0x2e, 0x31, 0x00, 0x6c, 2048, 1536, 0x3b3c}, /* 0x30 */ + {0x4007, 0x2f, 0x33, 0x00, 0x6c, 2048, 1536, 0x3b41}, /* 0x31 */ + {0x4007, 0x30, 0x37, 0x00, 0x6c, 2048, 1536, 0x3b46}, /* 0x32 */ + {0x4005, 0x31, 0x38, 0x00, 0x6c, 2048, 1536, 0x3b4b}, /* 0x33 */ + {0x0057, 0x32, 0x40, 0x08, 0x70, 800, 480, 0x3b52}, /* 0x34 */ + {0x0047, 0x33, 0x07, 0x08, 0x70, 800, 480, 0x3b57}, /* 0x35 */ + {0x0047, 0x34, 0x0a, 0x08, 0x70, 800, 480, 0x3b5c}, /* 0x36 */ + {0x0057, 0x35, 0x0b, 0x09, 0x71, 1024, 576, 0x3b63}, /* 0x37 */ + {0x0047, 0x36, 0x11, 0x09, 0x71, 1024, 576, 0x3b68}, /* 0x38 */ + {0x0047, 0x37, 0x16, 0x09, 0x71, 1024, 576, 0x3b6d}, /* 0x39 */ + {0x0057, 0x38, 0x19, 0x0a, 0x75, 1280, 720, 0x3b74}, /* 0x3a */ + {0x0047, 0x39, 0x1e, 0x0a, 0x75, 1280, 720, 0x3b79}, /* 0x3b */ + {0x0047, 0x3a, 0x20, 0x0a, 0x75, 1280, 720, 0x3b7e}, /* 0x3c */ + {0x0027, 0x3b, 0x19, 0x08, 0x7b, 1280, 960, 0x3ad0}, /* 0x3d */ + {0x0027, 0x3b, 0x19, 0x08, 0x7b, 1280, 960, 0x3ad5}, /* 0x3e */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0000, 0000, 0x0000} +}; + +typedef struct _SiS310_CRT1TableStruct { + UCHAR CR[17]; +} SiS310_CRT1TableStruct; + +SiS310_CRT1TableStruct SiS310_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}}, /* 0x0 */ + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x1 */ + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, /* 0x2 */ + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, /* 0x3 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, /* 0x4 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x5 */ + {{0x63, 0x4f, 0x50, 0x86, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8b, 0xdf, 0xe7, 0xff, 0x10, 0x00, 0x01, + 0x00}}, /* 0x6 */ + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, /* 0x7 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, /* 0x8 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x00, 0x00, 0x05, + 0x61}}, /* 0x9 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}}, /* 0xa */ + {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x10, 0x00, 0x05, + 0x61}}, /* 0xb */ + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xe5, 0xe5, 0xfc, 0x00, 0x00, 0x01, + 0x00}}, /* 0xc */ + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, /* 0xd */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, /* 0xe */ + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, /* 0xf */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, /* 0x10 */ + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, /* 0x11 */ + {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}}, /* 0x12 */ + {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}}, /* 0x13 */ + {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}}, /* 0x14 */ + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, /* 0x15 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x16 */ + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x17 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, /* 0x18 */ + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, /* 0x19 */ + {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1a */ + {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1b */ + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, /* 0x1c */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1d */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1e */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1f */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x20 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x21 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x22 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x23 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x24 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x25 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x26 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x27 */ + {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x28 */ + {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x29 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2a */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2b */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2c */ + {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2d */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2e */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2f */ + {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x30 */ + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, /* 0x31 */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, /* 0x32 */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, /* 0x33 */ + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, /* 0x34 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, /* 0x35 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x36 */ + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x15, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, /* 0x37 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x38 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x39 */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, /* 0x3a */ + {{0xdc, 0x9f, 0x9f, 0x00, 0xab, 0x19, 0xe6, 0xef, + 0xc0, 0xc3, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, /* 0x3b */ + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x3c */ + {{0x7b, 0x59, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x3f, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}} /* 0x3d */ +}; + +typedef struct _SiS310_MCLKDataStruct { + UCHAR SR28, SR29, SR2A; + USHORT CLOCK; +} SiS310_MCLKDataStruct; +SiS310_MCLKDataStruct SiS310_MCLKData[] = { + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166} +}; + +typedef struct _SiS310_ECLKDataStruct { + UCHAR SR2E, SR2F, SR30; + USHORT CLOCK; +} SiS310_ECLKDataStruct; +SiS310_ECLKDataStruct SiS310_ECLKData[] = { + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166} +}; + +typedef struct _SiS310_VCLKDataStruct { + UCHAR SR2B, SR2C; + USHORT CLOCK; +} SiS310_VCLKDataStruct; +SiS310_VCLKDataStruct SiS310_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x0 */ + {0x4e, 0xe4, 28}, /* 0x1 */ + {0x57, 0xe4, 31}, /* 0x2 */ + {0xc3, 0xc8, 36}, /* 0x3 */ + {0x42, 0xe2, 40}, /* 0x4 */ + {0xfe, 0xcd, 43}, /* 0x5 */ + {0x5d, 0xc4, 44}, /* 0x6 */ + {0x52, 0xe2, 49}, /* 0x7 */ + {0x53, 0xe2, 50}, /* 0x8 */ + {0x74, 0x67, 52}, /* 0x9 */ + {0x6d, 0x66, 56}, /* 0xa */ + {0x6c, 0xc3, 65}, /* 0xb */ + {0x46, 0x44, 67}, /* 0xc */ + {0xb1, 0x46, 68}, /* 0xd */ + {0xd3, 0x4a, 72}, /* 0xe */ + {0x29, 0x61, 75}, /* 0xf */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a */ + {0x52, 0x6a, 27}, /* 0x3b */ + {0x62, 0x24, 70}, /* 0x3c */ + {0x62, 0x64, 70}, /* 0x3d */ + {0xa8, 0x4c, 30}, /* 0x3e */ + {0x20, 0x26, 33}, /* 0x3f */ + {0x31, 0xc2, 39} /* 0x40 */ +}; + +typedef struct _SiS310_VBVCLKDataStruct { + UCHAR Part4_A, Part4_B; + USHORT CLOCK; +} SiS310_VBVCLKDataStruct; +SiS310_VBVCLKDataStruct SiS310_VBVCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x0 */ + {0x4e, 0xe4, 28}, /* 0x1 */ + {0x57, 0xe4, 31}, /* 0x2 */ + {0xc3, 0xc8, 36}, /* 0x3 */ + {0x42, 0x47, 40}, /* 0x4 */ + {0xfe, 0xcd, 43}, /* 0x5 */ + {0x5d, 0xc4, 44}, /* 0x6 */ + {0x52, 0x47, 49}, /* 0x7 */ + {0x53, 0x47, 50}, /* 0x8 */ + {0x74, 0x67, 52}, /* 0x9 */ + {0x6d, 0x66, 56}, /* 0xa */ + {0x5a, 0x64, 65}, /* 0xb */ + {0x46, 0x44, 67}, /* 0xc */ + {0xb1, 0x46, 68}, /* 0xd */ + {0xd3, 0x4a, 72}, /* 0xe */ + {0x29, 0x61, 75}, /* 0xf */ + {0x6d, 0x46, 75}, /* 0x10 */ + {0x41, 0x43, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x22, 104}, /* 0x17 */ + {0x49, 0x24, 105}, /* 0x18 */ + {0xf8, 0x2f, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0xd4, 0x28, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x70, 0x07, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a */ + {0x52, 0x6a, 27}, /* 0x3b */ + {0x62, 0x24, 70}, /* 0x3c */ + {0x62, 0x64, 70}, /* 0x3d */ + {0xa8, 0x4c, 30}, /* 0x3e */ + {0x20, 0x26, 33}, /* 0x3f */ + {0x31, 0xc2, 39} /* 0x40 */ +}; + +UCHAR SiS310_ScreenOffset[] = + { 0x14, 0x19, 0x20, 0x28, 0x32, 0x40, 0x50, 0x64, 0x78, 0x80, 0x2d, 0x35 }; + +typedef struct _SiS310_StResInfoStruct { + USHORT HTotal; + USHORT VTotal; +} SiS310_StResInfoStruct; +SiS310_StResInfoStruct SiS310_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} +}; + +typedef struct _SiS310_ModeResInfoStruct { + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} SiS310_ModeResInfoStruct; +SiS310_ModeResInfoStruct SiS310_ModeResInfo[] = { + {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}, + {2048, 1536, 8, 16}, + {720, 480, 8, 16}, + {720, 576, 8, 16}, + {1280, 960, 8, 16}, + {800, 480, 8, 16}, + {1024, 576, 8, 16}, + {1280, 720, 8, 16} +}; + +UCHAR SiS310_OutputSelect = 0x40; +UCHAR SiS310_SoftSetting = 30; +UCHAR SiS310_SR07 = 0x18; +UCHAR SiS310_SR15[8][4] = { + {0x0, 0x4, 0x60, 0x60}, + {0xf, 0xf, 0xf, 0xf}, + {0xba, 0xba, 0xba, 0xba}, + {0xa9, 0xa9, 0xac, 0xac}, + {0xa0, 0xa0, 0xa0, 0xa8}, + {0x0, 0x0, 0x2, 0x2}, + {0x30, 0x30, 0x40, 0x40}, + {0x0, 0xa5, 0xfb, 0xf6} +}; +UCHAR SiS310_CR40[5][4] = { + {0x77, 0x77, 0x33, 0x33}, + {0x77, 0x77, 0x33, 0x33}, + {0x0, 0x0, 0x0, 0x0}, + {0x5b, 0x5b, 0x3, 0x3}, + {0x0, 0x0, 0xf0, 0xf8} +}; +UCHAR SiS310_CR49[] = { 0xaa, 0x88 }; +UCHAR SiS310_SR1F = 0x0; +UCHAR SiS310_SR21 = 0xa5; +UCHAR SiS310_SR22 = 0xfb; +UCHAR SiS310_SR23 = 0xf6; +UCHAR SiS310_SR24 = 0xd; +UCHAR SiS310_SR25[] = { 0x33, 0x3 }; +UCHAR SiS310_SR31 = 0x0; +UCHAR SiS310_SR32 = 0x11; +UCHAR SiS310_SR33 = 0x0; +UCHAR SiS310_CRT2Data_1_2 = 0x0; +UCHAR SiS310_CRT2Data_4_D = 0x0; +UCHAR SiS310_CRT2Data_4_E = 0x0; +UCHAR SiS310_CRT2Data_4_10 = 0x80; +USHORT SiS310_RGBSenseData = 0xd1; +USHORT SiS310_VideoSenseData = 0xb9; +USHORT SiS310_YCSenseData = 0xb3; +USHORT SiS310_RGBSenseData2 = 0x0190; /*301b */ +USHORT SiS310_VideoSenseData2 = 0x0174; +USHORT SiS310_YCSenseData2 = 0x016b; +UCHAR SiS310_NTSCPhase[] = { 0x21, 0xed, 0x8a, 0x8 }; +UCHAR SiS310_PALPhase[] = { 0x2a, 0x5, 0xd3, 0x0 }; +UCHAR SiS310_NTSCPhase2[] = { 0x21, 0xF0, 0x7B, 0xD6 }; /*301b */ +UCHAR SiS310_PALPhase2[] = { 0x2a, 0x09, 0x86, 0xe9 }; +UCHAR SiS310_PALMPhase[] = { 0x21, 0xE4, 0x2E, 0x9B }; /*palmn */ +UCHAR SiS310_PALNPhase[] = { 0x21, 0xF4, 0x3E, 0xBA }; + +typedef struct _SiS310_LCDDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS310_LCDDataStruct; +SiS310_LCDDataStruct SiS310_StLCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_ExtLCD1024x768Data[] = { + {12, 5, 896, 512, 1344, 806}, + {12, 5, 896, 510, 1344, 806}, + {32, 15, 1008, 505, 1344, 806}, + {32, 15, 1008, 514, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_St2LCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_StLCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = { + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 500, 1688, 1066}, + {211, 75, 1024, 625, 1688, 1066}, + {211, 120, 1280, 798, 1688, 1066}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_St2LCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_NoScaleData[] = { + {1, 1, 800, 449, 800, 449}, + {1, 1, 800, 449, 800, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 800, 525, 800, 525}, + {1, 1, 1056, 628, 1056, 628}, + {1, 1, 1344, 806, 1344, 806}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_LCD1280x960Data[] = { + {9, 2, 800, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {30, 11, 1056, 625, 1800, 1000}, + {5, 3, 1350, 800, 1800, 1000}, + {1, 1, 1576, 1050, 1576, 1050}, + {1, 1, 1800, 1000, 1800, 1000} +}; + +typedef struct _SiS310_TVDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} SiS310_TVDataStruct; +SiS310_TVDataStruct SiS310_StPALData[] = { + {1, 1, 864, 525, 1270, 400, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 350, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 864, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 864, 525, 1270, 480, 50, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 600, 50, 0, 0, 0xf4, 0xff, 0x1c, 0x22} +}; + +SiS310_TVDataStruct SiS310_ExtPALData[] = { + {27, 10, 848, 448, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {108, 35, 848, 398, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {12, 5, 954, 448, 1270, 530, 50, 0, 50, 0xf1, 0x04, 0x1f, 0x18}, + {9, 4, 960, 463, 1644, 438, 50, 0, 50, 0xf4, 0x0b, 0x1c, 0x0a}, + {9, 4, 848, 528, 1270, 530, 0, 0, 50, 0xf5, 0xfb, 0x1b, 0x2a}, + {36, 25, 1060, 648, 1316, 530, 438, 0, 438, 0xeb, 0x05, 0x25, 0x16}, + {3, 2, 1080, 619, 1270, 540, 438, 0, 438, 0xf3, 0x00, 0x1d, 0x20}, + {1, 1, 1170, 821, 1270, 520, 686, 0, 686, 0xF3, 0x00, 0x1D, 0x20} /*301b */ +}; + +SiS310_TVDataStruct SiS310_StNTSCData[] = { + {1, 1, 858, 525, 1270, 400, 50, 0, 760, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 50, 0, 640, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 858, 525, 1270, 480, 0, 0, 760, 0xf1, 0x04, 0x1f, 0x18} +}; + +SiS310_TVDataStruct SiS310_ExtNTSCData[] = { + {143, 65, 858, 443, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {88, 35, 858, 393, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 443, 1270, 440, 92, 0, 92, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 393, 1270, 440, 92, 0, 92, 0xf4, 0x0b, 0x1c, 0x0a}, + {143, 76, 836, 523, 1270, 440, 224, 0, 0, 0xf1, 0x05, 0x1f, 0x16}, + {143, 120, 1056, 643, 1270, 440, 0, 128, 0, 0xf4, 0x10, 0x1c, 0x00}, + {2, 1, 858, 503, 1270, 480, 0, 128, 0, 0xee, 0x0c, 0x22, 0x08}, + {65, 64, 1056, 791, 1270, 480, 638, 0, 0, 0xEE, 0x0C, 0x22, 0x08} /*301b */ +}; + +SiS310_TVDataStruct SiS310_St1HiTVData[] = { + {0x00} +}; + +SiS310_TVDataStruct SiS310_St2HiTVData[] = { + {0x00} +}; + +SiS310_TVDataStruct SiS310_ExtHiTVData[] = { + {0x00} +}; + +UCHAR SiS310_NTSCTiming[] = { + 0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c, + 0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a, + 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b, + 0x0c, 0x50, 0x00, 0x97, 0x00, 0xda, 0x4a, 0x17, + 0x7d, 0x05, 0x4b, 0x00, 0x00, 0xe2, 0x00, 0x02, + 0x03, 0x0a, 0x65, 0x9d, 0x08, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x50, + 0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00 +}; + +UCHAR SiS310_PALTiming[] = { + 0x19, 0x52, 0x35, 0x6e, 0x04, 0x38, 0x3d, 0x70, + 0x94, 0x49, 0x01, 0x12, 0x06, 0x3e, 0x35, 0x6d, + 0x06, 0x14, 0x3e, 0x35, 0x6d, 0x00, 0x45, 0x2b, + 0x70, 0x50, 0x00, 0x9b, 0x00, 0xd9, 0x5d, 0x17, + 0x7d, 0x05, 0x45, 0x00, 0x00, 0xe8, 0x00, 0x02, + 0x0d, 0x00, 0x68, 0xb0, 0x0b, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x63, + 0x00, 0x40, 0x3e, 0x00, 0xe1, 0x02, 0x28, 0x00 +}; + +UCHAR SiS310_HiTVExtTiming[] = { 0x00 }; + +UCHAR SiS310_HiTVSt1Timing[] = { 0x00 }; + +UCHAR SiS310_HiTVSt2Timing[] = { 0x00 }; + +UCHAR SiS310_HiTVTextTiming[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Data[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Simu[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Text[] = { 0x00 }; + +typedef struct _SiS310_PanelDelayTblStruct { + UCHAR timer[2]; +} SiS310_PanelDelayTblStruct; +SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[] = { + {{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}} +}; + +typedef struct _SiS310_LVDSDataStruct { + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS310_LVDSDataStruct; +SiS310_LVDSDataStruct SiS310_LVDS800x600Data_1[] = { + {848, 433, 1060, 629}, + {848, 389, 1060, 629}, + {848, 433, 1060, 629}, + {848, 389, 1060, 629}, + {848, 518, 1060, 629}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {800, 449, 1000, 644}, + {800, 525, 1000, 635} +}; + +SiS310_LVDSDataStruct SiS310_LVDS800x600Data_2[] = { + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {800, 449, 1000, 644}, + {800, 525, 1000, 635} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1024x768Data_1[] = { + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 518, 1344, 806}, + {1050, 638, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1024x768Data_2[] = { + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1280x1024Data_1[] = { + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 518, 1344, 806}, + {1050, 638, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1280x1024Data_2[] = { + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS640x480Data_1[] = { + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 525, 800, 525}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628} +}; + +SiS310_LVDSDataStruct SiS310_CHTVUNTSCData[] = { + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {784, 600, 784, 600}, + {1064, 750, 1064, 750} +}; + +SiS310_LVDSDataStruct SiS310_CHTVONTSCData[] = { + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {784, 525, 784, 525}, + {1040, 700, 1040, 700} +}; + +SiS310_LVDSDataStruct SiS310_CHTVUPALData[] = { + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {840, 750, 840, 750}, + {936, 836, 936, 836} +}; + +SiS310_LVDSDataStruct SiS310_CHTVOPALData[] = { + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {840, 625, 840, 625}, + {960, 750, 960, 750} +}; + +typedef struct _SiS310_LVDSDesStruct { + USHORT LCDHDES; + USHORT LCDVDES; +} SiS310_LVDSDesStruct; +SiS310_LVDSDesStruct SiS310_PanelType00_1[] = { + {0, 626}, + {0, 624}, + {0, 626}, + {0, 624}, + {0, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType01_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType02_1[] = { + {0, 626}, + {0, 624}, + {0, 626}, + {0, 624}, + {0, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType03_1[] = { + {8, 436}, + {8, 440}, + {8, 436}, + {8, 440}, + {8, 512}, + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794} +}; + +SiS310_LVDSDesStruct SiS310_PanelType04_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType05_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType06_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType07_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType08_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType09_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0a_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0b_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0c_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0d_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0e_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0f_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType00_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType01_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType02_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType03_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {1152, 622}, + {1152, 597} +}; + +SiS310_LVDSDesStruct SiS310_PanelType04_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType05_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType06_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType07_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType08_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType09_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0a_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0b_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0c_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0d_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0e_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0f_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; +/*301b*/ +SiS310_LVDSDesStruct SiS310_PanelType1076_1[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1210_1[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1296_1[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1076_2[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1210_2[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1296_2[] = { + {0x00, 0x00} +}; +/*end 301b*/ + +SiS310_LVDSDesStruct SiS310_CHTVUNTSCDesData[] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVONTSCDesData[] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVUPALDesData[] = { + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVOPALDesData[] = { + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + {0, 0}, + {0, 0} +}; + +/*add for LCDA*/ +typedef struct _SiS310_LCDACRT1DataStruct { + UCHAR CR[17]; +} SiS310_LCDACRT1DataStruct; +SiS310_LCDACRT1DataStruct SiS310_LCDACRT1800x600_1[] = { + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x05, + 0x00}}, + {{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_1[] = { + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0xDf, 0x05, 0x00, 0x00, 0x05, + 0x00}}, + {{0x87, 0x63, 0x63, 0x8B, 0x69, 0x1A, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x57, 0x7D, 0x20, 0x00, 0x26, + 0x01}}, + {{0xA3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0xFf, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_1[] = { + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x01, + 0x00}}, + {{0x7e, 0x63, 0x82, 0x68, 0x15, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x26, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT1800x600_1_H[] = { + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x04, + 0x00}}, + {{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_1_H[] = { + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0xDf, 0x05, 0x00, 0x00, 0x44, + 0x00}}, + {{0x41, 0x31, 0x31, 0x85, 0x35, 0x1d, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x57, 0x7D, 0x20, 0x00, 0x55, + 0x01}}, + {{0x4f, 0x3F, 0x3F, 0x93, 0x45, 0x0D, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0xFf, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_1_H[] = { + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x04, + 0x00}}, + {{0x3c, 0x31, 0x80, 0x35, 0x1c, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x55, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT1800x600_2[] = { + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_2[] = { + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_2[] = { + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT1800x600_2_H[] = { + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x3a, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_2_H[] = { + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x31, 0x93, 0x3e, 0x06, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_2_H[] = { + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x31, 0x93, 0x3e, 0x86, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +typedef struct _SiS310_LVDSCRT1DataStruct { + UCHAR CR[15]; +} SiS310_LVDSCRT1DataStruct; +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1[] = { + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x05, + 0x00}}, + {{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1[] = { + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0x05, 0x00, 0x00, 0x05, + 0x00}}, + {{0x87, 0x63, 0x8B, 0x69, 0x1A, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x7D, 0x20, 0x00, 0x26, + 0x01}}, + {{0xA3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1[] = { + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x01, + 0x00}}, + {{0x7e, 0x63, 0x82, 0x68, 0x15, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x26, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1_H[] = { + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x04, + 0x00}}, + {{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1_H[] = { + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0x05, 0x00, 0x00, 0x44, + 0x00}}, + {{0x41, 0x31, 0x85, 0x35, 0x1d, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x7D, 0x20, 0x00, 0x55, + 0x01}}, + {{0x4f, 0x3F, 0x93, 0x45, 0x0D, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1_H[] = { + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x04, + 0x00}}, + {{0x3c, 0x31, 0x80, 0x35, 0x1c, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x55, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2[] = { + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2[] = { + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2[] = { + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2_H[] = { + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x3a, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2_H[] = { + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x31, 0x93, 0x3e, 0x06, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2_H[] = { + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x31, 0x93, 0x3e, 0x86, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = { + {{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xe8, 0x84, 0x8f, 0x57, 0x20, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xd0, 0x82, 0x5d, 0x57, 0x00, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xe8, 0x84, 0x8f, 0x57, 0x20, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xd0, 0x82, 0x5d, 0x57, 0x00, 0x00, 0x01, + 0x00}}, + {{0x5d, 0x4f, 0x81, 0x53, 0x9c, 0x56, 0xba, + 0x18, 0x84, 0xdf, 0x57, 0x00, 0x00, 0x01, + 0x00}}, + {{0x80, 0x63, 0x84, 0x6c, 0x17, 0xec, 0xf0, + 0x90, 0x8c, 0x57, 0xed, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = { + {{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xc0, 0x84, 0x8f, 0x0c, 0x20, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xb0, 0x8d, 0x5d, 0x0c, 0x00, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xc0, 0x84, 0x8f, 0x0c, 0x20, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xb0, 0x8d, 0x5d, 0x0c, 0x00, 0x00, 0x01, + 0x00}}, + {{0x5d, 0x4f, 0x81, 0x56, 0x9c, 0x0b, 0x3e, + 0xe8, 0x84, 0xdf, 0x0c, 0x00, 0x00, 0x01, + 0x00}}, + {{0x7d, 0x63, 0x81, 0x6a, 0x16, 0xba, 0xf0, + 0x7f, 0x86, 0x57, 0xbb, 0x00, 0x00, 0x06, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = { + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf8, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf8, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x55, 0x80, 0xec, 0xba, + 0x50, 0x84, 0xdf, 0xed, 0x00, 0x00, 0x05, + 0x00}}, + {{0x70, 0x63, 0x94, 0x68, 0x8d, 0x42, 0xf1, + 0xc8, 0x8c, 0x57, 0xe9, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = { + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf0, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf0, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x55, 0x80, 0x6f, 0xba, + 0x20, 0x83, 0xdf, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x73, 0x63, 0x97, 0x69, 0x8e, 0xec, 0xf0, + 0x90, 0x8c, 0x57, 0xed, 0x20, 0x00, 0x05, + 0x01}} +}; + +typedef struct _SiS310_CHTVRegDataStruct { + UCHAR Reg[5]; +} SiS310_CHTVRegDataStruct; +SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = { + {{0x00}} +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = { + {{0x00}} +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = { + {{0x00}} +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = { + {{0x00}} +}; + +UCHAR SiS310_CHTVVCLKUNTSC[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKONTSC[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKUPAL[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKOPAL[] = { 0x00 }; diff --git a/drivers/video/sis/325vtbl.h b/drivers/video/sis/325vtbl.h new file mode 100644 index 000000000000..16a1e597b093 --- /dev/null +++ b/drivers/video/sis/325vtbl.h @@ -0,0 +1,2318 @@ +typedef struct _SiS310_StStruct { + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; +} SiS310_StStruct; +SiS310_StStruct SiS310_SModeIDTable[] = +{ + {0x01, 0x9208, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, + {0x01, 0x1210, 0x14, 0x01, 0x01, 0x00, 0x01, 0x00}, + {0x01, 0x1010, 0x17, 0x02, 0x02, 0x00, 0x01, 0x01}, + {0x03, 0x8208, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02}, + {0x03, 0x0210, 0x16, 0x01, 0x01, 0x00, 0x01, 0x02}, + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03}, + {0x05, 0x9209, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x06, 0x8209, 0x06, 0x00, 0x00, 0x00, 0x00, 0x05}, + {0x07, 0x0000, 0x07, 0x03, 0x03, 0x00, 0x01, 0x03}, + {0x07, 0x0000, 0x19, 0x02, 0x02, 0x00, 0x01, 0x03}, + {0x0d, 0x920a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x0e, 0x820a, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x05}, + {0x0f, 0x0202, 0x11, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0x10, 0x0212, 0x12, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0x11, 0x0212, 0x1a, 0x04, 0x04, 0x00, 0x00, 0x05}, + {0x12, 0x0212, 0x1b, 0x04, 0x04, 0x00, 0x00, 0x05}, + {0x13, 0x021b, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x12, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x00, 0x05}, + {0x12, 0x0210, 0x18, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +typedef struct _SiS310_StandTableStruct { + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} SiS310_StandTableStruct; + +SiS310_StandTableStruct SiS310_StandTable[] = { +/* MD_0_200 */ + { + 0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_1_200 */ + { + 0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_200 */ + { + 0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_3_200 */ + { + 0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_4 */ + { + 0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff} + }, +/* MD_5 */ + { + 0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff} + }, +/* MD_6 */ + { + 0x50, 0x18, 0x08, 0x4000, + {0x01, 0x01, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, + 0xff}, + {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x01, 0x00, 0x01, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0xff} + }, +/* MD_7 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x00, 0x03, 0x00, 0x03}, + 0xa6, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff} + }, +/* MDA_DAC */ + { + 0x00, 0x00, 0x00, 0x0000, + {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} + }, +/* CGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {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} + }, +/* EGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {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} + }, +/* VGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {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, 0x0a08, + {0x0c, 0x0e, 0x10, 0x0b}, + 0x0c, + {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, + 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00, + 0x06}, + {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08, + 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} + }, +/* MD_D */ + { + 0x28, 0x18, 0x08, 0x2000, + {0x09, 0x0f, 0x00, 0x06}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_E */ + { + 0x50, 0x18, 0x08, 0x4000, + {0x01, 0x0f, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* ExtVGATable */ + { + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} + }, +/* ROM_SAVEPTR */ + { + 0x9f, 0x3b, 0x00, 0x00c0, + {0x00, 0x00, 0x00, 0x00}, + 0x00, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x3f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0x00, 0xac, 0x3e, 0x00, 0xc0, + 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} + }, +/* MD_F */ + { + 0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa2, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x0b, 0x00, 0x05, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, + 0xff} + }, +/* MD_10 */ + { + 0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_0_350 */ + { + 0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_1_350 */ + { + 0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_350 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_3_350 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_0_1_400 */ + { + 0x28, 0x18, 0x10, 0x0800, + {0x08, 0x03, 0x00, 0x02}, + 0x67, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_3_400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_7_400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x66, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff} + }, +/* MD_11 */ + { + 0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3, + 0xff}, + {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, + 0xff} + }, +/* ExtEGATable */ + { + 0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_13 */ + { + 0x28, 0x18, 0x08, 0x2000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x41, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} + } +}; + +typedef struct _SiS310_ExtStruct { + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_ModeInfo; + USHORT Ext_Point; + USHORT Ext_VESAID; + UCHAR Ext_VESAMEMSize; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR REFindex; +} SiS310_ExtStruct; +SiS310_ExtStruct SiS310_EModeIDTable[] = { + + {0x6a, 0x2212, 0x0407, 0x3a81, 0x0102, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x2e, 0x0a1b, 0x0306, 0x3a57, 0x0101, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x2f, 0x0a1b, 0x0305, 0x3a50, 0x0100, 0x08, 0x05, 0x00, 0x00, 0x05, + 0x10}, + {0x30, 0x2a1b, 0x0407, 0x3a81, 0x0103, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x31, 0x0a1b, 0x030d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x32, 0x0a1b, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x33, 0x0a1d, 0x0a0d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x34, 0x2a1d, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x35, 0x0a1f, 0x0a0d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x36, 0x2a1f, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x37, 0x0212, 0x0508, 0x3aab, 0x0104, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x38, 0x0a1b, 0x0508, 0x3aab, 0x0105, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x3a, 0x0e3b, 0x0609, 0x3adc, 0x0107, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x3c, 0x063b, 0x070a, 0x3af2, 0x0130, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x3d, 0x067d, 0x070a, 0x3af2, 0x0131, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x40, 0x9a1c, 0x0000, 0x3a34, 0x010d, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x41, 0x9a1d, 0x0000, 0x3a34, 0x010e, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x43, 0x0a1c, 0x0306, 0x3a57, 0x0110, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x44, 0x0a1d, 0x0306, 0x3a57, 0x0111, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x46, 0x2a1c, 0x0407, 0x3a81, 0x0113, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x47, 0x2a1d, 0x0407, 0x3a81, 0x0114, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x49, 0x0a3c, 0x0508, 0x3aab, 0x0116, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x4a, 0x0a3d, 0x0508, 0x3aab, 0x0117, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x4c, 0x0e7c, 0x0609, 0x3adc, 0x0119, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x4d, 0x0e7d, 0x0609, 0x3adc, 0x011a, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x50, 0x9a1b, 0x0001, 0x3a3b, 0x0132, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x26}, + {0x51, 0xba1b, 0x0103, 0x3a42, 0x0133, 0x08, 0x03, 0x00, 0x00, 0x07, + 0x27}, + {0x52, 0x9a1b, 0x0204, 0x3a49, 0x0134, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x28}, + {0x56, 0x9a1d, 0x0001, 0x3a3b, 0x0135, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x26}, + {0x57, 0xba1d, 0x0103, 0x3a42, 0x0136, 0x08, 0x03, 0x00, 0x00, 0x07, + 0x27}, + {0x58, 0x9a1d, 0x0204, 0x3a49, 0x0137, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x28}, + {0x59, 0x9a1b, 0x0000, 0x3a34, 0x0138, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x5d, 0x0a1d, 0x0305, 0x3a50, 0x0139, 0x08, 0x05, 0x00, 0x00, 0x07, + 0x10}, + {0x62, 0x0a3f, 0x0306, 0x3a57, 0x013a, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x63, 0x2a3f, 0x0407, 0x3a81, 0x013b, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x64, 0x0a7f, 0x0508, 0x3aab, 0x013c, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x65, 0x0eff, 0x0609, 0x3adc, 0x013d, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x66, 0x06ff, 0x070a, 0x3af2, 0x013e, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x68, 0x067b, 0x080b, 0x3b17, 0x013f, 0x08, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x69, 0x06fd, 0x080b, 0x3b17, 0x0140, 0x08, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x6b, 0x07ff, 0x080b, 0x3b17, 0x0141, 0x10, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x6c, 0x067b, 0x090c, 0x3b37, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x6d, 0x06fd, 0x090c, 0x3b37, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x6e, 0x07ff, 0x090c, 0x3b37, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x70, 0x2a1b, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x71, 0x0a1b, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x74, 0x0a1d, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x75, 0x0a3d, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x76, 0x2a1f, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x77, 0x0a1f, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x78, 0x0a3f, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x79, 0x0a3b, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x7a, 0x2a1d, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x7b, 0x0e3b, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0x7c, 0x0e7d, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0x7d, 0x0eff, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0xff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} +}; + +typedef struct _SiS310_Ext2Struct { + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + USHORT ROM_OFFSET; +} SiS310_Ext2Struct; +SiS310_Ext2Struct SiS310_RefIndex[] = { + {0x005f, 0x0d, 0x03, 0x05, 0x6a, 800, 600, 0x3a81}, /* 0x0 */ + {0x0467, 0x0e, 0x04, 0x05, 0x6a, 800, 600, 0x3a86}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x6a, 800, 600, 0x3a8b}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x6a, 800, 600, 0x3a90}, /* 0x3 */ + {0x0147, 0x11, 0x0a, 0x00, 0x6a, 800, 600, 0x3a95}, /* 0x4 */ + {0x4147, 0x12, 0x0d, 0x00, 0x6a, 800, 600, 0x3a9a}, /* 0x5 */ + {0x4047, 0x13, 0x13, 0x00, 0x6a, 800, 600, 0x3a9f}, /* 0x6 */ + {0x4047, 0x14, 0x1c, 0x00, 0x6a, 800, 600, 0x3aa4}, /* 0x7 */ + {0xc05f, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x3a57}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x2e, 640, 480, 0x3a5c}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x2e, 640, 480, 0x3a61}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x2e, 640, 480, 0x3a66}, /* 0xb */ + {0x4047, 0x09, 0x05, 0x00, 0x2e, 640, 480, 0x3a6b}, /* 0xc */ + {0x4047, 0x0a, 0x09, 0x00, 0x2e, 640, 480, 0x3a70}, /* 0xd */ + {0x4047, 0x0b, 0x0e, 0x00, 0x2e, 640, 480, 0x3a75}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x2e, 640, 480, 0x3a7a}, /* 0xf */ + {0x407f, 0x04, 0x00, 0x00, 0x2f, 640, 400, 0x3a50}, /* 0x10 */ + {0xc00f, 0x3c, 0x01, 0x06, 0x31, 720, 480, 0x3b85}, /* 0x11 */ + {0x000f, 0x3d, 0x03, 0x06, 0x32, 720, 576, 0x3b8c}, /* 0x12 */ + {0x0187, 0x15, 0x06, 0x00, 0x37, 1024, 768, 0x3aab}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x37, 1024, 768, 0x3ab0}, /* 0x14 301b TV1024x768 */ + {0xc067, 0x17, 0x0f, 0x49, 0x37, 1024, 768, 0x3ab5}, /* 0x15 */ + {0x0267, 0x18, 0x11, 0x00, 0x37, 1024, 768, 0x3aba}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x37, 1024, 768, 0x3abf}, /* 0x17 */ + {0x4047, 0x1a, 0x1b, 0x00, 0x37, 1024, 768, 0x3ac4}, /* 0x18 */ + {0x4047, 0x1b, 0x1f, 0x00, 0x37, 1024, 768, 0x3ac9}, /* 0x19 */ + {0x0387, 0x1c, 0x11, 0x00, 0x3a, 1280, 1024, 0x3adc}, /* 0x1a */ + {0x0077, 0x1d, 0x19, 0x07, 0x3a, 1280, 1024, 0x3ae1}, /* 0x1b */ + {0x0047, 0x1e, 0x1e, 0x00, 0x3a, 1280, 1024, 0x3ae6}, /* 0x1c */ + {0x0007, 0x1f, 0x20, 0x00, 0x3a, 1280, 1024, 0x3aeb}, /* 0x1d */ + {0x0007, 0x20, 0x21, 0x00, 0x3c, 1600, 1200, 0x3af2}, /* 0x1e */ + {0x0007, 0x21, 0x22, 0x00, 0x3c, 1600, 1200, 0x3af7}, /* 0x1f */ + {0x0007, 0x22, 0x23, 0x00, 0x3c, 1600, 1200, 0x3afc}, /* 0x20 */ + {0x0007, 0x23, 0x25, 0x00, 0x3c, 1600, 1200, 0x3b01}, /* 0x21 */ + {0x0007, 0x24, 0x26, 0x00, 0x3c, 1600, 1200, 0x3b06}, /* 0x22 */ + {0x0007, 0x25, 0x2c, 0x00, 0x3c, 1600, 1200, 0x3b0b}, /* 0x23 */ + {0x0007, 0x26, 0x34, 0x00, 0x3c, 1600, 1200, 0x3b10}, /* 0x24 */ + {0x407f, 0x00, 0x00, 0x00, 0x40, 320, 200, 0x3a34}, /* 0x25 */ + {0xc07f, 0x01, 0x00, 0x04, 0x50, 320, 240, 0x3a3b}, /* 0x26 */ + {0x007f, 0x02, 0x04, 0x05, 0x51, 400, 300, 0x3a42}, /* 0x27 */ + {0xc077, 0x03, 0x0b, 0x06, 0x52, 512, 384, 0x3a49}, /* 0x28 */ + {0x8007, 0x27, 0x27, 0x00, 0x68, 1920, 1440, 0x3b17}, /* 0x29 */ + {0x4007, 0x28, 0x29, 0x00, 0x68, 1920, 1440, 0x3b1c}, /* 0x2a */ + {0x4007, 0x29, 0x2e, 0x00, 0x68, 1920, 1440, 0x3b21}, /* 0x2b */ + {0x4007, 0x2a, 0x30, 0x00, 0x68, 1920, 1440, 0x3b26}, /* 0x2c */ + {0x4007, 0x2b, 0x35, 0x00, 0x68, 1920, 1440, 0x3b2b}, /* 0x2d */ + {0x4005, 0x2c, 0x39, 0x00, 0x68, 1920, 1440, 0x3b30}, /* 0x2e */ + {0x4007, 0x2d, 0x2b, 0x00, 0x6c, 2048, 1536, 0x3b37}, /* 0x2f */ + {0x4007, 0x2e, 0x31, 0x00, 0x6c, 2048, 1536, 0x3b3c}, /* 0x30 */ + {0x4007, 0x2f, 0x33, 0x00, 0x6c, 2048, 1536, 0x3b41}, /* 0x31 */ + {0x4007, 0x30, 0x37, 0x00, 0x6c, 2048, 1536, 0x3b46}, /* 0x32 */ + {0x4005, 0x31, 0x38, 0x00, 0x6c, 2048, 1536, 0x3b4b}, /* 0x33 */ + {0x0057, 0x32, 0x40, 0x08, 0x70, 800, 480, 0x3b52}, /* 0x34 */ + {0x0047, 0x33, 0x07, 0x08, 0x70, 800, 480, 0x3b57}, /* 0x35 */ + {0x0047, 0x34, 0x0a, 0x08, 0x70, 800, 480, 0x3b5c}, /* 0x36 */ + {0x0057, 0x35, 0x0b, 0x09, 0x71, 1024, 576, 0x3b63}, /* 0x37 */ + {0x0047, 0x36, 0x11, 0x09, 0x71, 1024, 576, 0x3b68}, /* 0x38 */ + {0x0047, 0x37, 0x16, 0x09, 0x71, 1024, 576, 0x3b6d}, /* 0x39 */ + {0x0057, 0x38, 0x19, 0x0a, 0x75, 1280, 720, 0x3b74}, /* 0x3a */ + {0x0047, 0x39, 0x1e, 0x0a, 0x75, 1280, 720, 0x3b79}, /* 0x3b */ + {0x0047, 0x3a, 0x20, 0x0a, 0x75, 1280, 720, 0x3b7e}, /* 0x3c */ + {0x0027, 0x3b, 0x19, 0x08, 0x7b, 1280, 960, 0x3ad0}, /* 0x3d */ + {0x0027, 0x3b, 0x19, 0x08, 0x7b, 1280, 960, 0x3ad5}, /* 0x3e */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0000, 0000, 0x0000} +}; + +typedef struct _SiS310_CRT1TableStruct { + UCHAR CR[17]; +} SiS310_CRT1TableStruct; +SiS310_CRT1TableStruct SiS310_CRT1Table[] = { + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}, /* 0x0 */ + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}, /* 0x1 */ + {0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}, /* 0x2 */ + {0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}, /* 0x3 */ + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}, /* 0x4 */ + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}, /* 0x5 */ + {0x63, 0x4f, 0x50, 0x86, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8b, 0xdf, 0xe7, 0xff, 0x10, 0x00, 0x01, + 0x00}, /* 0x6 */ + {0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}, /* 0x7 */ + {0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}, /* 0x8 */ + {0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x00, 0x00, 0x05, + 0x61}, /* 0x9 */ + {0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}, /* 0xa */ + {0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x10, 0x00, 0x05, + 0x61}, /* 0xb */ + {0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xe5, 0xe5, 0xfc, 0x00, 0x00, 0x01, + 0x00}, /* 0xc */ + {0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}, /* 0xd */ + {0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}, /* 0xe */ + {0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}, /* 0xf */ + {0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}, /* 0x10 */ + {0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}, /* 0x11 */ + {0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}, /* 0x12 */ + {0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}, /* 0x13 */ + {0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}, /* 0x14 */ + {0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}, /* 0x15 */ + {0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}, /* 0x16 */ + {0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}, /* 0x17 */ + {0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}, /* 0x18 */ + {0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}, /* 0x19 */ + {0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}, /* 0x1a */ + {0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}, /* 0x1b */ + {0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}, /* 0x1c */ + {0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}, /* 0x1d */ + {0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}, /* 0x1e */ + {0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}, /* 0x1f */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x20 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x21 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x22 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x23 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x24 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x25 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x26 */ + {0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}, /* 0x27 */ + {0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}, /* 0x28 */ + {0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}, /* 0x29 */ + {0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}, /* 0x2a */ + {0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}, /* 0x2b */ + {0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}, /* 0x2c */ + {0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}, /* 0x2d */ + {0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}, /* 0x2e */ + {0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}, /* 0x2f */ + {0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}, /* 0x30 */ + {0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}, /* 0x31 */ + {0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}, /* 0x32 */ + {0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}, /* 0x33 */ + {0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}, /* 0x34 */ + {0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}, /* 0x35 */ + {0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}, /* 0x36 */ + {0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x15, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}, /* 0x37 */ + {0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}, /* 0x38 */ + {0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}, /* 0x39 */ + {0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}, /* 0x3a */ + {0xdc, 0x9f, 0x9f, 0x00, 0xab, 0x19, 0xe6, 0xef, + 0xc0, 0xc3, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}, /* 0x3b */ + {0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}, /* 0x3c */ + {0x7b, 0x59, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x3f, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01} /* 0x3d */ +}; + +typedef struct _SiS310_MCLKDataStruct { + UCHAR SR28, SR29, SR2A; + USHORT CLOCK; +} SiS310_MCLKDataStruct; +SiS310_MCLKDataStruct SiS310_MCLKData[] = { + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166} +}; + +typedef struct _SiS310_ECLKDataStruct { + UCHAR SR2E, SR2F, SR30; + USHORT CLOCK; +} SiS310_ECLKDataStruct; +SiS310_ECLKDataStruct SiS310_ECLKData[] = { + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166} +}; + +typedef struct _SiS310_VCLKDataStruct { + UCHAR SR2B, SR2C; + USHORT CLOCK; +} SiS310_VCLKDataStruct; +SiS310_VCLKDataStruct SiS310_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x0 */ + {0x4e, 0xe4, 28}, /* 0x1 */ + {0x57, 0xe4, 31}, /* 0x2 */ + {0xc3, 0xc8, 36}, /* 0x3 */ + {0x42, 0xe2, 40}, /* 0x4 */ + {0xfe, 0xcd, 43}, /* 0x5 */ + {0x5d, 0xc4, 44}, /* 0x6 */ + {0x52, 0xe2, 49}, /* 0x7 */ + {0x53, 0xe2, 50}, /* 0x8 */ + {0x74, 0x67, 52}, /* 0x9 */ + {0x6d, 0x66, 56}, /* 0xa */ + {0x6c, 0xc3, 65}, /* 0xb */ + {0x46, 0x44, 67}, /* 0xc */ + {0xb1, 0x46, 68}, /* 0xd */ + {0xd3, 0x4a, 72}, /* 0xe */ + {0x29, 0x61, 75}, /* 0xf */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a */ + {0x52, 0x6a, 27}, /* 0x3b */ + {0x62, 0x24, 70}, /* 0x3c */ + {0x62, 0x64, 70}, /* 0x3d */ + {0xa8, 0x4c, 30}, /* 0x3e */ + {0x20, 0x26, 33}, /* 0x3f */ + {0x31, 0xc2, 39} /* 0x40 */ +}; + +typedef struct _SiS310_VBVCLKDataStruct { + UCHAR Part4_A, Part4_B; + USHORT CLOCK; +} SiS310_VBVCLKDataStruct; +SiS310_VBVCLKDataStruct SiS310_VBVCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x0 */ + {0x4e, 0xe4, 28}, /* 0x1 */ + {0x57, 0xe4, 31}, /* 0x2 */ + {0xc3, 0xc8, 36}, /* 0x3 */ + {0x42, 0x47, 40}, /* 0x4 */ + {0xfe, 0xcd, 43}, /* 0x5 */ + {0x5d, 0xc4, 44}, /* 0x6 */ + {0x52, 0x47, 49}, /* 0x7 */ + {0x53, 0x47, 50}, /* 0x8 */ + {0x74, 0x67, 52}, /* 0x9 */ + {0x6d, 0x66, 56}, /* 0xa */ + {0x5a, 0x64, 65}, /* 0xb */ + {0x46, 0x44, 67}, /* 0xc */ + {0xb1, 0x46, 68}, /* 0xd */ + {0xd3, 0x4a, 72}, /* 0xe */ + {0x29, 0x61, 75}, /* 0xf */ + {0x6d, 0x46, 75}, /* 0x10 */ + {0x41, 0x43, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x22, 104}, /* 0x17 */ + {0x49, 0x24, 105}, /* 0x18 */ + {0xf8, 0x2f, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0xd4, 0x28, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x70, 0x07, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a */ + {0x52, 0x6a, 27}, /* 0x3b */ + {0x62, 0x24, 70}, /* 0x3c */ + {0x62, 0x64, 70}, /* 0x3d */ + {0xa8, 0x4c, 30}, /* 0x3e */ + {0x20, 0x26, 33}, /* 0x3f */ + {0x31, 0xc2, 39} /* 0x40 */ +}; + +UCHAR SiS310_ScreenOffset[] = + { 0x14, 0x19, 0x20, 0x28, 0x32, 0x40, 0x50, 0x64, 0x78, 0x80, 0x2d, 0x35 }; + +typedef struct _SiS310_StResInfoStruct { + USHORT HTotal; + USHORT VTotal; +} SiS310_StResInfoStruct; +SiS310_StResInfoStruct SiS310_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} +}; + +typedef struct _SiS310_ModeResInfoStruct { + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} SiS310_ModeResInfoStruct; +SiS310_ModeResInfoStruct SiS310_ModeResInfo[] = { + {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}, + {2048, 1536, 8, 16}, + {720, 480, 8, 16}, + {720, 576, 8, 16}, + {1280, 960, 8, 16}, + {800, 480, 8, 16}, + {1024, 576, 8, 16}, + {1280, 720, 8, 16} +}; + +UCHAR SiS310_OutputSelect = 0; +UCHAR SiS310_SoftSetting = 30; +UCHAR SiS310_SR07 = 0x18; +UCHAR SiS310_SR15[8][4] = { + {0x0, 0x4, 0x60, 0x60}, + {0xf, 0xf, 0xf, 0xf}, + {0xba, 0xba, 0xba, 0xba}, + {0xa9, 0xa9, 0xac, 0xac}, + {0xa0, 0xa0, 0xa0, 0xa8}, + {0x0, 0x0, 0x2, 0x2}, + {0x30, 0x30, 0x40, 0x40}, + {0x0, 0xa5, 0xfb, 0xf6} +}; +UCHAR SiS310_CR40[5][4] = { + {0x77, 0x77, 0x33, 0x33}, + {0x77, 0x77, 0x33, 0x33}, + {0x0, 0x0, 0x0, 0x0}, + {0x5b, 0x5b, 0x3, 0x3}, + {0x0, 0x0, 0xf0, 0xf8} +}; +UCHAR SiS310_CR49[] = { 0xaa, 0x88 }; +UCHAR SiS310_SR1F = 0x0; +UCHAR SiS310_SR21 = 0xa5; +UCHAR SiS310_SR22 = 0xfb; +UCHAR SiS310_SR23 = 0xf6; +UCHAR SiS310_SR24 = 0xd; +UCHAR SiS310_SR25[] = { 0x33, 0x3 }; +UCHAR SiS310_SR31 = 0x0; +UCHAR SiS310_SR32 = 0x11; +UCHAR SiS310_SR33 = 0x0; +UCHAR SiS310_CRT2Data_1_2 = 0x0; +UCHAR SiS310_CRT2Data_4_D = 0x0; +UCHAR SiS310_CRT2Data_4_E = 0x0; +UCHAR SiS310_CRT2Data_4_10 = 0x80; +USHORT SiS310_RGBSenseData = 0xd1; +USHORT SiS310_VideoSenseData = 0xb9; +USHORT SiS310_YCSenseData = 0xb3; +USHORT SiS310_RGBSenseData2 = 0x0190; /*301b */ +USHORT SiS310_VideoSenseData2 = 0x0174; +USHORT SiS310_YCSenseData2 = 0x016b; +UCHAR SiS310_NTSCPhase[] = { 0x21, 0xed, 0x8a, 0x8 }; + +UCHAR SiS310_PALPhase[] = { 0x2a, 0x5, 0xd3, 0x0 }; + +typedef struct _SiS310_LCDDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS310_LCDDataStruct; +SiS310_LCDDataStruct SiS310_StLCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_ExtLCD1024x768Data[] = { + {12, 5, 896, 512, 1344, 806}, + {12, 5, 896, 510, 1344, 806}, + {32, 15, 1008, 505, 1344, 806}, + {32, 15, 1008, 514, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_St2LCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_StLCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = { + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 500, 1688, 1066}, + {211, 75, 1024, 625, 1688, 1066}, + {211, 120, 1280, 798, 1688, 1066}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_St2LCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_NoScaleData[] = { + {1, 1, 800, 449, 800, 449}, + {1, 1, 800, 449, 800, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 800, 525, 800, 525}, + {1, 1, 1056, 628, 1056, 628}, + {1, 1, 1344, 806, 1344, 806}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_LCD1280x960Data[] = { + {9, 2, 800, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {30, 11, 1056, 625, 1800, 1000}, + {5, 3, 1350, 800, 1800, 1000}, + {1, 1, 1576, 1050, 1576, 1050}, + {1, 1, 1800, 1000, 1800, 1000} +}; + +typedef struct _SiS310_TVDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} SiS310_TVDataStruct; +SiS310_TVDataStruct SiS310_StPALData[] = { + {1, 1, 864, 525, 1270, 400, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 350, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 864, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 864, 525, 1270, 480, 50, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 600, 50, 0, 0, 0xf4, 0xff, 0x1c, 0x22} +}; + +SiS310_TVDataStruct SiS310_ExtPALData[] = { + {27, 10, 848, 448, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {108, 35, 848, 398, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {12, 5, 954, 448, 1270, 530, 50, 0, 50, 0xf1, 0x04, 0x1f, 0x18}, + {9, 4, 960, 463, 1644, 438, 50, 0, 50, 0xf4, 0x0b, 0x1c, 0x0a}, + {9, 4, 848, 528, 1270, 530, 0, 0, 50, 0xf5, 0xfb, 0x1b, 0x2a}, + {36, 25, 1060, 648, 1316, 530, 438, 0, 438, 0xeb, 0x05, 0x25, 0x16}, + {3, 2, 1080, 619, 1270, 540, 438, 0, 438, 0xf3, 0x00, 0x1d, 0x20}, + {1, 1, 1170, 821, 1270, 520, 686, 0, 686, 0xF3, 0x00, 0x1D, 0x20} /*301b */ +}; + +SiS310_TVDataStruct SiS310_StNTSCData[] = { + {1, 1, 858, 525, 1270, 400, 50, 0, 760, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 50, 0, 640, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 858, 525, 1270, 480, 0, 0, 760, 0xf1, 0x04, 0x1f, 0x18} +}; + +SiS310_TVDataStruct SiS310_ExtNTSCData[] = { + {143, 65, 858, 443, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {88, 35, 858, 393, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 443, 1270, 440, 92, 0, 92, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 393, 1270, 440, 92, 0, 92, 0xf4, 0x0b, 0x1c, 0x0a}, + {143, 76, 836, 523, 1270, 440, 224, 0, 0, 0xf1, 0x05, 0x1f, 0x16}, + {143, 120, 1056, 643, 1288, 440, 0, 128, 0, 0xf4, 0x10, 0x1c, 0x00}, + {2, 1, 858, 503, 1270, 480, 0, 128, 0, 0xee, 0x0c, 0x22, 0x08}, + {65, 64, 1056, 791, 1270, 480, 638, 0, 0, 0xEE, 0x0C, 0x22, 0x08} /*301b */ +}; + +SiS310_TVDataStruct SiS310_St1HiTVData[] = { + 0x00 +}; + +SiS310_TVDataStruct SiS310_St2HiTVData[] = { + 0x00 +}; + +SiS310_TVDataStruct SiS310_ExtHiTVData[] = { + 0x00 +}; + +UCHAR SiS310_NTSCTiming[] = { + 0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c, + 0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a, + 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b, + 0x0c, 0x50, 0x00, 0x97, 0x00, 0xda, 0x4a, 0x17, + 0x7d, 0x05, 0x4b, 0x00, 0x00, 0xe2, 0x00, 0x02, + 0x03, 0x0a, 0x65, 0x9d, 0x08, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x50, + 0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00 +}; + +UCHAR SiS310_PALTiming[] = { + 0x19, 0x52, 0x35, 0x6e, 0x04, 0x38, 0x3d, 0x70, + 0x94, 0x49, 0x01, 0x12, 0x06, 0x3e, 0x35, 0x6d, + 0x06, 0x14, 0x3e, 0x35, 0x6d, 0x00, 0x45, 0x2b, + 0x70, 0x50, 0x00, 0x9b, 0x00, 0xd9, 0x5d, 0x17, + 0x7d, 0x05, 0x45, 0x00, 0x00, 0xe8, 0x00, 0x02, + 0x0d, 0x00, 0x68, 0xb0, 0x0b, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x63, + 0x00, 0x40, 0x3e, 0x00, 0xe1, 0x02, 0x28, 0x00 +}; + +UCHAR SiS310_HiTVExtTiming[] = { 0x00 }; + +UCHAR SiS310_HiTVSt1Timing[] = { 0x00 }; + +UCHAR SiS310_HiTVSt2Timing[] = { 0x00 }; + +UCHAR SiS310_HiTVTextTiming[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Data[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Simu[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Text[] = { 0x00 }; + +typedef struct _SiS310_PanelDelayTblStruct { + UCHAR timer[2]; +} SiS310_PanelDelayTblStruct; +SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[] = { {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} +}; + +typedef struct _SiS310_LVDSDataStruct { + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS310_LVDSDataStruct; +SiS310_LVDSDataStruct SiS310_LVDS800x600Data_1[] = { + {848, 433, 1060, 629}, + {848, 389, 1060, 629}, + {848, 433, 1060, 629}, + {848, 389, 1060, 629}, + {848, 518, 1060, 629}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {800, 449, 1000, 644}, + {800, 525, 1000, 635} +}; + +SiS310_LVDSDataStruct SiS310_LVDS800x600Data_2[] = { + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {800, 449, 1000, 644}, + {800, 525, 1000, 635} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1024x768Data_1[] = { + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 518, 1344, 806}, + {1050, 638, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1024x768Data_2[] = { + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1280x1024Data_1[] = { + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 518, 1344, 806}, + {1050, 638, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1280x1024Data_2[] = { + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS640x480Data_1[] = { + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 525, 800, 525}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628} +}; + +SiS310_LVDSDataStruct SiS310_CHTVUNTSCData[] = { + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {784, 600, 784, 600}, + {1064, 750, 1064, 750} +}; + +SiS310_LVDSDataStruct SiS310_CHTVONTSCData[] = { + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {784, 525, 784, 525}, + {1040, 700, 1040, 700} +}; + +SiS310_LVDSDataStruct SiS310_CHTVUPALData[] = { + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {840, 750, 840, 750}, + {936, 836, 936, 836} +}; + +SiS310_LVDSDataStruct SiS310_CHTVOPALData[] = { + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {840, 625, 840, 625}, + {960, 750, 960, 750} +}; + +typedef struct _SiS310_LVDSDesStruct { + USHORT LCDHDES; + USHORT LCDVDES; +} SiS310_LVDSDesStruct; +SiS310_LVDSDesStruct SiS310_PanelType00_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType01_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType02_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType03_1[] = { + {8, 436}, + {8, 440}, + {8, 436}, + {8, 440}, + {8, 512}, + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794} +}; + +SiS310_LVDSDesStruct SiS310_PanelType04_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType05_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType06_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType07_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType08_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType09_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0a_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0b_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0c_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0d_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0e_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0f_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType00_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType01_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType02_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType03_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {1152, 622}, + {1152, 597} +}; + +SiS310_LVDSDesStruct SiS310_PanelType04_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType05_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType06_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType07_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType08_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType09_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0a_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0b_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0c_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0d_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0e_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0f_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; +/*301b*/ +SiS310_LVDSDesStruct SiS310_PanelType1076_1[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1210_1[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1296_1[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1076_2[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1210_2[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1296_2[] = { + 0x00, 0x00 +}; +/*end 301b*/ + +SiS310_LVDSDesStruct SiS310_CHTVUNTSCDesData[] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVONTSCDesData[] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVUPALDesData[] = { + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVOPALDesData[] = { + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + {0, 0}, + {0, 0} +}; + +typedef struct _SiS310_LVDSCRT1DataStruct { + UCHAR CR[17]; +} SiS310_LVDSCRT1DataStruct; +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1[] = + { {0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}, +{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}, +{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}, +{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}, +{0x65, 0x4f, 0x89, 0x56, 0x83, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x05, + 0x00}, +{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1[] = + { {0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}, +{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}, +{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}, +{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}, +{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0xDf, 0x05, 0x00, 0x00, 0x05, + 0x00}, +{0x87, 0x63, 0x63, 0x8B, 0x69, 0x1A, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x57, 0x7D, 0x20, 0x00, 0x26, + 0x01}, +{0xA3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0xFf, 0x25, 0x10, 0x00, 0x02, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1[] = + { {0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}, +{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}, +{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}, +{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}, +{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x01, + 0x00}, +{0x7e, 0x63, 0x82, 0x68, 0x15, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x26, + 0x01}, +{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1_H[] = + { {0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}, +{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}, +{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}, +{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}, +{0x30, 0x27, 0x94, 0x2c, 0x92, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x04, + 0x00}, +{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1_H[] = + { {0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}, +{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}, +{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}, +{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}, +{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0xDf, 0x05, 0x00, 0x00, 0x44, + 0x00}, +{0x41, 0x31, 0x31, 0x85, 0x35, 0x1d, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x57, 0x7D, 0x20, 0x00, 0x55, + 0x01}, +{0x4f, 0x3F, 0x3F, 0x93, 0x45, 0x0D, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0xFf, 0x25, 0x10, 0x00, 0x01, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1_H[] = + { {0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}, +{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}, +{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}, +{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}, +{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x04, + 0x00}, +{0x3c, 0x31, 0x80, 0x35, 0x1c, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x55, + 0x01}, +{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2[] = + { {0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}, +{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}, +{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}, +{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}, +{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x00}, +{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2[] = + { {0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}, +{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2[] = + { {0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}, +{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2_H[] = + { {0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}, +{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}, +{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}, +{0x3d, 0x27, 0x81, 0x3a, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}, +{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x05, + 0x00}, +{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2_H[] = + { {0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x31, 0x93, 0x3e, 0x06, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}, +{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2_H[] = + { {0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x31, 0x93, 0x3e, 0x86, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}, +{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = + { {0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xe8, 0x84, 0x8f, 0x57, 0x20, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xd0, 0x82, 0x5d, 0x57, 0x00, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xe8, 0x84, 0x8f, 0x57, 0x20, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xd0, 0x82, 0x5d, 0x57, 0x00, 0x00, 0x01, + 0x00}, +{0x5d, 0x4f, 0x81, 0x53, 0x9c, 0x56, 0xba, + 0x18, 0x84, 0xdf, 0x57, 0x00, 0x00, 0x01, + 0x00}, +{0x80, 0x63, 0x84, 0x6c, 0x17, 0xec, 0xf0, + 0x90, 0x8c, 0x57, 0xed, 0x20, 0x00, 0x06, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = + { {0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xc0, 0x84, 0x8f, 0x0c, 0x20, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xb0, 0x8d, 0x5d, 0x0c, 0x00, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xc0, 0x84, 0x8f, 0x0c, 0x20, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xb0, 0x8d, 0x5d, 0x0c, 0x00, 0x00, 0x01, + 0x00}, +{0x5d, 0x4f, 0x81, 0x56, 0x9c, 0x0b, 0x3e, + 0xe8, 0x84, 0xdf, 0x0c, 0x00, 0x00, 0x01, + 0x00}, +{0x7d, 0x63, 0x81, 0x6a, 0x16, 0xba, 0xf0, + 0x7f, 0x86, 0x57, 0xbb, 0x00, 0x00, 0x06, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = + { {0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf8, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf8, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x64, 0x4f, 0x88, 0x55, 0x80, 0xec, 0xba, + 0x50, 0x84, 0xdf, 0xed, 0x00, 0x00, 0x05, + 0x00}, +{0x70, 0x63, 0x94, 0x68, 0x8d, 0x42, 0xf1, + 0xc8, 0x8c, 0x57, 0xe9, 0x20, 0x00, 0x05, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = + { {0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf0, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf0, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x64, 0x4f, 0x88, 0x55, 0x80, 0x6f, 0xba, + 0x20, 0x83, 0xdf, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x73, 0x63, 0x97, 0x69, 0x8e, 0xec, 0xf0, + 0x90, 0x8c, 0x57, 0xed, 0x20, 0x00, 0x05, + 0x01} +}; + +typedef struct _SiS310_CHTVRegDataStruct { + UCHAR Reg[5]; +} SiS310_CHTVRegDataStruct; +SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = { + 0x00 +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = { + 0x00 +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = { + 0x00 +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = { + 0x00 +}; + +UCHAR SiS310_CHTVVCLKUNTSC[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKONTSC[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKUPAL[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKOPAL[] = { 0x00 }; diff --git a/drivers/video/sis/Makefile b/drivers/video/sis/Makefile index a09f4af0ac64..dec70b81b78b 100644 --- a/drivers/video/sis/Makefile +++ b/drivers/video/sis/Makefile @@ -6,7 +6,7 @@ O_TARGET := sisfb.o export-objs := sis_main.o -obj-y := sis_main.o sis_300.o sis_301.o +obj-y := sis_main.o init.o init301.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c new file mode 100644 index 000000000000..1573adbb0989 --- /dev/null +++ b/drivers/video/sis/init.c @@ -0,0 +1,3784 @@ +/* Function: Support NT X.0 MM function */ +/* Version : V 0.80 [ynlai] 04/12/98 */ + +#include "init.h" +#ifdef CONFIG_FB_SIS_300 +#include "300vtbl.h" +#endif +#ifdef CONFIG_FB_SIS_315 +#include "310vtbl.h" +#endif + +BOOLEAN SiSInit (PSIS_HW_DEVICE_INFO HwDeviceExtension); +BOOLEAN SiSSetMode (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo); + +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(PAGE,SiSSetMode) +#pragma alloc_text(PAGE,SiSInit) +#endif + +void SiS_SetReg1 (USHORT, USHORT, USHORT); +void SiS_SetReg2 (USHORT, USHORT, USHORT); +void SiS_SetReg3 (USHORT, USHORT); +void SiS_SetReg4 (USHORT, ULONG); +UCHAR SiS_GetReg1 (USHORT, USHORT); +UCHAR SiS_GetReg2 (USHORT); +ULONG SiS_GetReg3 (USHORT); +void SiS_ClearDAC (ULONG); + +#ifdef CONFIG_FB_SIS_300 +void +InitTo300Pointer (void) +{ + SiS_SModeIDTable = (SiS_StStruct *) SiS300_SModeIDTable; + SiS_VBModeIDTable = (SiS_VBModeStruct *) SiS300_VBModeIDTable; /*add for 300 oem util */ + SiS_StandTable = (SiS_StandTableStruct *) SiS300_StandTable; + SiS_EModeIDTable = (SiS_ExtStruct *) SiS300_EModeIDTable; + SiS_RefIndex = (SiS_Ext2Struct *) SiS300_RefIndex; + SiS_CRT1Table = (SiS_CRT1TableStruct *) SiS300_CRT1Table; + SiS_MCLKData = (SiS_MCLKDataStruct *) SiS300_MCLKData; + SiS_ECLKData = (SiS_ECLKDataStruct *) SiS300_ECLKData; + SiS_VCLKData = (SiS_VCLKDataStruct *) SiS300_VCLKData; + SiS_VBVCLKData = (SiS_VBVCLKDataStruct *) SiS300_VCLKData; + SiS_ScreenOffset = SiS300_ScreenOffset; + SiS_StResInfo = (SiS_StResInfoStruct *) SiS300_StResInfo; + SiS_ModeResInfo = (SiS_ModeResInfoStruct *) SiS300_ModeResInfo; + + pSiS_OutputSelect = &SiS300_OutputSelect; + pSiS_SoftSetting = &SiS300_SoftSetting; + pSiS_SR07 = &SiS300_SR07; + SiS_SR15 = SiS300_SR15; + SiS_CR40 = SiS300_CR40; + SiS_CR49 = SiS300_CR49; + pSiS_SR1F = &SiS300_SR1F; + pSiS_SR21 = &SiS300_SR21; + pSiS_SR22 = &SiS300_SR22; + pSiS_SR23 = &SiS300_SR23; + pSiS_SR24 = &SiS300_SR24; + SiS_SR25 = SiS300_SR25; + pSiS_SR31 = &SiS300_SR31; + pSiS_SR32 = &SiS300_SR32; + pSiS_SR33 = &SiS300_SR33; + pSiS_CRT2Data_1_2 = &SiS300_CRT2Data_1_2; + pSiS_CRT2Data_4_D = &SiS300_CRT2Data_4_D; + pSiS_CRT2Data_4_E = &SiS300_CRT2Data_4_E; + pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10; + pSiS_RGBSenseData = &SiS300_RGBSenseData; + pSiS_VideoSenseData = &SiS300_VideoSenseData; + pSiS_YCSenseData = &SiS300_YCSenseData; + pSiS_RGBSenseData2 = &SiS300_RGBSenseData2; + pSiS_VideoSenseData2 = &SiS300_VideoSenseData2; + pSiS_YCSenseData2 = &SiS300_YCSenseData2; + + SiS_NTSCPhase = SiS300_NTSCPhase; + SiS_PALPhase = SiS300_PALPhase; + SiS_NTSCPhase2 = SiS300_NTSCPhase2; + SiS_PALPhase2 = SiS300_PALPhase2; + SiS_PALMPhase = SiS300_PALMPhase; /*add for PALMN */ + SiS_PALNPhase = SiS300_PALNPhase; + + SiS_StLCD1024x768Data = (SiS_LCDDataStruct *) SiS300_StLCD1024x768Data; + SiS_ExtLCD1024x768Data = + (SiS_LCDDataStruct *) SiS300_ExtLCD1024x768Data; + SiS_St2LCD1024x768Data = + (SiS_LCDDataStruct *) SiS300_St2LCD1024x768Data; + SiS_StLCD1280x1024Data = + (SiS_LCDDataStruct *) SiS300_StLCD1280x1024Data; + SiS_ExtLCD1280x1024Data = + (SiS_LCDDataStruct *) SiS300_ExtLCD1280x1024Data; + SiS_St2LCD1280x1024Data = + (SiS_LCDDataStruct *) SiS300_St2LCD1280x1024Data; + SiS_NoScaleData = (SiS_LCDDataStruct *) SiS300_NoScaleData; + SiS_LCD1280x960Data = (SiS_LCDDataStruct *) SiS300_LCD1280x960Data; + SiS_StPALData = (SiS_TVDataStruct *) SiS300_StPALData; + SiS_ExtPALData = (SiS_TVDataStruct *) SiS300_ExtPALData; + SiS_StNTSCData = (SiS_TVDataStruct *) SiS300_StNTSCData; + SiS_ExtNTSCData = (SiS_TVDataStruct *) SiS300_ExtNTSCData; + SiS_St1HiTVData = (SiS_TVDataStruct *) SiS300_St1HiTVData; + SiS_St2HiTVData = (SiS_TVDataStruct *) SiS300_St2HiTVData; + SiS_ExtHiTVData = (SiS_TVDataStruct *) SiS300_ExtHiTVData; + SiS_NTSCTiming = SiS300_NTSCTiming; + SiS_PALTiming = SiS300_PALTiming; + SiS_HiTVSt1Timing = SiS300_HiTVSt1Timing; + SiS_HiTVSt2Timing = SiS300_HiTVSt2Timing; + SiS_HiTVTextTiming = SiS300_HiTVTextTiming; + SiS_HiTVGroup3Data = SiS300_HiTVGroup3Data; + SiS_HiTVGroup3Simu = SiS300_HiTVGroup3Simu; + SiS_HiTVGroup3Text = SiS300_HiTVGroup3Text; + + SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *) SiS300_PanelDelayTbl; + SiS_LVDS800x600Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS800x600Data_1; + SiS_LVDS800x600Data_2 = (SiS_LVDSDataStruct *) SiS300_LVDS800x600Data_2; + SiS_LVDS1024x768Data_1 = + (SiS_LVDSDataStruct *) SiS300_LVDS1024x768Data_1; + SiS_LVDS1024x768Data_2 = + (SiS_LVDSDataStruct *) SiS300_LVDS1024x768Data_2; + SiS_LVDS1280x1024Data_1 = + (SiS_LVDSDataStruct *) SiS300_LVDS1280x1024Data_1; + SiS_LVDS1280x1024Data_2 = + (SiS_LVDSDataStruct *) SiS300_LVDS1280x1024Data_2; + SiS_LVDS640x480Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS640x480Data_1; + SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *) SiS300_CHTVUNTSCData; + SiS_CHTVONTSCData = (SiS_LVDSDataStruct *) SiS300_CHTVONTSCData; + SiS_CHTVUPALData = (SiS_LVDSDataStruct *) SiS300_CHTVUPALData; + SiS_CHTVOPALData = (SiS_LVDSDataStruct *) SiS300_CHTVOPALData; + SiS_PanelType00_1 = (SiS_LVDSDesStruct *) SiS300_PanelType00_1; + SiS_PanelType01_1 = (SiS_LVDSDesStruct *) SiS300_PanelType01_1; + SiS_PanelType02_1 = (SiS_LVDSDesStruct *) SiS300_PanelType02_1; + SiS_PanelType03_1 = (SiS_LVDSDesStruct *) SiS300_PanelType03_1; + SiS_PanelType04_1 = (SiS_LVDSDesStruct *) SiS300_PanelType04_1; + SiS_PanelType05_1 = (SiS_LVDSDesStruct *) SiS300_PanelType05_1; + SiS_PanelType06_1 = (SiS_LVDSDesStruct *) SiS300_PanelType06_1; + SiS_PanelType07_1 = (SiS_LVDSDesStruct *) SiS300_PanelType07_1; + SiS_PanelType08_1 = (SiS_LVDSDesStruct *) SiS300_PanelType08_1; + SiS_PanelType09_1 = (SiS_LVDSDesStruct *) SiS300_PanelType09_1; + SiS_PanelType0a_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0a_1; + SiS_PanelType0b_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0b_1; + SiS_PanelType0c_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0c_1; + SiS_PanelType0d_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0d_1; + SiS_PanelType0e_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0e_1; + SiS_PanelType0f_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0f_1; + SiS_PanelType00_2 = (SiS_LVDSDesStruct *) SiS300_PanelType00_2; + SiS_PanelType01_2 = (SiS_LVDSDesStruct *) SiS300_PanelType01_2; + SiS_PanelType02_2 = (SiS_LVDSDesStruct *) SiS300_PanelType02_2; + SiS_PanelType03_2 = (SiS_LVDSDesStruct *) SiS300_PanelType03_2; + SiS_PanelType04_2 = (SiS_LVDSDesStruct *) SiS300_PanelType04_2; + SiS_PanelType05_2 = (SiS_LVDSDesStruct *) SiS300_PanelType05_2; + SiS_PanelType06_2 = (SiS_LVDSDesStruct *) SiS300_PanelType06_2; + SiS_PanelType07_2 = (SiS_LVDSDesStruct *) SiS300_PanelType07_2; + SiS_PanelType08_2 = (SiS_LVDSDesStruct *) SiS300_PanelType08_2; + SiS_PanelType09_2 = (SiS_LVDSDesStruct *) SiS300_PanelType09_2; + SiS_PanelType0a_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0a_2; + SiS_PanelType0b_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0b_2; + SiS_PanelType0c_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0c_2; + SiS_PanelType0d_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0d_2; + SiS_PanelType0e_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0e_2; + SiS_PanelType0f_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0f_2; + SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *) SiS300_CHTVUNTSCDesData; + SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *) SiS300_CHTVONTSCDesData; + SiS_CHTVUPALDesData = (SiS_LVDSDesStruct *) SiS300_CHTVUPALDesData; + SiS_CHTVOPALDesData = (SiS_LVDSDesStruct *) SiS300_CHTVOPALDesData; + SiS_LVDSCRT1800x600_1 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_1; + SiS_LVDSCRT11024x768_1 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_1; + SiS_LVDSCRT11280x1024_1 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_1; + SiS_LVDSCRT1800x600_1_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_1_H; + SiS_LVDSCRT11024x768_1_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_1_H; + SiS_LVDSCRT11280x1024_1_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_1_H; + SiS_LVDSCRT1800x600_2 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_2; + SiS_LVDSCRT11024x768_2 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_2; + SiS_LVDSCRT11280x1024_2 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_2; + SiS_LVDSCRT1800x600_2_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_2_H; + SiS_LVDSCRT11024x768_2_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_2_H; + SiS_LVDSCRT11280x1024_2_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_2_H; + SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1UNTSC; + SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1ONTSC; + SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1UPAL; + SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1OPAL; + SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_UNTSC; + SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_ONTSC; + SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_UPAL; + SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_OPAL; + SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC; + SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC; + SiS_CHTVVCLKUPAL = SiS300_CHTVVCLKUPAL; + SiS_CHTVVCLKOPAL = SiS300_CHTVVCLKOPAL; + /* 300 customization related */ +} +#endif + +#ifdef CONFIG_FB_SIS_315 +void +InitTo310Pointer (void) +{ + SiS_SModeIDTable = (SiS_StStruct *) SiS310_SModeIDTable; + SiS_StandTable = (SiS_StandTableStruct *) SiS310_StandTable; + SiS_EModeIDTable = (SiS_ExtStruct *) SiS310_EModeIDTable; + SiS_RefIndex = (SiS_Ext2Struct *) SiS310_RefIndex; + SiS_CRT1Table = (SiS_CRT1TableStruct *) SiS310_CRT1Table; + SiS_MCLKData = (SiS_MCLKDataStruct *) SiS310_MCLKData; + SiS_ECLKData = (SiS_ECLKDataStruct *) SiS310_ECLKData; + SiS_VCLKData = (SiS_VCLKDataStruct *) SiS310_VCLKData; + SiS_VBVCLKData = (SiS_VBVCLKDataStruct *) SiS310_VBVCLKData; + SiS_ScreenOffset = SiS310_ScreenOffset; + SiS_StResInfo = (SiS_StResInfoStruct *) SiS310_StResInfo; + SiS_ModeResInfo = (SiS_ModeResInfoStruct *) SiS310_ModeResInfo; + + pSiS_OutputSelect = &SiS310_OutputSelect; + pSiS_SoftSetting = &SiS310_SoftSetting; + pSiS_SR07 = &SiS310_SR07; + SiS_SR15 = SiS310_SR15; + SiS_CR40 = SiS310_CR40; + SiS_CR49 = SiS310_CR49; + pSiS_SR1F = &SiS310_SR1F; + pSiS_SR21 = &SiS310_SR21; + pSiS_SR22 = &SiS310_SR22; + pSiS_SR23 = &SiS310_SR23; + pSiS_SR24 = &SiS310_SR24; + SiS_SR25 = SiS310_SR25; + pSiS_SR31 = &SiS310_SR31; + pSiS_SR32 = &SiS310_SR32; + pSiS_SR33 = &SiS310_SR33; + pSiS_CRT2Data_1_2 = &SiS310_CRT2Data_1_2; + pSiS_CRT2Data_4_D = &SiS310_CRT2Data_4_D; + pSiS_CRT2Data_4_E = &SiS310_CRT2Data_4_E; + pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10; + pSiS_RGBSenseData = &SiS310_RGBSenseData; + pSiS_VideoSenseData = &SiS310_VideoSenseData; + pSiS_YCSenseData = &SiS310_YCSenseData; + pSiS_RGBSenseData2 = &SiS310_RGBSenseData2; + pSiS_VideoSenseData2 = &SiS310_VideoSenseData2; + pSiS_YCSenseData2 = &SiS310_YCSenseData2; + SiS_NTSCPhase = SiS310_NTSCPhase; + SiS_PALPhase = SiS310_PALPhase; + SiS_NTSCPhase2 = SiS310_NTSCPhase2; + SiS_PALPhase2 = SiS310_PALPhase2; + SiS_PALMPhase = SiS310_PALMPhase; /*add for PALMN */ + SiS_PALNPhase = SiS310_PALNPhase; + + SiS_StLCD1024x768Data = (SiS_LCDDataStruct *) SiS310_StLCD1024x768Data; + SiS_ExtLCD1024x768Data = + (SiS_LCDDataStruct *) SiS310_ExtLCD1024x768Data; + SiS_St2LCD1024x768Data = + (SiS_LCDDataStruct *) SiS310_St2LCD1024x768Data; + SiS_StLCD1280x1024Data = + (SiS_LCDDataStruct *) SiS310_StLCD1280x1024Data; + SiS_ExtLCD1280x1024Data = + (SiS_LCDDataStruct *) SiS310_ExtLCD1280x1024Data; + SiS_St2LCD1280x1024Data = + (SiS_LCDDataStruct *) SiS310_St2LCD1280x1024Data; + SiS_NoScaleData = (SiS_LCDDataStruct *) SiS310_NoScaleData; + SiS_LCD1280x960Data = (SiS_LCDDataStruct *) SiS310_LCD1280x960Data; + SiS_StPALData = (SiS_TVDataStruct *) SiS310_StPALData; + SiS_ExtPALData = (SiS_TVDataStruct *) SiS310_ExtPALData; + SiS_StNTSCData = (SiS_TVDataStruct *) SiS310_StNTSCData; + SiS_ExtNTSCData = (SiS_TVDataStruct *) SiS310_ExtNTSCData; + SiS_St1HiTVData = (SiS_TVDataStruct *) SiS310_St1HiTVData; + SiS_St2HiTVData = (SiS_TVDataStruct *) SiS310_St2HiTVData; + SiS_ExtHiTVData = (SiS_TVDataStruct *) SiS310_ExtHiTVData; + SiS_NTSCTiming = SiS310_NTSCTiming; + SiS_PALTiming = SiS310_PALTiming; + SiS_HiTVSt1Timing = SiS310_HiTVSt1Timing; + SiS_HiTVSt2Timing = SiS310_HiTVSt2Timing; + SiS_HiTVTextTiming = SiS310_HiTVTextTiming; + SiS_HiTVGroup3Data = SiS310_HiTVGroup3Data; + SiS_HiTVGroup3Simu = SiS310_HiTVGroup3Simu; + SiS_HiTVGroup3Text = SiS310_HiTVGroup3Text; + + SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *) SiS310_PanelDelayTbl; + SiS_LVDS800x600Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS800x600Data_1; + SiS_LVDS800x600Data_2 = (SiS_LVDSDataStruct *) SiS310_LVDS800x600Data_2; + SiS_LVDS1024x768Data_1 = + (SiS_LVDSDataStruct *) SiS310_LVDS1024x768Data_1; + SiS_LVDS1024x768Data_2 = + (SiS_LVDSDataStruct *) SiS310_LVDS1024x768Data_2; + SiS_LVDS1280x1024Data_1 = + (SiS_LVDSDataStruct *) SiS310_LVDS1280x1024Data_1; + SiS_LVDS1280x1024Data_2 = + (SiS_LVDSDataStruct *) SiS310_LVDS1280x1024Data_2; + SiS_LVDS640x480Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS640x480Data_1; + SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *) SiS310_CHTVUNTSCData; + SiS_CHTVONTSCData = (SiS_LVDSDataStruct *) SiS310_CHTVONTSCData; + SiS_CHTVUPALData = (SiS_LVDSDataStruct *) SiS310_CHTVUPALData; + SiS_CHTVOPALData = (SiS_LVDSDataStruct *) SiS310_CHTVOPALData; + SiS_PanelType00_1 = (SiS_LVDSDesStruct *) SiS310_PanelType00_1; + SiS_PanelType01_1 = (SiS_LVDSDesStruct *) SiS310_PanelType01_1; + SiS_PanelType02_1 = (SiS_LVDSDesStruct *) SiS310_PanelType02_1; + SiS_PanelType03_1 = (SiS_LVDSDesStruct *) SiS310_PanelType03_1; + SiS_PanelType04_1 = (SiS_LVDSDesStruct *) SiS310_PanelType04_1; + SiS_PanelType05_1 = (SiS_LVDSDesStruct *) SiS310_PanelType05_1; + SiS_PanelType06_1 = (SiS_LVDSDesStruct *) SiS310_PanelType06_1; + SiS_PanelType07_1 = (SiS_LVDSDesStruct *) SiS310_PanelType07_1; + SiS_PanelType08_1 = (SiS_LVDSDesStruct *) SiS310_PanelType08_1; + SiS_PanelType09_1 = (SiS_LVDSDesStruct *) SiS310_PanelType09_1; + SiS_PanelType0a_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0a_1; + SiS_PanelType0b_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0b_1; + SiS_PanelType0c_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0c_1; + SiS_PanelType0d_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0d_1; + SiS_PanelType0e_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0e_1; + SiS_PanelType0f_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0f_1; + SiS_PanelType00_2 = (SiS_LVDSDesStruct *) SiS310_PanelType00_2; + SiS_PanelType01_2 = (SiS_LVDSDesStruct *) SiS310_PanelType01_2; + SiS_PanelType02_2 = (SiS_LVDSDesStruct *) SiS310_PanelType02_2; + SiS_PanelType03_2 = (SiS_LVDSDesStruct *) SiS310_PanelType03_2; + SiS_PanelType04_2 = (SiS_LVDSDesStruct *) SiS310_PanelType04_2; + SiS_PanelType05_2 = (SiS_LVDSDesStruct *) SiS310_PanelType05_2; + SiS_PanelType06_2 = (SiS_LVDSDesStruct *) SiS310_PanelType06_2; + SiS_PanelType07_2 = (SiS_LVDSDesStruct *) SiS310_PanelType07_2; + SiS_PanelType08_2 = (SiS_LVDSDesStruct *) SiS310_PanelType08_2; + SiS_PanelType09_2 = (SiS_LVDSDesStruct *) SiS310_PanelType09_2; + SiS_PanelType0a_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0a_2; + SiS_PanelType0b_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0b_2; + SiS_PanelType0c_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0c_2; + SiS_PanelType0d_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0d_2; + SiS_PanelType0e_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0e_2; + SiS_PanelType0f_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0f_2; + /*301b */ + LVDS1024x768Des_1 = (SiS_LVDSDesStruct *) SiS310_PanelType1076_1; + LVDS1280x1024Des_1 = (SiS_LVDSDesStruct *) SiS310_PanelType1210_1; + LVDS1280x960Des_1 = (SiS_LVDSDesStruct *) SiS310_PanelType1296_1; + LVDS1024x768Des_2 = (SiS_LVDSDesStruct *) SiS310_PanelType1076_2; + LVDS1280x1024Des_2 = (SiS_LVDSDesStruct *) SiS310_PanelType1210_2; + LVDS1280x960Des_2 = (SiS_LVDSDesStruct *) SiS310_PanelType1296_2; + /*end 301b */ + + SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *) SiS310_CHTVUNTSCDesData; + SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *) SiS310_CHTVONTSCDesData; + SiS_CHTVUPALDesData = (SiS_LVDSDesStruct *) SiS310_CHTVUPALDesData; + SiS_CHTVOPALDesData = (SiS_LVDSDesStruct *) SiS310_CHTVOPALDesData; + SiS_LVDSCRT1800x600_1 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_1; + SiS_LVDSCRT11024x768_1 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_1; + SiS_LVDSCRT11280x1024_1 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_1; + SiS_LVDSCRT1800x600_1_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_1_H; + SiS_LVDSCRT11024x768_1_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_1_H; + SiS_LVDSCRT11280x1024_1_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_1_H; + SiS_LVDSCRT1800x600_2 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_2; + SiS_LVDSCRT11024x768_2 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_2; + SiS_LVDSCRT11280x1024_2 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_2; + SiS_LVDSCRT1800x600_2_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_2_H; + SiS_LVDSCRT11024x768_2_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_2_H; + SiS_LVDSCRT11280x1024_2_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_2_H; + SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1UNTSC; + SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1ONTSC; + SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1UPAL; + SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1OPAL; + SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_UNTSC; + SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_ONTSC; + SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_UPAL; + SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_OPAL; + /*add for LCDA */ + SiS_LCDACRT1800x600_1 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_1; + SiS_LCDACRT11024x768_1 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_1; + SiS_LCDACRT11280x1024_1 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_1; + SiS_LCDACRT1800x600_1_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_1_H; + SiS_LCDACRT11024x768_1_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_1_H; + SiS_LCDACRT11280x1024_1_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_1_H; + SiS_LCDACRT1800x600_2 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_2; + SiS_LCDACRT11024x768_2 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_2; + SiS_LCDACRT11280x1024_2 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_2; + SiS_LCDACRT1800x600_2_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_2_H; + SiS_LCDACRT11024x768_2_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_2_H; + SiS_LCDACRT11280x1024_2_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_2_H; + /*end for 301b */ + + SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC; + SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC; + SiS_CHTVVCLKUPAL = SiS310_CHTVVCLKUPAL; + SiS_CHTVVCLKOPAL = SiS310_CHTVVCLKOPAL; + /* 310 customization related */ + +} +#endif + +BOOLEAN +SiSInit (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + ULONG ROMAddr = (ULONG) HwDeviceExtension->pjVirtualRomBase; + ULONG FBAddr = (ULONG) HwDeviceExtension->pjVideoMemoryAddress; + USHORT BaseAddr = (USHORT) HwDeviceExtension->ulIOAddress; + UCHAR i, temp = 0; + UCHAR SR11, temp1; + ULONG base; + UCHAR SR12 = 0, SR13 = 0, SR14 = 0, SR16 = 0, SR17 = 0, SR18 = 0, SR19 = + 0, SR1A = 0; +#ifdef CONFIG_FB_SIS_315 + /* ULONG j, k; */ + UCHAR CR39 = 0, CR3A = 0, CR3B = 0, CR3C = 0, CR3D = 0, CR3E = 0, CR3F = + 0; + UCHAR CR79 = 0, CR7A = 0, CR7B = 0, CR7C = 0; + PSIS_DSReg pSR; + ULONG Temp; +#endif + UCHAR VBIOSVersion[5]; + +/* if(ROMAddr==0) return (FALSE);*/ + if (FBAddr == 0) + return (FALSE); + if (BaseAddr == 0) + return (FALSE); + + SiS_SetReg3 ((USHORT) (BaseAddr + 0x12), 0x67); /* 3c2 <- 67 ,ynlai */ +#ifdef CONFIG_FB_SIS_315 + /*if(HwDeviceExtension->jChipType > SIS_315H) */ + if (HwDeviceExtension->jChipType > SIS_315PRO) { + if (!HwDeviceExtension->bIntegratedMMEnabled) + return (FALSE); /* alan */ + } +#endif + + SiS_MemoryCopy (VBIOSVersion, HwDeviceExtension->szVBIOSVer, 4); + + VBIOSVersion[4] = 0x0; + /* 09/07/99 modify by domao */ + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO) || + (HwDeviceExtension->jChipType == SIS_550) || /* 05/02/01 ynlai for 550 */ + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) /* 09/03/01 chiawen for 650 */ + InitTo310Pointer (); +#endif + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730) || + (HwDeviceExtension->jChipType == SIS_300)) + InitTo300Pointer (); +#endif + + SiS_P3c4 = BaseAddr + 0x14; + SiS_P3d4 = BaseAddr + 0x24; + SiS_P3c0 = BaseAddr + 0x10; + SiS_P3ce = BaseAddr + 0x1e; + SiS_P3c2 = BaseAddr + 0x12; + SiS_P3ca = BaseAddr + 0x1a; + SiS_P3c6 = BaseAddr + 0x16; + SiS_P3c7 = BaseAddr + 0x17; + SiS_P3c8 = BaseAddr + 0x18; + SiS_P3c9 = BaseAddr + 0x19; + SiS_P3da = BaseAddr + 0x2A; + SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; + SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10; + SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12; + SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14; + SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; + SiS_Set_LVDS_TRUMPION (HwDeviceExtension); /*2/29/00 by Mars Wen for LVDS and Trumpion */ + + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); /* 1.Openkey */ + +#ifdef LINUX_KERNEL +#ifdef CONFIG_FB_SIS_300 /* add to set SR14 */ + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + base = 0x80000060; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 >> (16 + 8 + 4); + temp1 = temp1 & (0x07); + temp1 = temp1 + 1; + temp1 = 1 << temp1; + SR14 = temp1 - 1; + base = 0x80000064; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 & (0x00000020); + if (temp1) + SR14 = (0x10000000) | SR14; + else + SR14 = (0x01000000) | SR14; + } +#endif + +#ifdef CONFIG_FB_SIS_315 /* add to set SR14 */ + if ((HwDeviceExtension->jChipType == SIS_550)) { + base = 0x80000060; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 >> (16 + 8 + 4); + temp1 = temp1 & (0x07); + temp1 = temp1 + 1; + temp1 = 1 << temp1; + SR14 = temp1 - 1; + base = 0x80000064; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 & (0x00000020); + if (temp1) + SR14 = (0x10000000) | SR14; + else + SR14 = (0x01000000) | SR14; + } + + if ((HwDeviceExtension->jChipType == SIS_640) + || (HwDeviceExtension->jChipType == SIS_740)) { + base = 0x80000064; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp >> 4; + temp1 = temp1 & (0x07); + if (temp1 > 2) { + temp = temp1; + switch (temp) { + case 3: + temp1 = 0x07; + break; + case 4: + temp1 = 0x0F; + break; + case 5: + temp1 = 0x1F; + break; + case 6: + temp1 = 0x05; + break; + case 7: + temp1 = 0x17; + break; + case 8: + break; + case 9: + break; + } + } + SR14 = temp1; + base = 0x8000007C; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 & (0x00000020); + if (temp1) + SR14 = (0x10000000) | SR14; + } +#endif + +#endif + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + SR12 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x12); + SR13 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x13); + SR14 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x14); + SR16 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x16); + SR17 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x17); + SR18 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x18); + SR19 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x19); + SR1A = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x1A); + } else { + SR13 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x13); + SR14 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x14); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_550)) { + CR39 = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x39); + CR3A = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3A); + CR3B = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3B); + CR3C = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3C); + CR3D = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3D); + CR3E = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3E); + CR3F = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3F); + CR79 = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x79); + CR7A = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x7A); + CR7B = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x7B); + CR7C = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x7C); + } else if ((HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { + SR12 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x12); + SR13 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x13); + SR14 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x14); + SR16 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x16); + SR17 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x17); + SR18 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x18); + SR19 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x19); + SR1A = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x1A); + } +#endif +/* ResetExtReg begin */ + for (i = 0x06; i < 0x20; i++) + SiS_SetReg1 (SiS_P3c4, i, 0); /* 2.Reset Extended register */ + for (i = 0x21; i <= 0x27; i++) + SiS_SetReg1 (SiS_P3c4, i, 0); /* Reset Extended register */ + for (i = 0x31; i <= 0x3D; i++) + SiS_SetReg1 (SiS_P3c4, i, 0); + +#ifdef CONFIG_FB_SIS_300H + for (i = 0x38; i <= 0x3F; i++) + SiS_SetReg1 (SiS_P3d4, i, 0); +#endif + +#ifdef CONFIG_FB_SIS_315 + for (i = 0x37; i <= 0x3F; i++) + SiS_SetReg1 (SiS_P3d4, i, 0); + for (i = 0x79; i <= 0x7C; i++) + SiS_SetReg1 (SiS_P3d4, i, 0); +#endif +/* ResetExtReg end */ +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + SiS_SetReg1 (SiS_P3c4, 0x12, SR12); + SiS_SetReg1 (SiS_P3c4, 0x13, SR13); + SiS_SetReg1 (SiS_P3c4, 0x14, SR14); + SiS_SetReg1 (SiS_P3c4, 0x16, SR16); + SiS_SetReg1 (SiS_P3c4, 0x17, SR17); + SiS_SetReg1 (SiS_P3c4, 0x18, SR18); + SiS_SetReg1 (SiS_P3c4, 0x19, SR19); + SiS_SetReg1 (SiS_P3c4, 0x1A, SR1A); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_550)) { + SiS_SetReg1 (SiS_P3d4, 0x39, CR39); + SiS_SetReg1 (SiS_P3d4, 0x3A, CR3A); + SiS_SetReg1 (SiS_P3d4, 0x3B, CR3B); + SiS_SetReg1 (SiS_P3d4, 0x3C, CR3C); + SiS_SetReg1 (SiS_P3d4, 0x3D, CR3D); + SiS_SetReg1 (SiS_P3d4, 0x3E, CR3E); + SiS_SetReg1 (SiS_P3d4, 0x3F, CR3F); + SiS_SetReg1 (SiS_P3d4, 0x79, CR79); + SiS_SetReg1 (SiS_P3d4, 0x7A, CR7A); + SiS_SetReg1 (SiS_P3d4, 0x7B, CR7B); + SiS_SetReg1 (SiS_P3d4, 0x7C, CR7C); + } else if ((HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { + SiS_SetReg1 (SiS_P3c4, 0x12, SR12); + SiS_SetReg1 (SiS_P3c4, 0x13, SR13); + SiS_SetReg1 (SiS_P3c4, 0x14, SR14); + SiS_SetReg1 (SiS_P3c4, 0x16, SR16); + SiS_SetReg1 (SiS_P3c4, 0x17, SR17); + SiS_SetReg1 (SiS_P3c4, 0x18, SR18); + SiS_SetReg1 (SiS_P3c4, 0x19, SR19); + SiS_SetReg1 (SiS_P3c4, 0x1A, SR1A); + } +#endif + +/* detect ExtChip Type */ + SiS_Set_LVDS_TRUMPION (HwDeviceExtension); /*2/29/00 by Mars Wen for LVDS and Trumpion */ + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + temp = (UCHAR) SR1A; + } else +#endif + { + if ((*pSiS_SoftSetting & SoftDRAMType) == 0) { + temp = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x3A); + } + } + + SiS_RAMType = temp & 0x03; + SiS_SetMemoryClock (ROMAddr); + +/* SetDefExt1Regs begin */ + SiS_SetReg1 (SiS_P3c4, 0x07, *pSiS_SR07); + if ((HwDeviceExtension->jChipType != SIS_540) && + (HwDeviceExtension->jChipType != SIS_630) && + (HwDeviceExtension->jChipType != SIS_730)) { + for (i = 0x15; i < 0x1C; i++) { + SiS_SetReg1 (SiS_P3c4, i, + SiS_SR15[i - 0x15][SiS_RAMType]); + } + } +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO)) { + for (i = 0x40; i <= 0x44; i++) { + SiS_SetReg1 (SiS_P3d4, i, + SiS_CR40[i - 0x40][SiS_RAMType]); + } + SiS_SetReg1 (SiS_P3d4, 0x48, 0x23); + SiS_SetReg1 (SiS_P3d4, 0x49, SiS_CR49[0]); + /* /SiS_SetReg1(SiS_P3c4,0x25,SiS_SR25[0]); */ + } +#endif + + SiS_SetReg1 (SiS_P3c4, 0x1F, *pSiS_SR1F); + /*SiS_SetReg1(SiS_P3c4,0x20,0x20); */ + SiS_SetReg1 (SiS_P3c4, 0x20, 0xA0); /* alan, 2001/6/26 Frame buffer can read/write */ + SiS_SetReg1 (SiS_P3c4, 0x23, *pSiS_SR23); + SiS_SetReg1 (SiS_P3c4, 0x24, *pSiS_SR24); + SiS_SetReg1 (SiS_P3c4, 0x25, SiS_SR25[0]); +#ifdef CONFIG_FB_SIS_300 + if (HwDeviceExtension->jChipType == SIS_300) { + SiS_SetReg1 (SiS_P3c4, 0x21, 0x84); + SiS_SetReg1 (SiS_P3c4, 0x22, 0x00); + } +#endif + SR11 = 0x0F; + SiS_SetReg1 (SiS_P3c4, 0x11, SR11); + + SiS_UnLockCRT2 (HwDeviceExtension, BaseAddr); + SiS_SetReg1 (SiS_Part1Port, 0x00, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x02, *pSiS_CRT2Data_1_2); +#ifdef CONFIG_FB_SIS_315 /* 05/02/01 ynlai for sis550 */ + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO) || + (HwDeviceExtension->jChipType == SIS_550) || + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) + /* 09/03/01 chiawen for 650 */ + SiS_SetReg1 (SiS_Part1Port, 0x2E, 0x08); /* use VB */ +#endif + + temp = *pSiS_SR32; + if (SiS_BridgeIsOn (BaseAddr)) { + temp = temp & 0xEF; + } + SiS_SetReg1 (SiS_P3c4, 0x32, temp); + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO)) { + HwDeviceExtension->pQueryVGAConfigSpace (HwDeviceExtension, + 0x50, 0, &Temp); /* Get */ + + Temp >>= 20; + Temp &= 0xF; + if (Temp != 1) { + SiS_SetReg1 (SiS_P3c4, 0x25, SiS_SR25[1]); + SiS_SetReg1 (SiS_P3d4, 0x49, SiS_CR49[1]); + } + + SiS_SetReg1 (SiS_P3c4, 0x27, 0x1F); + + SiS_SetReg1 (SiS_P3c4, 0x31, *pSiS_SR31); + SiS_SetReg1 (SiS_P3c4, 0x32, *pSiS_SR32); + SiS_SetReg1 (SiS_P3c4, 0x33, *pSiS_SR33); + } +#endif + + if (SiS_BridgeIsOn (BaseAddr) == 1) { + if (SiS_IF_DEF_LVDS == 0) { + SiS_SetReg1 (SiS_Part2Port, 0x00, 0x1C); + SiS_SetReg1 (SiS_Part4Port, 0x0D, *pSiS_CRT2Data_4_D); + SiS_SetReg1 (SiS_Part4Port, 0x0E, *pSiS_CRT2Data_4_E); + SiS_SetReg1 (SiS_Part4Port, 0x10, *pSiS_CRT2Data_4_10); + SiS_SetReg1 (SiS_Part4Port, 0x0F, 0x3F); + } + SiS_LockCRT2 (HwDeviceExtension, BaseAddr); + } + SiS_SetReg1 (SiS_P3d4, 0x83, 0x00); +/* SetDefExt1Regs end */ + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO) + ) { /* 05/02/01 ynlai */ + /* For SiS 300,310 Chip */ + if (HwDeviceExtension->bSkipDramSizing == TRUE) { + SiS_SetDRAMModeRegister (ROMAddr); + pSR = HwDeviceExtension->pSR; + if (pSR != NULL) { + while (pSR->jIdx != 0xFF) { + SiS_SetReg1 (SiS_P3c4, pSR->jIdx, + pSR->jVal); + pSR++; + } + } + } else + SiS_SetDRAMSize_310 (HwDeviceExtension); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_550)) { /* 05/02/01 ynlai For SiS 550 */ + /* SetDRAMConfig begin */ +/* SiS_SetReg1(SiS_P3c4,0x12,SR12); + SiS_SetReg1(SiS_P3c4,0x13,SR13); + SiS_SetReg1(SiS_P3c4,0x14,SR14); + SiS_SetReg1(SiS_P3c4,0x16,SR16); + SiS_SetReg1(SiS_P3c4,0x17,SR17); + SiS_SetReg1(SiS_P3c4,0x18,SR18); + SiS_SetReg1(SiS_P3c4,0x19,SR19); + SiS_SetReg1(SiS_P3c4,0x1A,SR1A); */ + /* SetDRAMConfig end */ + } +#endif +#ifdef CONFIG_FB_SIS_300 + if (HwDeviceExtension->jChipType == SIS_300) { /* For SiS 300 Chip */ + if (HwDeviceExtension->bSkipDramSizing == TRUE) { +/* SiS_SetDRAMModeRegister(ROMAddr); + temp = (HwDeviceExtension->pSR)->jVal; + SiS_SetReg1(SiS_P3c4,0x13,temp); + temp = (HwDeviceExtension->pSR)->jVal; + SiS_SetReg1(SiS_P3c4,0x14,temp); */ + } else { +#ifdef TC + SiS_SetReg1 (SiS_P3c4, 0x13, SR13); + SiS_SetReg1 (SiS_P3c4, 0x14, SR14); + SiS_SetRegANDOR (SiS_P3c4, 0x15, 0xFF, 0x04); +#else + SiS_SetDRAMSize_300 (HwDeviceExtension); + SiS_SetDRAMSize_300 (HwDeviceExtension); +#endif + } + } + if ((HwDeviceExtension->jChipType == SIS_540) || /* For SiS 630/540/730 Chip */ + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + /* SetDRAMConfig begin */ +/* SiS_SetReg1(SiS_P3c4,0x12,SR12); + SiS_SetReg1(SiS_P3c4,0x13,SR13); + SiS_SetReg1(SiS_P3c4,0x14,SR14); + SiS_SetReg1(SiS_P3c4,0x16,SR16); + SiS_SetReg1(SiS_P3c4,0x17,SR17); + SiS_SetReg1(SiS_P3c4,0x18,SR18); + SiS_SetReg1(SiS_P3c4,0x19,SR19); + SiS_SetReg1(SiS_P3c4,0x1A,SR1A); */ + /* SetDRAMConfig end */ + } +/* SetDRAMSize end */ +#endif + +/* SetDefExt2Regs begin */ +/* AGP=1; + temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x3A); + temp=temp&0x30; + if(temp==0x30) AGP=0; + if(AGP==0) *pSiS_SR21=*pSiS_SR21&0xEF; + SiS_SetReg1(SiS_P3c4,0x21,*pSiS_SR21); + if(AGP==1) *pSiS_SR22=*pSiS_SR22&0x20; + SiS_SetReg1(SiS_P3c4,0x22,*pSiS_SR22); */ + + SiS_SetReg1 (SiS_P3c4, 0x21, *pSiS_SR21); + SiS_SetReg1 (SiS_P3c4, 0x22, *pSiS_SR22); +/* SetDefExt2Regs end */ + +/* SiS_SetReg3(SiS_P3c6,0xff); + SiS_ClearDAC(SiS_P3c8); [ynlai] 05/22/01 */ + + SiS_DetectMonitor (HwDeviceExtension, BaseAddr); + SiS_GetSenseStatus (HwDeviceExtension, ROMAddr); /* sense CRT2 */ + + return (TRUE); +} + +void +SiS_Set_LVDS_TRUMPION (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp; + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + temp = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x1A); + temp = (temp & 0xE0) >> 4; + SiS_SetRegANDOR (SiS_P3d4, 0x37, 0xF1, temp); + temp = temp >> 1; + if ((temp == 0) || (temp == 1)) { /* for 301 */ + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_CH7005 = 0; + SiS_IF_DEF_TRUMPION = 0; + } + if ((temp >= 2) && (temp <= 5)) { + SiS_IF_DEF_LVDS = 1; + } + if (temp == 3) + SiS_IF_DEF_TRUMPION = 1; + if ((temp == 4) || (temp == 5)) + SiS_IF_DEF_CH7005 = 1; + } else { + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_TRUMPION = 0; + SiS_IF_DEF_CH7005 = 0; + } +#else + if ((HwDeviceExtension->jChipType == SIS_550) || + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) + { /* 09/03/01 chiawen for 650 */ + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_TRUMPION = 0; + SiS_IF_DEF_CH7005 = 0; + } +#endif +} + +/* =============== for 300 dram sizing begin =============== */ +#ifdef CONFIG_FB_SIS_300 +void +SiS_SetDRAMSize_300 (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + /*ULONG ROMAddr = (ULONG)HwDeviceExtension->pjVirtualRomBase; */ + ULONG FBAddr = (ULONG) HwDeviceExtension->pjVideoMemoryAddress; + /*USHORT BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress; */ + USHORT SR13, SR14 = 0, buswidth, Done; + SHORT i, j, k; + USHORT data, TotalCapacity, PhysicalAdrOtherPage = 0; + ULONG Addr; + UCHAR temp; + + int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount; + int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank; + /*int PageCapacity,PhysicalAdrHigh,PhysicalAdrHalfPage,PhysicalAdrAnotherPage; */ + int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage; + + SiSSetMode (HwDeviceExtension, 0x2e); + data = SiS_GetReg1 (SiS_P3c4, 0x1); + data = data | 0x20; + SiS_SetReg1 (SiS_P3c4, 0x01, data); /* Turn OFF Display */ + + SiS_SetReg1 (SiS_P3c4, 0x13, 0x00); + SiS_SetReg1 (SiS_P3c4, 0x14, 0xBF); + buswidth = SiS_ChkBUSWidth_300 (FBAddr); + + MB2Bank = 16; + Done = 0; + for (i = 6; i >= 0; i--) { + if (Done == 1) + break; + PseudoRankCapacity = 1 << i; + for (j = 4; j >= 1; j--) { + if (Done == 1) + break; + PseudoTotalCapacity = PseudoRankCapacity * j; + PseudoAdrPinCount = 15 - j; + if (PseudoTotalCapacity <= 64) { + for (k = 0; k <= 16; k++) { + if (Done == 1) + break; + RankCapacity = + buswidth * SiS_DRAMType[k][3]; + AdrPinCount = + SiS_DRAMType[k][2] + + SiS_DRAMType[k][0]; + if (RankCapacity == PseudoRankCapacity) + if (AdrPinCount <= + PseudoAdrPinCount) { + if (j == 3) { /* Rank No */ + BankNumHigh = + RankCapacity + * MB2Bank * + 3 - 1; + BankNumMid = + RankCapacity + * MB2Bank * + 1 - 1; + } else { + BankNumHigh = + RankCapacity + * MB2Bank * + j - 1; + BankNumMid = + RankCapacity + * MB2Bank * + j / 2 - 1; + } + PageCapacity = + (1 << + SiS_DRAMType[k][1]) + * buswidth * 4; + PhysicalAdrHigh = + BankNumHigh; + PhysicalAdrHalfPage = + (PageCapacity / 2 + + PhysicalAdrHigh) % + PageCapacity; + PhysicalAdrOtherPage = + PageCapacity * + SiS_DRAMType[k][2] + + PhysicalAdrHigh; + /* Write data */ + /*Test */ + temp = + (UCHAR) + SiS_GetReg1 + (SiS_P3c4, 0x15); + SiS_SetReg1 (SiS_P3c4, + 0x15, + (USHORT) + (temp & + 0xFB)); + + temp = + (UCHAR) + SiS_GetReg1 + (SiS_P3c4, 0x15); + SiS_SetReg1 (SiS_P3c4, + 0x15, + (USHORT) + (temp | + 0x04)); + /*Test */ + TotalCapacity = + SiS_DRAMType[k][3] * + buswidth; + SR13 = + SiS_DRAMType[k][4]; + if (buswidth == 4) + SR14 = + (TotalCapacity + - + 1) | 0x80; + if (buswidth == 2) + SR14 = + (TotalCapacity + - + 1) | 0x40; + if (buswidth == 1) + SR14 = + (TotalCapacity + - + 1) | 0x00; + SiS_SetReg1 (SiS_P3c4, + 0x13, + SR13); + SiS_SetReg1 (SiS_P3c4, + 0x14, + SR14); + + Addr = + FBAddr + + (BankNumHigh) * 64 * + 1024 + + PhysicalAdrHigh; + *((USHORT *) (Addr)) = + (USHORT) + PhysicalAdrHigh; + Addr = + FBAddr + + (BankNumMid) * 64 * + 1024 + + PhysicalAdrHigh; + *((USHORT *) (Addr)) = + (USHORT) BankNumMid; + Addr = + FBAddr + + (BankNumHigh) * 64 * + 1024 + + PhysicalAdrHalfPage; + *((USHORT *) (Addr)) = + (USHORT) + PhysicalAdrHalfPage; + Addr = + FBAddr + + (BankNumHigh) * 64 * + 1024 + + PhysicalAdrOtherPage; + *((USHORT *) (Addr)) = + PhysicalAdrOtherPage; + + /* Read data */ + Addr = + FBAddr + + (BankNumHigh) * 64 * + 1024 + + PhysicalAdrHigh; + data = + *((USHORT *) + (Addr)); + if (data == + PhysicalAdrHigh) + Done = 1; + } /* if struct */ + } /* for loop (k) */ + } /* if struct */ + } /* for loop (j) */ + } /* for loop (i) */ +} + +USHORT +SiS_ChkBUSWidth_300 (ULONG FBAddress) +{ + /*USHORT data; */ + PULONG pVideoMemory; + + pVideoMemory = (PULONG) FBAddress; + + pVideoMemory[0] = 0x01234567L; + pVideoMemory[1] = 0x456789ABL; + pVideoMemory[2] = 0x89ABCDEFL; + pVideoMemory[3] = 0xCDEF0123L; + if (pVideoMemory[3] == 0xCDEF0123L) { /*ChannelA128Bit */ + return (4); + } + if (pVideoMemory[1] == 0x456789ABL) { /*ChannelB64Bit */ + return (2); + } + return (1); +} +#endif + +/* =============== for 300 dram sizing end =============== */ + +/* ============== alan ====================== */ +#ifdef CONFIG_FB_SIS_315 +UCHAR +SiS_Get310DRAMType (ULONG ROMAddr) +{ + UCHAR data; + + /* + index=SiS_GetReg1(SiS_P3c4,0x1A); + index=index&07; + */ + if (*pSiS_SoftSetting & SoftDRAMType) + data = *pSiS_SoftSetting & 0x03; + else + data = SiS_GetReg1 (SiS_P3c4, 0x3a) & 0x03; + + return data; +} + +void +SiS_Delay15us (ULONG ulMicrsoSec) +{ +} + +void +SiS_SDR_MRS (void) +{ + USHORT data; + + data = SiS_GetReg1 (SiS_P3c4, 0x16); + data = data & 0x3F; /*/ SR16 D7=0,D6=0 */ + SiS_SetReg1 (SiS_P3c4, 0x16, data); /*/ enable mode register set(MRS) low */ + SiS_Delay15us (0x100); + data = data | 0x80; /*/ SR16 D7=1,D6=0 */ + SiS_SetReg1 (SiS_P3c4, 0x16, data); /*/ enable mode register set(MRS) high */ + SiS_Delay15us (0x100); +} + +void +SiS_DDR_MRS (void) +{ + USHORT data; + + /* SR16 <- 1F,DF,2F,AF */ + + /* enable DLL of DDR SD/SGRAM , SR16 D4=1 */ + data = SiS_GetReg1 (SiS_P3c4, 0x16); + data &= 0x0F; + data |= 0x10; + SiS_SetReg1 (SiS_P3c4, 0x16, data); + + if (!(SiS_SR15[1][SiS_RAMType] & 0x10)) { + data &= 0x0F; + } + /* SR16 D7=1,D6=1 */ + data |= 0xC0; + SiS_SetReg1 (SiS_P3c4, 0x16, data); + + /* SR16 D7=1,D6=0,D5=1,D4=0 */ + data &= 0x0F; + data |= 0x20; + SiS_SetReg1 (SiS_P3c4, 0x16, data); + if (!(SiS_SR15[1][SiS_RAMType] & 0x10)) { + data &= 0x0F; + } + /* SR16 D7=1 */ + data |= 0x80; + SiS_SetReg1 (SiS_P3c4, 0x16, data); +} + +void +SiS_SetDRAMModeRegister (ULONG ROMAddr) +{ + + if (SiS_Get310DRAMType (ROMAddr) < 2) { + SiS_SDR_MRS (); + } else { + /* SR16 <- 0F,CF,0F,8F */ + SiS_DDR_MRS (); + } +} + +void +SiS_DisableRefresh (void) +{ + USHORT data; + + data = SiS_GetReg1 (SiS_P3c4, 0x17); + data &= 0xF8; + SiS_SetReg1 (SiS_P3c4, 0x17, data); + + data = SiS_GetReg1 (SiS_P3c4, 0x19); + data |= 0x03; + SiS_SetReg1 (SiS_P3c4, 0x19, data); + +} + +void +SiS_EnableRefresh (ULONG ROMAddr) +{ + + SiS_SetReg1 (SiS_P3c4, 0x17, SiS_SR15[2][SiS_RAMType]); /* SR17 */ + + SiS_SetReg1 (SiS_P3c4, 0x19, SiS_SR15[4][SiS_RAMType]); /* SR19 */ + +} + +void +SiS_DisableChannelInterleaving (int index, USHORT SiS_DDRDRAM_TYPE[][5]) +{ + USHORT data; + + data = SiS_GetReg1 (SiS_P3c4, 0x15); + data &= 0x1F; + switch (SiS_DDRDRAM_TYPE[index][3]) { + case 64: + data |= 0; + break; + case 32: + data |= 0x20; + break; + case 16: + data |= 0x40; + break; + case 4: + data |= 0x60; + break; + } + SiS_SetReg1 (SiS_P3c4, 0x15, data); + +} + +void +SiS_SetDRAMSizingType (int index, USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + + data = DRAMTYPE_TABLE[index][4]; + SiS_SetReg1 (SiS_P3c4, 0x13, data); + + /* should delay 50 ns */ + +} + +void +SiS_CheckBusWidth_310 (ULONG ROMAddress, ULONG FBAddress) +{ + USHORT data; + PULONG volatile pVideoMemory; + + pVideoMemory = (PULONG) FBAddress; + if (SiS_Get310DRAMType (ROMAddress) < 2) { + + SiS_SetReg1 (SiS_P3c4, 0x13, 0x00); + SiS_SetReg1 (SiS_P3c4, 0x14, 0x12); + /* should delay */ + SiS_SDR_MRS (); + + SiS_ChannelAB = 0; + SiS_DataBusWidth = 128; + pVideoMemory[0] = 0x01234567L; + pVideoMemory[1] = 0x456789ABL; + pVideoMemory[2] = 0x89ABCDEFL; + pVideoMemory[3] = 0xCDEF0123L; + pVideoMemory[4] = 0x55555555L; + pVideoMemory[5] = 0x55555555L; + pVideoMemory[6] = 0xFFFFFFFFL; + pVideoMemory[7] = 0xFFFFFFFFL; + if ((pVideoMemory[3] != 0xCDEF0123L) + || (pVideoMemory[2] != 0x89ABCDEFL)) { + /*ChannelA64Bit */ + SiS_DataBusWidth = 64; + SiS_ChannelAB = 0; + data = SiS_GetReg1 (SiS_P3c4, 0x14); + SiS_SetReg1 (SiS_P3c4, 0x14, (USHORT) (data & 0xFD)); + } + + if ((pVideoMemory[1] != 0x456789ABL) + || (pVideoMemory[0] != 0x01234567L)) { + /*ChannelB64Bit */ + SiS_DataBusWidth = 64; + SiS_ChannelAB = 1; + data = SiS_GetReg1 (SiS_P3c4, 0x14); + SiS_SetReg1 (SiS_P3c4, 0x14, + (USHORT) ((data & 0xFD) | 0x01)); + } + return; + + } else { + /* DDR Dual channel */ + SiS_SetReg1 (SiS_P3c4, 0x13, 0x00); + SiS_SetReg1 (SiS_P3c4, 0x14, 0x02); /* Channel A, 64bit */ + /* should delay */ + SiS_DDR_MRS (); + + SiS_ChannelAB = 0; + SiS_DataBusWidth = 64; + pVideoMemory[0] = 0x01234567L; + pVideoMemory[1] = 0x456789ABL; + pVideoMemory[2] = 0x89ABCDEFL; + pVideoMemory[3] = 0xCDEF0123L; + pVideoMemory[4] = 0x55555555L; + pVideoMemory[5] = 0x55555555L; + pVideoMemory[6] = 0xAAAAAAAAL; + pVideoMemory[7] = 0xAAAAAAAAL; + + if (pVideoMemory[1] == 0x456789ABL) { + if (pVideoMemory[0] == 0x01234567L) { + /* Channel A 64bit */ + return; + } + } else { + if (pVideoMemory[0] == 0x01234567L) { + /* Channel A 32bit */ + SiS_DataBusWidth = 32; + SiS_SetReg1 (SiS_P3c4, 0x14, 0x00); + return; + } + + } + + SiS_SetReg1 (SiS_P3c4, 0x14, 0x03); /* Channel B, 64bit */ + SiS_DDR_MRS (); + + SiS_ChannelAB = 1; + SiS_DataBusWidth = 64; + pVideoMemory[0] = 0x01234567L; + pVideoMemory[1] = 0x456789ABL; + pVideoMemory[2] = 0x89ABCDEFL; + pVideoMemory[3] = 0xCDEF0123L; + pVideoMemory[4] = 0x55555555L; + pVideoMemory[5] = 0x55555555L; + pVideoMemory[6] = 0xAAAAAAAAL; + pVideoMemory[7] = 0xAAAAAAAAL; + if (pVideoMemory[1] == 0x456789ABL) { + /* Channel B 64 */ + if (pVideoMemory[0] == 0x01234567L) { + /* Channel B 64bit */ + return; + } else { + /* error */ + } + } else { + if (pVideoMemory[0] == 0x01234567L) { + /* Channel B 32 */ + SiS_DataBusWidth = 32; + SiS_SetReg1 (SiS_P3c4, 0x14, 0x01); + } else { + /* error */ + } + } + } +} + +int +SiS_SetRank (int index, UCHAR RankNo, UCHAR SiS_ChannelAB, + USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + int RankSize; + + if ((RankNo == 2) && (DRAMTYPE_TABLE[index][0] == 2)) + return 0; + + RankSize = DRAMTYPE_TABLE[index][3] / 2 * SiS_DataBusWidth / 32; + + if (RankNo * RankSize <= 128) { + data = 0; + while ((RankSize >>= 1) > 0) { + data += 0x10; + } + data |= (RankNo - 1) << 2; + data |= (SiS_DataBusWidth / 64) & 2; + data |= SiS_ChannelAB; + SiS_SetReg1 (SiS_P3c4, 0x14, data); + /* should delay */ + SiS_SDR_MRS (); + return 1; + } else + return 0; + +} + +int +SiS_SetDDRChannel (int index, UCHAR ChannelNo, UCHAR SiS_ChannelAB, + USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + int RankSize; + + RankSize = DRAMTYPE_TABLE[index][3] / 2 * SiS_DataBusWidth / 32; + /* RankSize = DRAMTYPE_TABLE[index][3]; */ + if (ChannelNo * RankSize <= 128) { + data = 0; + while ((RankSize >>= 1) > 0) { + data += 0x10; + } + if (ChannelNo == 2) + data |= 0x0C; + + data |= (SiS_DataBusWidth / 32) & 2; + data |= SiS_ChannelAB; + SiS_SetReg1 (SiS_P3c4, 0x14, data); + /* should delay */ + SiS_DDR_MRS (); + return 1; + } else + return 0; + +} + +int +SiS_CheckColumn (int index, USHORT DRAMTYPE_TABLE[][5], ULONG FBAddress) +{ + int i; + ULONG Increment, Position; + + /*Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_DataBusWidth / 64 + 1); */ + Increment = 1 << (10 + SiS_DataBusWidth / 64); + + for (i = 0, Position = 0; i < 2; i++) { + *((PULONG) (FBAddress + Position)) = Position; + Position += Increment; + } + + for (i = 0, Position = 0; i < 2; i++) { +/* if (FBAddress[Position]!=Position) */ + if ((*(PULONG) (FBAddress + Position)) != Position) + return 0; + Position += Increment; + } + return 1; +} + +int +SiS_CheckBanks (int index, USHORT DRAMTYPE_TABLE[][5], ULONG FBAddress) +{ + int i; + ULONG Increment, Position; + Increment = 1 << (DRAMTYPE_TABLE[index][2] + SiS_DataBusWidth / 64 + 2); + + for (i = 0, Position = 0; i < 4; i++) { +/* FBAddress[Position]=Position; */ + *((PULONG) (FBAddress + Position)) = Position; + Position += Increment; + } + + for (i = 0, Position = 0; i < 4; i++) { +/* if (FBAddress[Position]!=Position) */ + if ((*(PULONG) (FBAddress + Position)) != Position) + return 0; + Position += Increment; + } + return 1; +} + +int +SiS_CheckRank (int RankNo, int index, USHORT DRAMTYPE_TABLE[][5], + ULONG FBAddress) +{ + int i; + ULONG Increment, Position; + Increment = 1 << (DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] + + DRAMTYPE_TABLE[index][0] + SiS_DataBusWidth / 64 + + RankNo); + + for (i = 0, Position = 0; i < 2; i++) { +/* FBAddress[Position]=Position; */ + *((PULONG) (FBAddress + Position)) = Position; + /* *((PULONG)(FBAddress))=Position; */ + Position += Increment; + } + + for (i = 0, Position = 0; i < 2; i++) { +/* if (FBAddress[Position]!=Position) */ + if ((*(PULONG) (FBAddress + Position)) != Position) + /*if ( (*(PULONG) (FBAddress )) !=Position) */ + return 0; + Position += Increment; + } + return 1; + +} + +int +SiS_CheckDDRRank (int RankNo, int index, USHORT DRAMTYPE_TABLE[][5], + ULONG FBAddress) +{ + ULONG Increment, Position; + USHORT data; + + Increment = 1 << (DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] + + DRAMTYPE_TABLE[index][0] + SiS_DataBusWidth / 64 + + RankNo); + + Increment += Increment / 2; + + Position = 0; + *((PULONG) (FBAddress + Position + 0)) = 0x01234567; + *((PULONG) (FBAddress + Position + 1)) = 0x456789AB; + *((PULONG) (FBAddress + Position + 2)) = 0x55555555; + *((PULONG) (FBAddress + Position + 3)) = 0x55555555; + *((PULONG) (FBAddress + Position + 4)) = 0xAAAAAAAA; + *((PULONG) (FBAddress + Position + 5)) = 0xAAAAAAAA; + + if ((*(PULONG) (FBAddress + 1)) == 0x456789AB) + return 1; + + if ((*(PULONG) (FBAddress + 0)) == 0x01234567) + return 0; + + data = SiS_GetReg1 (SiS_P3c4, 0x14); + data &= 0xF3; + data |= 0x08; + SiS_SetReg1 (SiS_P3c4, 0x14, data); + data = SiS_GetReg1 (SiS_P3c4, 0x15); + data += 0x20; + SiS_SetReg1 (SiS_P3c4, 0x15, data); + + return 1; + +} + +int +SiS_CheckRanks (int RankNo, int index, USHORT DRAMTYPE_TABLE[][5], + ULONG FBAddress) +{ + int r; + + for (r = RankNo; r >= 1; r--) { + if (!SiS_CheckRank (r, index, DRAMTYPE_TABLE, FBAddress)) + return 0; + } + if (!SiS_CheckBanks (index, DRAMTYPE_TABLE, FBAddress)) + return 0; + + if (!SiS_CheckColumn (index, DRAMTYPE_TABLE, FBAddress)) + return 0; + return 1; + +} + +int +SiS_CheckDDRRanks (int RankNo, int index, USHORT DRAMTYPE_TABLE[][5], + ULONG FBAddress) +{ + int r; + + for (r = RankNo; r >= 1; r--) { + if (!SiS_CheckDDRRank (r, index, DRAMTYPE_TABLE, FBAddress)) + return 0; + } + if (!SiS_CheckBanks (index, DRAMTYPE_TABLE, FBAddress)) + return 0; + + if (!SiS_CheckColumn (index, DRAMTYPE_TABLE, FBAddress)) + return 0; + return 1; + +} + +int +SiS_SDRSizing (ULONG FBAddress) +{ + int i; + UCHAR j; + + for (i = 0; i < 13; i++) { + SiS_SetDRAMSizingType (i, SiS_SDRDRAM_TYPE); + for (j = 2; j > 0; j--) { + + if (!SiS_SetRank + (i, (UCHAR) j, SiS_ChannelAB, + SiS_SDRDRAM_TYPE)) continue; + else { + if (SiS_CheckRanks + (j, i, SiS_SDRDRAM_TYPE, + FBAddress)) return 1; + } + } + } + return 0; +} + +int +SiS_DDRSizing (ULONG FBAddress) +{ + + int i; + UCHAR j; + + for (i = 0; i < 4; i++) { + SiS_SetDRAMSizingType (i, SiS_DDRDRAM_TYPE); + SiS_DisableChannelInterleaving (i, SiS_DDRDRAM_TYPE); + for (j = 2; j > 0; j--) { + SiS_SetDDRChannel (i, j, SiS_ChannelAB, + SiS_DDRDRAM_TYPE); + if (!SiS_SetRank + (i, (UCHAR) j, SiS_ChannelAB, + SiS_DDRDRAM_TYPE)) continue; + else { + if (SiS_CheckDDRRanks + (j, i, SiS_DDRDRAM_TYPE, + FBAddress)) return 1; + } + } + } + return 0; +} + +/* + + check if read cache pointer is correct + +*/ +void +SiS_VerifyMclk (ULONG FBAddr) +{ + PUCHAR pVideoMemory = (PUCHAR) FBAddr; + UCHAR i, j; + USHORT Temp, SR21; + + pVideoMemory[0] = 0xaa; /* alan */ + pVideoMemory[16] = 0x55; /* note: PCI read cache is off */ + + if ((pVideoMemory[0] != 0xaa) || (pVideoMemory[16] != 0x55)) { + for (i = 0, j = 16; i < 2; i++, j += 16) { + SR21 = SiS_GetReg1 (SiS_P3c4, 0x21); + Temp = SR21 & 0xFB; /* disable PCI post write buffer empty gating */ + SiS_SetReg1 (SiS_P3c4, 0x21, Temp); + + Temp = SiS_GetReg1 (SiS_P3c4, 0x3C); + Temp = Temp | 0x01; /*MCLK reset */ + SiS_SetReg1 (SiS_P3c4, 0x3C, Temp); + Temp = SiS_GetReg1 (SiS_P3c4, 0x3C); + Temp = Temp & 0xFE; /* MCLK normal operation */ + SiS_SetReg1 (SiS_P3c4, 0x3C, Temp); + SiS_SetReg1 (SiS_P3c4, 0x21, SR21); + + pVideoMemory[16 + j] = j; + if (pVideoMemory[16 + j] == j) { + pVideoMemory[j] = j; + break; + } + } + } + +} + +int +Is315E (void) +{ + USHORT data; + + data = SiS_GetReg1 (SiS_P3d4, 0x5F); + if (data & 0x10) + return 1; + else + return 0; +} + +void +SiS_SetDRAMSize_310 (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + ULONG ROMAddr = (ULONG) HwDeviceExtension->pjVirtualRomBase; + ULONG FBAddr = (ULONG) HwDeviceExtension->pjVideoMemoryAddress; + /*USHORT BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress; */ + USHORT data; + +#ifdef SIS301 + /*SiS_SetReg1(SiS_P3d4,0x30,0x40); */ +#endif +#ifdef SIS302 + SiS_SetReg1 (SiS_P3d4, 0x30, 0x4D); /* alan,should change value */ + SiS_SetReg1 (SiS_P3d4, 0x31, 0xc0); /* alan,should change value */ + SiS_SetReg1 (SiS_P3d4, 0x34, 0x3F); /* alan,should change value */ +#endif + + SiSSetMode (HwDeviceExtension, 0x2e); + + data = SiS_GetReg1 (SiS_P3c4, 0x21); + SiS_SetReg1 (SiS_P3c4, 0x21, (USHORT) (data & 0xDF)); /* disable read cache */ + + data = SiS_GetReg1 (SiS_P3c4, 0x1); + data = data | 0x20; + SiS_SetReg1 (SiS_P3c4, 0x01, data); /* Turn OFF Display */ + + data = SiS_GetReg1 (SiS_P3c4, 0x16); + SiS_SetReg1 (SiS_P3c4, 0x16, (USHORT) (data | 0x0F)); /* assume lowest speed DRAM */ + + SiS_SetDRAMModeRegister (ROMAddr); + SiS_DisableRefresh (); + SiS_CheckBusWidth_310 (ROMAddr, FBAddr); + + SiS_VerifyMclk (FBAddr); /* alan 2000/7/3 */ + + if (SiS_Get310DRAMType (ROMAddr) < 2) { + SiS_SDRSizing (FBAddr); + } else { + SiS_DDRSizing (FBAddr); + } + + if (Is315E ()) { + data = SiS_GetReg1 (SiS_P3c4, 0x14); + if ((data & 0x0C) == 0x0C) { /* dual channel */ + if ((data & 0xF0) > 0x40) + data = (data & 0x0F) | 0x40; + } else { /* single channel */ + + if ((data & 0xF0) > 0x50) + data = (data & 0x0F) | 0x50; + } + + } + + SiS_SetReg1 (SiS_P3c4, 0x16, SiS_SR15[1][SiS_RAMType]); /* restore SR16 */ + + SiS_EnableRefresh (ROMAddr); + data = SiS_GetReg1 (SiS_P3c4, 0x21); + SiS_SetReg1 (SiS_P3c4, 0x21, (USHORT) (data | 0x20)); /* enable read cache */ + +} +#endif + +void +SiS_SetMemoryClock (ULONG ROMAddr) +{ + SiS_SetReg1 (SiS_P3c4, 0x28, SiS_MCLKData[SiS_RAMType].SR28); + SiS_SetReg1 (SiS_P3c4, 0x29, SiS_MCLKData[SiS_RAMType].SR29); + SiS_SetReg1 (SiS_P3c4, 0x2A, SiS_MCLKData[SiS_RAMType].SR2A); + SiS_SetReg1 (SiS_P3c4, 0x2E, SiS_ECLKData[SiS_RAMType].SR2E); + SiS_SetReg1 (SiS_P3c4, 0x2F, SiS_ECLKData[SiS_RAMType].SR2F); + SiS_SetReg1 (SiS_P3c4, 0x30, SiS_ECLKData[SiS_RAMType].SR30); + +#ifdef CONFIG_FB_SIS_315 + if (Is315E ()) { + SiS_SetReg1 (SiS_P3c4, 0x28, 0x3B); /* 143 */ + SiS_SetReg1 (SiS_P3c4, 0x29, 0x22); + SiS_SetReg1 (SiS_P3c4, 0x2E, 0x3B); /* 143 */ + SiS_SetReg1 (SiS_P3c4, 0x2F, 0x22); + } +#endif + +} + +/* +========================================= + ======== SiS SetMode Function ========== +========================================= +*/ +BOOLEAN +SiSSetMode (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo) +{ + ULONG temp; + USHORT ModeIdIndex, KeepLockReg; + ULONG ROMAddr = (ULONG) HwDeviceExtension->pjVirtualRomBase; + /*ULONG FBAddr = (ULONG)HwDeviceExtension->pjVideoMemoryAddress; */ + USHORT BaseAddr = (USHORT) HwDeviceExtension->ulIOAddress; + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || /* 05/02/01 ynlai for sis550 */ + (HwDeviceExtension->jChipType == SIS_315PRO) || + (HwDeviceExtension->jChipType == SIS_550) || + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) /* 09/03/01 chiawen for 650 */ + InitTo310Pointer (); +#endif + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730) || + (HwDeviceExtension->jChipType == SIS_300)) + InitTo300Pointer (); +#endif + + SiS_P3c4 = BaseAddr + 0x14; + SiS_P3d4 = BaseAddr + 0x24; + SiS_P3c0 = BaseAddr + 0x10; + SiS_P3ce = BaseAddr + 0x1e; + SiS_P3c2 = BaseAddr + 0x12; + SiS_P3ca = BaseAddr + 0x1a; + SiS_P3c6 = BaseAddr + 0x16; + SiS_P3c7 = BaseAddr + 0x17; + SiS_P3c8 = BaseAddr + 0x18; + SiS_P3c9 = BaseAddr + 0x19; + SiS_P3da = BaseAddr + 0x2A; + SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; + SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10; + SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12; + SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14; + SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; + + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_CH7005 = 0; + SiS_IF_DEF_HiVision = 0; + SiS_IF_DEF_DSTN = 0; /*for 550 dstn */ + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730) || + (HwDeviceExtension->jChipType == SIS_550) || + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { /* 09/03/01 chiawen for 650 */ + temp = SiS_GetReg1 (SiS_P3d4, 0x37); + temp = (temp & 0x0E) >> 1; + if ((temp == 0) || (temp == 1)) { /* for 301 */ + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_CH7005 = 0; + SiS_IF_DEF_TRUMPION = 0; + } + if ((temp >= 2) && (temp <= 5)) { + SiS_IF_DEF_LVDS = 1; + } + if (temp == 3) + SiS_IF_DEF_TRUMPION = 1; + if ((temp == 4) || (temp == 5)) + SiS_IF_DEF_CH7005 = 1; + } else { + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_TRUMPION = 0; + SiS_IF_DEF_CH7005 = 0; + } + + if (ModeNo & 0x80) { + ModeNo = ModeNo & 0x7F; + flag_clearbuffer = 0; + } else { + flag_clearbuffer = 1; + } + + SiS_PresetScratchregister (SiS_P3d4, HwDeviceExtension); /*add for CRT2 */ + KeepLockReg = SiS_GetReg1 (SiS_P3c4, 0x05); + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); /* 1.Openkey */ + temp = SiS_SearchModeID (ROMAddr, ModeNo, &ModeIdIndex); /* 2.Get ModeID Table */ + if (temp == 0) + return (0); + /*301b */ + SiS_GetVBType (BaseAddr); + /*end 301b */ + SiS_GetVBInfo301 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, HwDeviceExtension); /*add for CRT2 */ + SiS_GetLCDResInfo301 (ROMAddr, SiS_P3d4, ModeNo, ModeIdIndex); /*add for CRT2 */ + + temp = SiS_CheckMemorySize (ROMAddr, HwDeviceExtension, ModeNo, ModeIdIndex); /*3.Check memory size */ + if (temp == 0) + return (0); + if (SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) { /*301b */ + SiS_SetCRT1Group (ROMAddr, HwDeviceExtension, ModeNo, + ModeIdIndex); + } else { + if (!(SiS_VBInfo & SwitchToCRT2)) { + SiS_SetCRT1Group (ROMAddr, HwDeviceExtension, ModeNo, + ModeIdIndex); + } + } + + if (SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA)) { /*301b */ + switch (HwDeviceExtension->ujVBChipID) { +/*karl*/ + case VB_CHIP_301: + case VB_CHIP_301B: + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, ModeNo, HwDeviceExtension); /*add for CRT2 */ + break; + case VB_CHIP_302: + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, ModeNo, + HwDeviceExtension); + break; + case VB_CHIP_303: +/* SetCRT2Group302(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); add for CRT2 */ + break; + case VB_CHIP_UNKNOWN: /*add for lvds ch7005 */ + temp = SiS_GetReg1 (SiS_P3d4, 0x37); + if (temp & + (ExtChipLVDS | ExtChipTrumpion | ExtChipCH7005)) { + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, ModeNo, + HwDeviceExtension); + } + break; + } + } + if (KeepLockReg == 0xA1) + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); /* 05/02/01 ynlai */ + else + SiS_SetReg1 (SiS_P3c4, 0x05, 0x00); + return TRUE; +} + +void +SiS_SetCRT1Group (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT StandTableIndex, RefreshRateTableIndex; + USHORT temp; + + /*SiS_SetReg1(SiS_P3d4,0x34,ModeNo); */ + SiS_CRT1Mode = ModeNo; + /* set CR34->CRT1 ModeNofor CRT2 FIFO */ + StandTableIndex = SiS_GetModePtr (ROMAddr, ModeNo, ModeIdIndex); /* 4.GetModePtr */ + SiS_SetSeqRegs (ROMAddr, StandTableIndex); /* 5.SetSeqRegs */ + SiS_SetMiscRegs (ROMAddr, StandTableIndex); /* 6.SetMiscRegs */ + SiS_SetCRTCRegs (ROMAddr, HwDeviceExtension, StandTableIndex); /* 7.SetCRTCRegs */ + SiS_SetATTRegs (ROMAddr, StandTableIndex); /* 8.SetATTRegs */ + SiS_SetGRCRegs (ROMAddr, StandTableIndex); /* 9.SetGRCRegs */ + SiS_ClearExt1Regs (); /* 10.Clear Ext1Regs */ + temp = ~ProgrammingCRT2; /* 11.GetRatePtr */ + SiS_SetFlag = SiS_SetFlag & temp; + SiS_SelectCRT2Rate = 0; + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + /* SiS_SelectCRT2Rate=4; */ + } + } + /*end 301b */ + + RefreshRateTableIndex = SiS_GetRatePtrCRT2 (ROMAddr, ModeNo, ModeIdIndex); /* 11.GetRatePtr */ + + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (!(SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_SetFlag = SiS_SetFlag & (~ProgrammingCRT2); + } + } + /*end 301b */ + + if (RefreshRateTableIndex != 0xFFFF) { + SiS_SetSync (ROMAddr, RefreshRateTableIndex); /* 12.SetSync */ + SiS_SetCRT1CRTC (ROMAddr, ModeNo, ModeIdIndex, RefreshRateTableIndex); /* 13.SetCRT1CRTC */ + SiS_SetCRT1Offset (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); /* 14.SetCRT1Offset */ + SiS_SetCRT1VCLK (ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); /* 15.SetCRT1VCLK */ + } +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_540)) { + SiS_SetCRT1FIFO2 (ROMAddr, ModeNo, HwDeviceExtension, + RefreshRateTableIndex); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if (HwDeviceExtension->jChipType >= SIS_315H) { + SiS_SetCRT1FIFO (ROMAddr, ModeNo, HwDeviceExtension); + } +#endif + SiS_SetCRT1ModeRegs (ROMAddr, HwDeviceExtension, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + SiS_SetVCLKState (ROMAddr, HwDeviceExtension, ModeNo, + RefreshRateTableIndex); +#ifdef CONFIG_FB_SIS_315 + if (HwDeviceExtension->jChipType > SIS_315H) + SiS_SetInterlace (ROMAddr, ModeNo, RefreshRateTableIndex); +#endif + SiS_LoadDAC (ROMAddr, ModeNo, ModeIdIndex); + if (flag_clearbuffer) + SiS_ClearBuffer (HwDeviceExtension, ModeNo); + + if (!(SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA))) { /*301b */ + SiS_LongWait (); + SiS_DisplayOn (); + } +} + +void +SiS_GetVBType (USHORT BaseAddr) +{ + USHORT flag; + + flag = SiS_GetReg1 (SiS_Part4Port, 0x00); + if (flag >= 2) + SiS_VBType = VB_SIS302B; + else { + flag = SiS_GetReg1 (SiS_Part4Port, 0x01); + if (flag >= 0xB0) + SiS_VBType = VB_SIS301B; + else + SiS_VBType = VB_SIS301; + + flag = SiS_GetReg1 (SiS_Part4Port, 0x23); /*301dlvds */ + if (!(flag & 0x02)) + SiS_VBType = SiS_VBType | VB_NoLCD; + } + +} + +/* win2000 MM adapter not support standard mode */ +BOOLEAN +SiS_SearchModeID (ULONG ROMAddr, USHORT ModeNo, USHORT * ModeIdIndex) +{ + PUCHAR VGA_INFO = "\0x11"; + + if (ModeNo <= 5) + ModeNo |= 1; + if (ModeNo <= 0x13) { + /* for (*ModeIdIndex=0;*ModeIdIndex MemorySizeShift; + memorysize++; /* Get memory size */ + + temp = SiS_GetReg1 (SiS_P3c4, 0x14); /* Get DRAM Size */ + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO)) { + temp = 1 << ((temp & 0x0F0) >> 4); + if ((temp & 0x0c) == 0x08) { /* DDR asymetric */ + temp += temp / 2; + } else { + if ((temp & 0x0c) != 0) { + temp <<= 1; + } + } + } else { /* 300, 540 , 630 */ + + temp = temp & 0x3F; + temp++; + /* temp=1 << ((temp&0x0F0)>>4); */ + } + + if ((HwDeviceExtension->jChipType == SIS_550) || /* 05/02/01 ynlai for sis550 */ + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { /* 09/03/01 chiawen for 650 */ + return (TRUE); + } + + if (temp < memorysize) + return (FALSE); + else + return (TRUE); +} + +UCHAR +SiS_GetModePtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + UCHAR index; + + if (ModeNo <= 0x13) { + index = SiS_SModeIDTable[ModeIdIndex].St_StTableIndex; + } else { + if (SiS_ModeType <= 0x02) + index = 0x1B; /* 02 -> ModeEGA */ + else + index = 0x0F; + } + + return index; /* Get SiS_StandTable index */ +} + +void +SiS_SetSeqRegs (ULONG ROMAddr, USHORT StandTableIndex) +{ + UCHAR SRdata; + USHORT i; + + SiS_SetReg1 (SiS_P3c4, 0x00, 0x03); /* Set SR0 */ + SRdata = SiS_StandTable[StandTableIndex].SR[0]; + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) { + SRdata = SRdata | 0x01; + } + } + + /*end 301b */ + + if (SiS_IF_DEF_LVDS == 1) { + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_VBInfo & SetInSlaveMode) { + SRdata = SRdata | 0x01; /* 8 dot clock */ + } + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + if (SiS_VBInfo & SetInSlaveMode) { + SRdata = SRdata | 0x01; /* 8 dot clock */ + } + } + } + + SRdata = SRdata | 0x20; /* screen off */ + SiS_SetReg1 (SiS_P3c4, 0x01, SRdata); /* Set SR1 */ + for (i = 02; i <= 04; i++) { + SRdata = SiS_StandTable[StandTableIndex].SR[i - 1]; /* Get SR2,3,4 from file */ + SiS_SetReg1 (SiS_P3c4, i, SRdata); /* Set SR2 3 4 */ + } +} + +void +SiS_SetMiscRegs (ULONG ROMAddr, USHORT StandTableIndex) +{ + UCHAR Miscdata; + + Miscdata = SiS_StandTable[StandTableIndex].MISC; /* Get Misc from file */ + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) { + Miscdata = Miscdata | 0x0C; + } + } + /*end 301b */ + SiS_SetReg3 (SiS_P3c2, Miscdata); /* Set Misc(3c2) */ +} + +void +SiS_SetCRTCRegs (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT StandTableIndex) +{ + UCHAR CRTCdata; + USHORT i; + + CRTCdata = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); + CRTCdata = CRTCdata & 0x7f; + SiS_SetReg1 (SiS_P3d4, 0x11, CRTCdata); /* Unlock CRTC */ + + for (i = 0; i <= 0x18; i++) { + CRTCdata = SiS_StandTable[StandTableIndex].CRTC[i]; /* Get CRTC from file */ + SiS_SetReg1 (SiS_P3d4, i, CRTCdata); /* Set CRTC(3d4) */ + } + if ((HwDeviceExtension->jChipType == SIS_630) && + (HwDeviceExtension->jChipRevision == 0x30)) { /* for 630S0 */ + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { + SiS_SetReg1 (SiS_P3d4, 0x18, 0xFE); + } + } + } +} + +void +SiS_SetATTRegs (ULONG ROMAddr, USHORT StandTableIndex) +{ + UCHAR ARdata; + USHORT i; + + for (i = 0; i <= 0x13; i++) { + ARdata = SiS_StandTable[StandTableIndex].ATTR[i]; /* Get AR for file */ + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) { + if (i == 0x13) { + ARdata = 0; + } + } + } + /*end 301b */ + if (SiS_IF_DEF_LVDS == 1) { /*for LVDS */ + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if (i == 0x13) { + ARdata = 0; + } + } + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_LCDInfo & LCDNonExpanding) { + if (i == 0x13) { + ARdata = 0; + } + } + } + } + } + SiS_GetReg2 (SiS_P3da); /* reset 3da */ + SiS_SetReg3 (SiS_P3c0, i); /* set index */ + SiS_SetReg3 (SiS_P3c0, ARdata); /* set data */ + } + SiS_GetReg2 (SiS_P3da); /* reset 3da */ + SiS_SetReg3 (SiS_P3c0, 0x14); /* set index */ + SiS_SetReg3 (SiS_P3c0, 0x00); /* set data */ + + SiS_GetReg2 (SiS_P3da); /* Enable Attribute */ + SiS_SetReg3 (SiS_P3c0, 0x20); +} + +void +SiS_SetGRCRegs (ULONG ROMAddr, USHORT StandTableIndex) +{ + UCHAR GRdata; + USHORT i; + + for (i = 0; i <= 0x08; i++) { + GRdata = SiS_StandTable[StandTableIndex].GRC[i]; /* Get GR from file */ + SiS_SetReg1 (SiS_P3ce, i, GRdata); /* Set GR(3ce) */ + } + + if (SiS_ModeType > ModeVGA) { + GRdata = (UCHAR) SiS_GetReg1 (SiS_P3ce, 0x05); + GRdata = GRdata & 0xBF; /* 256 color disable */ + SiS_SetReg1 (SiS_P3ce, 0x05, GRdata); + } +} + +void +SiS_ClearExt1Regs () +{ + USHORT i; + + for (i = 0x0A; i <= 0x0E; i++) + SiS_SetReg1 (SiS_P3c4, i, 0x00); /* Clear SR0A-SR0E */ +} + +void +SiS_SetSync (ULONG ROMAddr, USHORT RefreshRateTableIndex) +{ + USHORT sync; + USHORT temp; + + sync = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8; /* di+0x00 */ + + sync = sync & 0xC0; + temp = 0x2F; + temp = temp | sync; + SiS_SetReg3 (SiS_P3c2, temp); /* Set Misc(3c2) */ +} + +void +SiS_SetCRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + UCHAR index; + UCHAR data; + USHORT temp, tempah, i, modeflag, j; + USHORT ResInfo, DisplayType; + SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL; + if ((SiS_VBType & VB_SIS302B) && (SiS_VBInfo & SetCRT2ToLCDA)) { + /*add crt1ptr */ + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + temp = + SiS_GetLCDACRT1Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &ResInfo, + &DisplayType); + + switch (DisplayType) { + case 0: + LCDACRT1Ptr = SiS_LCDACRT1800x600_1; + break; + case 1: + LCDACRT1Ptr = SiS_LCDACRT11024x768_1; + break; + case 2: + LCDACRT1Ptr = SiS_LCDACRT11280x1024_1; + break; + case 3: + LCDACRT1Ptr = SiS_LCDACRT1800x600_1_H; + break; + case 4: + LCDACRT1Ptr = SiS_LCDACRT11024x768_1_H; + break; + case 5: + LCDACRT1Ptr = SiS_LCDACRT11280x1024_1_H; + break; + case 6: + LCDACRT1Ptr = SiS_LCDACRT1800x600_2; + break; + case 7: + LCDACRT1Ptr = SiS_LCDACRT11024x768_2; + break; + case 8: + LCDACRT1Ptr = SiS_LCDACRT11280x1024_2; + break; + case 9: + LCDACRT1Ptr = SiS_LCDACRT1800x600_2_H; + break; + case 10: + LCDACRT1Ptr = SiS_LCDACRT11024x768_2_H; + break; + case 11: + LCDACRT1Ptr = SiS_LCDACRT11280x1024_2_H; + break; + /*case 12: LCDACRT1Ptr = SiS_CHTVCRT1UNTSC; break; + case 13: LCDACRT1Ptr = SiS_CHTVCRT1ONTSC; break; + case 14: LCDACRT1Ptr = SiS_CHTVCRT1UPAL; break; + case 15: LCDACRT1Ptr = SiS_CHTVCRT1OPAL; break; */ + } + + tempah = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); /*unlock cr0-7 */ + tempah = tempah & 0x7F; + SiS_SetReg1 (SiS_P3d4, 0x11, tempah); + tempah = (LCDACRT1Ptr + ResInfo)->CR[0]; + SiS_SetReg1 (SiS_P3d4, 0x0, tempah); + for (i = 0x01, j = 1; i <= 0x07; i++, j++) { + tempah = (LCDACRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } +/* for(i=0x06,j=5;i<=0x07;i++,j++){ + tempah = (LCDACRT1Ptr+ResInfo)->CR[j]; + SiS_SetReg1(SiS_P3d4,i,tempah); + }*/ + for (i = 0x10, j = 8; i <= 0x12; i++, j++) { + tempah = (LCDACRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x15, j = 11; i <= 0x16; i++, j++) { + tempah = (LCDACRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + + for (i = 0x0A, j = 13; i <= 0x0C; i++, j++) { + tempah = (LCDACRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3c4, i, tempah); + } + + tempah = (LCDACRT1Ptr + ResInfo)->CR[16]; + tempah = tempah & 0x0E0; + SiS_SetReg1 (SiS_P3c4, 0x0E, tempah); + + tempah = (LCDACRT1Ptr + ResInfo)->CR[16]; + tempah = tempah & 0x01; + tempah = tempah << 5; + if (modeflag & DoubleScanMode) { + tempah = tempah | 0x080; + } + SiS_SetRegANDOR (SiS_P3d4, 0x09, ~0x020, tempah); + if (SiS_ModeType > 0x03) + SiS_SetReg1 (SiS_P3d4, 0x14, 0x4F); +/*end 301b*/ + } else { + index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; /* Get index */ + index = index & 0x3F; + + data = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); + data = data & 0x7F; + SiS_SetReg1 (SiS_P3d4, 0x11, data); /* Unlock CRTC */ + + for (i = 0, j = 0; i <= 07; i++, j++) { + data = SiS_CRT1Table[index].CR[i]; + SiS_SetReg1 (SiS_P3d4, j, data); + } + for (j = 0x10; i <= 10; i++, j++) { + data = SiS_CRT1Table[index].CR[i]; + SiS_SetReg1 (SiS_P3d4, j, data); + } + for (j = 0x15; i <= 12; i++, j++) { + data = SiS_CRT1Table[index].CR[i]; + SiS_SetReg1 (SiS_P3d4, j, data); + } + for (j = 0x0A; i <= 15; i++, j++) { + data = SiS_CRT1Table[index].CR[i]; + SiS_SetReg1 (SiS_P3c4, j, data); + } + + data = SiS_CRT1Table[index].CR[16]; + data = data & 0xE0; + SiS_SetReg1 (SiS_P3c4, 0x0E, data); + + data = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x09); + data = data & 0xDF; /* clear CR9 D[5] */ + i = SiS_CRT1Table[index].CR[16]; + i = i & 0x01; + i = i << 5; + data = data | i; + + if (ModeNo <= 0x13) + i = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else + i = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + + i = i & DoubleScanMode; + if (i) + data = data | 0x80; + SiS_SetReg1 (SiS_P3d4, 0x09, data); + + if (SiS_ModeType > 0x03) + SiS_SetReg1 (SiS_P3d4, 0x14, 0x4F); + } +} +void +SiS_SetCRT1Offset (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp, ah, al; + USHORT temp2, i; + USHORT DisplayUnit; + + /* Alan */ + temp = SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo; + if (HwDeviceExtension->jChipType >= SIS_315H) { + temp = temp >> 8; /* sis310 *//* index */ + } else { + temp = temp >> 4; /* sis300 *//* index */ + } + temp = SiS_ScreenOffset[temp]; + if ((ModeNo >= 0x7C) && (ModeNo <= 0x7E)) { + temp = 0x6B; + temp2 = ModeNo - 0x7C; + } else { + temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + temp2 = temp2 & InterlaceMode; + if (temp2) + temp = temp << 1; + temp2 = SiS_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; /* ah */ + temp = temp & 0x0F; + i = SiS_GetReg1 (SiS_P3c4, 0x0E); + i = i & 0xF0; + i = i | temp; + SiS_SetReg1 (SiS_P3c4, 0x0E, i); + + temp = (UCHAR) temp2; + temp = temp & 0xFF; /* al */ + SiS_SetReg1 (SiS_P3d4, 0x13, temp); + + temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + 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; + SiS_SetReg1 (SiS_P3c4, 0x10, ah); +} + +void +SiS_SetCRT1VCLK (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + UCHAR index, data; + USHORT vclkindex; + if (SiS_IF_DEF_LVDS == 1) { + vclkindex = + SiS_GetVCLK2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + data = SiS_GetReg1 (SiS_P3c4, 0x31) & 0xCF; + SiS_SetReg1 (SiS_P3c4, 0x31, data); + + data = SiS_VCLKData[vclkindex].SR2B; + SiS_SetReg1 (SiS_P3c4, 0x2B, data); + data = SiS_VCLKData[vclkindex].SR2C; + SiS_SetReg1 (SiS_P3c4, 0x2C, data); + + if (HwDeviceExtension->jChipType < SIS_315H) + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x80); + else + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x01); + + } + else + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA) && (SiS_IF_DEF_LVDS == 0)) { + vclkindex = + SiS_GetVCLK2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + data = SiS_GetReg1 (SiS_P3c4, 0x31) & 0xCF; + SiS_SetReg1 (SiS_P3c4, 0x31, data); + + data = SiS_VBVCLKData[vclkindex].Part4_A; + SiS_SetReg1 (SiS_P3c4, 0x2B, data); + data = SiS_VBVCLKData[vclkindex].Part4_B; + SiS_SetReg1 (SiS_P3c4, 0x2C, data); + + if (HwDeviceExtension->jChipType < SIS_315H) + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x80); /* for300 series */ + else + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x01); + + } else { + index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + /*if(HwDeviceExtension->jChipType < SIS_315H) { */ + index = index & 0x3F; + /*} */ + data = SiS_GetReg1 (SiS_P3c4, 0x31) & 0xCF; +/*SiS_SetReg1(SiS_P3c4,0x31,0x00); *//* for300 */ + SiS_SetReg1 (SiS_P3c4, 0x31, data); + SiS_SetReg1 (SiS_P3c4, 0x2B, SiS_VCLKData[index].SR2B); + SiS_SetReg1 (SiS_P3c4, 0x2C, SiS_VCLKData[index].SR2C); + if (HwDeviceExtension->jChipType < SIS_315H) + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x80); /* for300 series */ + else + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x01); /* for310 series */ + } +} +void +SiS_IsLowResolution (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT data; + USHORT ModeFlag; + + data = SiS_GetReg1 (SiS_P3c4, 0x0F); + data = data & 0x7F; + SiS_SetReg1 (SiS_P3c4, 0x0F, data); + + if (ModeNo > 0x13) { + ModeFlag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + if ((ModeFlag & HalfDCLK) && (ModeFlag & DoubleScanMode)) { + data = SiS_GetReg1 (SiS_P3c4, 0x0F); + data = data | 0x80; + SiS_SetReg1 (SiS_P3c4, 0x0F, data); + data = SiS_GetReg1 (SiS_P3c4, 0x01); + data = data & 0xF7; + SiS_SetReg1 (SiS_P3c4, 0x01, data); + } + } +} + +void +SiS_SetCRT1ModeRegs (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT data, data2, data3; + USHORT infoflag = 0, modeflag; + USHORT resindex, xres; + + if (ModeNo > 0x13) { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + } else { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ModeFlag */ + } + SiS_SetRegANDOR (SiS_P3c4, 0x1F, 0x3F, 0x00); + if (ModeNo > 0x13) + data = infoflag; + else + data = 0; + data2 = 0; + if (ModeNo > 0x13) { + if (SiS_ModeType > 0x02) { + data2 = data2 | 0x02; + data3 = SiS_ModeType - ModeVGA; + data3 = data3 << 2; + data2 = data2 | data3; + } + } + data = data & InterlaceMode; + if (data) + data2 = data2 | 0x20; + SiS_SetReg1 (SiS_P3c4, 0x06, data2); + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_730)) { + resindex = SiS_GetResInfo (ROMAddr, ModeNo, ModeIdIndex); + if (ModeNo <= 0x13) { + xres = SiS_StResInfo[resindex].HTotal; + } else { + xres = SiS_ModeResInfo[resindex].HTotal; /* xres->ax */ + } + data = 0x0000; + if (infoflag & InterlaceMode) { + if (xres == 1024) + data = 0x0035; + if (xres == 1280) + data = 0x0048; + } + data2 = data & 0x00FF; + SiS_SetRegANDOR (SiS_P3d4, 0x19, 0xFF, data2); + data2 = (data & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_P3d4, 0x19, 0xFC, data2); + } + if (modeflag & HalfDCLK) { + SiS_SetRegANDOR (SiS_P3c4, 0x01, 0xFF, 0x01); + } + + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_730)) { + } else { + if (modeflag & LineCompareOff) { + SiS_SetRegANDOR (SiS_P3c4, 0x0F, 0xF7, 0x08); + } else { + SiS_SetRegANDOR (SiS_P3c4, 0x0F, 0xF7, 0x00); + } + } + + data = 0x60; + if (SiS_ModeType != ModeText) { + data = data ^ 0x60; + if (SiS_ModeType != ModeEGA) { + data = data ^ 0xA0; + } + } + SiS_SetRegANDOR (SiS_P3c4, 0x21, 0x1F, data); +} + +void +SiS_SetVCLKState (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT RefreshRateTableIndex) +{ + USHORT data, data2 = 0; + USHORT VCLK; + UCHAR index; + + if (ModeNo <= 0x13) + VCLK = 0; + else { + index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + /*if(HwDeviceExtension->jChipType < SIS_315H) { */ + index = index & 0x3F; + /*} */ + VCLK = SiS_VCLKData[index].CLOCK; + } + + if (HwDeviceExtension->jChipType < SIS_315H) { + data2 = 0x00; + if (VCLK > 150) + data2 = data2 | 0x80; + SiS_SetRegANDOR (SiS_P3c4, 0x07, 0x7B, data2); + + data2 = 0x00; + if (VCLK >= 150) + data2 = data2 | 0x08; /* VCLK > 150 */ + SiS_SetRegANDOR (SiS_P3c4, 0x32, 0xF7, data2); + } else { /* 310 series */ + + data = SiS_GetReg1 (SiS_P3c4, 0x32); + data = data & 0xf3; + if (VCLK >= 200) + data = data | 0x0c; /* VCLK > 200 */ + SiS_SetReg1 (SiS_P3c4, 0x32, data); + data = SiS_GetReg1 (SiS_P3c4, 0x1F); + data &= 0xE7; + if (VCLK < 200) + data |= 0x10; + SiS_SetReg1 (SiS_P3c4, 0x1F, data); + } + + if ((VCLK >= 0) && (VCLK < 135)) + data2 = 0x03; + if ((VCLK >= 135) && (VCLK < 160)) + data2 = 0x02; + if ((VCLK >= 160) && (VCLK < 260)) + data2 = 0x01; + if (VCLK > 260) + data2 = 0x00; + /* disable 24bit palette RAM gamma correction */ + + if (HwDeviceExtension->jChipType == SIS_540) { + if ((VCLK == 203) || (VCLK < 234)) + data2 = 0x02; + } + SiS_SetRegANDOR (SiS_P3c4, 0x07, 0xFC, data2); +} + +void +SiS_LoadDAC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT data, data2; + USHORT time, i, j, k; + USHORT m, n, o; + USHORT si, di, bx, dl; + USHORT al, ah, dh; + USHORT *table = NULL; + + if (ModeNo <= 0x13) + data = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else + data = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + + data = data & DACInfoFlag; + time = 64; + if (data == 0x00) + table = SiS_MDA_DAC; + if (data == 0x08) + table = SiS_CGA_DAC; + if (data == 0x10) + table = SiS_EGA_DAC; + if (data == 0x18) { + time = 256; + table = SiS_VGA_DAC; + } + if (time == 256) + j = 16; + else + j = time; + + SiS_SetReg3 (SiS_P3c6, 0xFF); + SiS_SetReg3 (SiS_P3c8, 0x00); + + for (i = 0; i < j; i++) { + data = table[i]; + for (k = 0; k < 3; k++) { + data2 = 0; + if (data & 0x01) + data2 = 0x2A; + if (data & 0x02) + data2 = data2 + 0x15; + SiS_SetReg3 (SiS_P3c9, data2); + data = data >> 2; + } + } + + if (time == 256) { + for (i = 16; i < 32; i++) { + data = table[i]; + for (k = 0; k < 3; k++) + SiS_SetReg3 (SiS_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++; + SiS_WriteDAC (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--; + SiS_WriteDAC (dl, ah, al, dh); + } /* for 3 */ + dl++; + } /* for 3 */ + si = si + 5; + } /* for 9 */ + } +} + +void +SiS_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; + } + } + SiS_SetReg3 (SiS_P3c9, (USHORT) dh); + SiS_SetReg3 (SiS_P3c9, (USHORT) bh); + SiS_SetReg3 (SiS_P3c9, (USHORT) bl); +} + +void +SiS_ClearBuffer (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo) +{ + PVOID VideoMemoryAddress = + (PVOID) HwDeviceExtension->pjVideoMemoryAddress; + ULONG AdapterMemorySize = (ULONG) HwDeviceExtension->ulVideoMemorySize; + PUSHORT pBuffer; + int i; + + if (SiS_ModeType >= ModeEGA) { + if (ModeNo > 0x13) { + SiS_SetMemory (VideoMemoryAddress, AdapterMemorySize, + 0); + } else { + pBuffer = VideoMemoryAddress; + for (i = 0; i < 0x4000; i++) + pBuffer[i] = 0x0000; + } + } else { + pBuffer = VideoMemoryAddress; + if (SiS_ModeType == ModeCGA) { + for (i = 0; i < 0x4000; i++) + pBuffer[i] = 0x0720; + } else { + for (i = 0; i < 0x4000; i++) + pBuffer[i] = 0x0000; + } + } +} + +void +SiS_DisplayOn (void) +{ + + SiS_SetRegANDOR (SiS_P3c4, 0x01, 0xDF, 0x00); +} + +void +SiS_DisplayOff (void) +{ + + SiS_SetRegANDOR (SiS_P3c4, 0x01, 0xDF, 0x20); +} + +/* ========================================== */ +/* SR CRTC GR */ +void +SiS_SetReg1 (USHORT port, USHORT index, USHORT data) +{ + OutPortByte (port, index); + OutPortByte (port + 1, data); + + /* + _asm + { + mov dx, port + mov ax, index + mov bx, data + out dx, al + mov ax, bx + inc dx + out dx, al + } + */ + +} + +/* ========================================== */ +/* AR(3C0) */ +void +SiS_SetReg2 (USHORT port, USHORT index, USHORT data) +{ + + InPortByte (port + 0x3da - 0x3c0); + OutPortByte (SiS_P3c0, index); + OutPortByte (SiS_P3c0, data); + OutPortByte (SiS_P3c0, 0x20); + + /* + _asm + { + mov dx, port + mov cx, index + mov bx, data + + add dx, 3dah-3c0h + in al, dx + + mov ax, cx + mov dx, 3c0h + out dx, al + mov ax, bx + out dx, al + + mov ax, 20h + out dx, al + } + */ + +} + +/* ========================================== */ +void +SiS_SetReg3 (USHORT port, USHORT data) +{ + + OutPortByte (port, data); + + /* + _asm + { + mov dx, port + mov ax, data + out dx, al + + } + */ + +} + +/* ========================================== */ +void +SiS_SetReg4 (USHORT port, ULONG data) +{ + + OutPortLong (port, data); + + /* + _asm + { + mov dx, port ;; port + mov eax, data ;; data + out dx, eax + + } + */ +} + +/* ========================================= */ +UCHAR SiS_GetReg1 (USHORT port, USHORT index) +{ + UCHAR data; + + OutPortByte (port, index); + data = InPortByte (port + 1); + + /* + _asm + { + mov dx, port ;; port + mov ax, index ;; index + + out dx, al + mov ax, bx + inc dx + xor eax, eax + in al, dx + mov data, al + } + */ + return (data); +} + +/* ========================================== */ +UCHAR SiS_GetReg2 (USHORT port) +{ + UCHAR data; + + data = InPortByte (port); + + /* + _asm + { + mov dx, port ;; port + xor eax, eax + in al, dx + mov data, al + } + */ + return (data); +} + +/* ========================================== */ +ULONG SiS_GetReg3 (USHORT port) +{ + ULONG data; + + data = InPortLong (port); + + /* + _asm + { + mov dx, port ;; port + xor eax, eax + in eax, dx + mov data, eax + } + */ + return (data); +} + +/* ========================================== */ +void +SiS_ClearDAC (ULONG port) +{ + int i; + + OutPortByte (port, 0); + port++; + for (i = 0; i < 256 * 3; i++) { + OutPortByte (port, 0); + } + +} + +/*========================================== */ + +void +SiS_SetInterlace (ULONG ROMAddr, USHORT ModeNo, USHORT RefreshRateTableIndex) +{ + ULONG Temp; + USHORT data, Temp2; + + Temp = (ULONG) SiS_GetReg1 (SiS_P3d4, 0x01); + Temp++; + Temp = Temp * 8; + + if (Temp == 1024) + data = 0x0035; + else if (Temp == 1280) + data = 0x0048; + else + data = 0x0000; + + Temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + Temp2 &= InterlaceMode; + if (Temp2 == 0) + data = 0x0000; + + SiS_SetReg1 (SiS_P3d4, 0x19, data); + + Temp = (ULONG) SiS_GetReg1 (SiS_P3d4, 0x1A); + Temp2 = (USHORT) (Temp & 0xFC); + SiS_SetReg1 (SiS_P3d4, 0x1A, (USHORT) Temp); + + Temp = (ULONG) SiS_GetReg1 (SiS_P3c4, 0x0f); + Temp2 = (USHORT) Temp & 0xBF; + if (ModeNo == 0x37) + Temp2 = Temp2 | 0x40; + SiS_SetReg1 (SiS_P3d4, 0x1A, (USHORT) Temp2); +} + +void +SiS_SetCRT1FIFO (ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + + USHORT data; + + data = SiS_GetReg1 (SiS_P3c4, 0x3D); + data &= 0xfe; + SiS_SetReg1 (SiS_P3c4, 0x3D, data); /* diable auto-threshold */ + if (ModeNo > 0x13) { + SiS_SetReg1 (SiS_P3c4, 0x08, 0x34); + data = SiS_GetReg1 (SiS_P3c4, 0x09); + data &= 0xF0; + SiS_SetReg1 (SiS_P3c4, 0x09, data); + + data = SiS_GetReg1 (SiS_P3c4, 0x3D); + data |= 0x01; + SiS_SetReg1 (SiS_P3c4, 0x3D, data); + } else { + SiS_SetReg1 (SiS_P3c4, 0x08, 0xAE); + data = SiS_GetReg1 (SiS_P3c4, 0x09); + data &= 0xF0; + SiS_SetReg1 (SiS_P3c4, 0x09, data); + } + +} + +USHORT +SiS_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 = SiS_GetReg1 (SiS_P3c4, 0x16); + data = data >> 6; + data2 = SiS_GetReg1 (SiS_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 = SiS_GetReg1 (SiS_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 +SiS_SetCRT1FIFO2 (ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT i, index, data, VCLK, data2, MCLK, colorth = 0; + USHORT ah, bl, B; + ULONG eax; + USHORT ThresholdLow = 0; + UCHAR FQBQData[] = { 0x01, 0x21, 0x41, 0x61, 0x81, + 0x31, 0x51, 0x71, 0x91, 0xb1, + 0x00, 0x20, 0x40, 0x60, 0x80, + 0x30, 0x50, 0x70, 0x90, 0xb0, 0xFF + }; + + if (ModeNo >= 0x13) { + index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + if (HwDeviceExtension->jChipType < SIS_315H) { /* for300 serial */ + index = index & 0x3F; + } + VCLK = SiS_VCLKData[index].CLOCK; /* Get VCLK */ + index = SiS_GetReg1 (SiS_P3c4, 0x1A); + index = index & 07; + MCLK = SiS_MCLKData[index].CLOCK; /* Get MCLK */ + data2 = SiS_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; + } + + i = 0; + do { + B = + (SiS_CalcDelay2 (ROMAddr, FQBQData[i]) * VCLK * + colorth); + bl = B / (16 * MCLK); + if (B == bl * 16 * MCLK) { + bl = bl + 1; + } else { + bl = bl + 1; + } + + if (bl > 0x13) { + if (FQBQData[i + 1] == 0xFF) { + ThresholdLow = 0x13; + break; + } + i++; + } else { + ThresholdLow = bl; + break; + } + } while (FQBQData[i] != 0xFF); + } else { + ThresholdLow = 0x02; + } + + data2 = FQBQData[i]; + data2 = (data2 & 0xf0) >> 4; + data2 = data2 << 24; + + SiS_SetReg4 (0xcf8, 0x80000050); + eax = SiS_GetReg3 (0xcfc); + eax = eax & 0x0f0ffffff; + eax = eax | data2; + SiS_SetReg4 (0xcfc, eax); + + ah = ThresholdLow; + ah = ah << 4; + ah = ah | 0x0f; + SiS_SetReg1 (SiS_P3c4, 0x08, ah); + + data = ThresholdLow; + data = data & 0x10; + data = data << 1; + SiS_SetRegANDOR (SiS_P3c4, 0x0F, 0xDF, data); + SiS_SetReg1 (SiS_P3c4, 0x3B, 0x09); + + data = ThresholdLow + 3; + if (data > 0x0f) + data = 0x0f; + SiS_SetRegANDOR (SiS_P3c4, 0x09, 0x80, data); +} + +USHORT +SiS_CalcDelay2 (ULONG ROMAddr, UCHAR key) +{ + USHORT data, index; + UCHAR LatencyFactor[] = { 97, 88, 86, 79, 77, 00, /*; 64 bit BQ=2 */ + 00, 87, 85, 78, 76, 54, /*; 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 00, /*; 128 bit BQ=2 */ + 00, 79, 77, 70, 68, 48, /*; 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 00, /*; 64 bit BQ=2 */ + 00, 70, 68, 61, 59, 37, /*; 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 00, /*; 128 bit BQ=2 */ + 00, 68, 66, 59, 57, 37 + }; /*; 128 bit BQ=1 */ + + index = (key & 0xE0) >> 5; + if (key & 0x10) + index = index + 6; + if (!(key & 0x01)) + index = index + 24; + data = SiS_GetReg1 (SiS_P3c4, 0x14); + if (data & 0x0080) + index = index + 12; + + data = LatencyFactor[index]; + return (data); +} + +void +SiS_CRT2AutoThreshold (USHORT BaseAddr) +{ + USHORT temp1; + USHORT Part1Port; + Part1Port = BaseAddr + SIS_CRT2_PORT_04; + temp1 = SiS_GetReg1 (SiS_Part1Port, 0x1); + temp1 |= 0x40; + SiS_SetReg1 (SiS_Part1Port, 0x1, temp1); +} + +/* ============= ynlai ============== */ +void +SiS_DetectMonitor (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + UCHAR DAC_TEST_PARMS[] = { 0x0F, 0x0F, 0x0F }; + UCHAR DAC_CLR_PARMS[] = { 0x00, 0x00, 0x00 }; + USHORT SR1F; + + SR1F = SiS_GetReg1 (SiS_P3c4, 0x1F); + SiS_SetRegANDOR (SiS_P3c4, 0x1F, 0xFF, 0x04); + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_BridgeIsOn (BaseAddr)) { + SiS_SetReg1 (SiS_P3d4, 0x30, 0x41); + } + } + SiSSetMode (HwDeviceExtension, 0x03); /* InitMode */ + SiS_SetReg3 (SiS_P3c6, 0xff); + SiS_ClearDAC (SiS_P3c8); + SiS_LongWait (); + SiS_LongWait (); + SiS_SetRegANDOR (SiS_P3d4, 0x32, 0xDF, 0x00); + if (SiS_TestMonitorType + (DAC_TEST_PARMS[0], DAC_TEST_PARMS[1], DAC_TEST_PARMS[2])) { + SiS_SetRegANDOR (SiS_P3d4, 0x32, 0xDF, 0x20); + } + if (SiS_TestMonitorType + (DAC_TEST_PARMS[0], DAC_TEST_PARMS[1], DAC_TEST_PARMS[2])) { + SiS_SetRegANDOR (SiS_P3d4, 0x32, 0xDF, 0x20); + } + SiS_TestMonitorType (DAC_CLR_PARMS[0], DAC_CLR_PARMS[1], + DAC_CLR_PARMS[2]); + SiS_SetReg1 (SiS_P3c4, 0x1F, SR1F); +} + +USHORT +SiS_TestMonitorType (UCHAR R_DAC, UCHAR G_DAC, UCHAR B_DAC) +{ + USHORT temp, tempbx; + + tempbx = R_DAC * 0x4d + G_DAC * 0x97 + B_DAC * 0x1c; + if (tempbx > 0x80) + tempbx = tempbx + 0x100; + tempbx = (tempbx & 0xFF00) >> 8; + R_DAC = (UCHAR) tempbx; + G_DAC = (UCHAR) tempbx; + B_DAC = (UCHAR) tempbx; + + SiS_SetReg3 (SiS_P3c8, 0x00); + SiS_SetReg3 (SiS_P3c9, R_DAC); + SiS_SetReg3 (SiS_P3c9, G_DAC); + SiS_SetReg3 (SiS_P3c9, B_DAC); + SiS_LongWait (); + temp = SiS_GetReg2 (SiS_P3c2); + if (temp & 0x10) + return (1); + else + return (0); +} + +/* ---- test ----- */ +void +SiS_GetSenseStatus (PSIS_HW_DEVICE_INFO HwDeviceExtension, ULONG ROMAddr) +{ + USHORT tempax = 0, tempbx, tempcx, temp; + USHORT P2reg0 = 0, SenseModeNo = 0, OutputSelect = *pSiS_OutputSelect; + USHORT ModeIdIndex, i; + USHORT BaseAddr = (USHORT) HwDeviceExtension->ulIOAddress; + + if (SiS_IF_DEF_LVDS == 1) { + SiS_GetPanelID (); + temp = LCDSense; + temp = temp | SiS_SenseCHTV (); + tempbx = ~(LCDSense | AVIDEOSense | SVIDEOSense); + SiS_SetRegANDOR (SiS_P3d4, 0x32, tempbx, temp); + } else { /* for 301 */ + if (SiS_IF_DEF_HiVision == 1) { /* for HiVision */ + tempax = SiS_GetReg1 (SiS_P3c4, 0x38); + temp = tempax & 0x01; + tempax = SiS_GetReg1 (SiS_P3c4, 0x3A); + temp = temp | (tempax & 0x02); + SiS_SetRegANDOR (SiS_P3d4, 0x32, 0xA0, temp); + } else { + if (SiS_BridgeIsOn (BaseAddr)) { + P2reg0 = SiS_GetReg1 (SiS_Part2Port, 0x00); + if (!SiS_BridgeIsEnable + (BaseAddr, HwDeviceExtension)) { + SenseModeNo = 0x2e; + temp = + SiS_SearchModeID (ROMAddr, + SenseModeNo, + &ModeIdIndex); + SiS_SetFlag = 0x00; + SiS_ModeType = ModeVGA; + SiS_VBInfo = + SetCRT2ToRAMDAC | LoadDACFlag | + SetInSlaveMode; + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, + SenseModeNo, + HwDeviceExtension); + for (i = 0; i < 20; i++) { + SiS_LongWait (); + } + } + SiS_SetReg1 (SiS_Part2Port, 0x00, 0x1c); + tempax = 0; + tempbx = *pSiS_RGBSenseData; + /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + tempbx = *pSiS_RGBSenseData2; + } + /*end 301b */ + tempcx = 0x0E08; + if (SiS_Sense (SiS_Part4Port, tempbx, tempcx)) { + if (SiS_Sense + (SiS_Part4Port, tempbx, tempcx)) { + tempax = tempax | Monitor2Sense; + } + } + + tempbx = *pSiS_YCSenseData; + /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + tempbx = *pSiS_YCSenseData2; + } + /*301b */ + tempcx = 0x0604; + if (SiS_Sense (SiS_Part4Port, tempbx, tempcx)) { + if (SiS_Sense + (SiS_Part4Port, tempbx, tempcx)) { + tempax = tempax | SVIDEOSense; + } + } + + if (OutputSelect & BoardTVType) { + tempbx = *pSiS_VideoSenseData; + /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + tempbx = *pSiS_VideoSenseData2; + } + /*end 301b */ + tempcx = 0x0804; + if (SiS_Sense + (SiS_Part4Port, tempbx, tempcx)) { + if (SiS_Sense + (SiS_Part4Port, tempbx, + tempcx)) { + tempax = + tempax | + AVIDEOSense; + } + } + } else { + if (!(tempax & SVIDEOSense)) { + tempbx = *pSiS_VideoSenseData; + /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + tempbx = + *pSiS_VideoSenseData2; + } + /*end 301b */ + tempcx = 0x0804; + if (SiS_Sense + (SiS_Part4Port, tempbx, + tempcx)) { + if (SiS_Sense + (SiS_Part4Port, + tempbx, tempcx)) { + tempax = + tempax | + AVIDEOSense; + } + } + } + } + } + + if (SiS_SenseLCD (HwDeviceExtension)) { + tempax = tempax | LCDSense; + } + + tempbx = 0; + tempcx = 0; + SiS_Sense (SiS_Part4Port, tempbx, tempcx); + + SiS_SetRegANDOR (SiS_P3d4, 0x32, ~0xDF, tempax); + SiS_SetReg1 (SiS_Part2Port, 0x00, P2reg0); + if (!(P2reg0 & 0x20)) { + SiS_VBInfo = DisableCRT2Display; + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, + SenseModeNo, + HwDeviceExtension); + } + } + } +} + +BOOLEAN +SiS_Sense (USHORT Part4Port, USHORT tempbx, USHORT tempcx) +{ + USHORT temp, i, tempch; + + temp = tempbx & 0xFF; + SiS_SetReg1 (SiS_Part4Port, 0x11, temp); + temp = (tempbx & 0xFF00) >> 8; + temp = temp | (tempcx & 0x00FF); + SiS_SetRegANDOR (SiS_Part4Port, 0x10, ~0x1F, temp); + + for (i = 0; i < 10; i++) + SiS_LongWait (); + + tempch = (tempcx & 0x7F00) >> 8; /* ynlai [05/22/2001] */ + temp = SiS_GetReg1 (SiS_Part4Port, 0x03); + temp = temp ^ (0x0E); + temp = temp & tempch; /* ynlai [05/22/2001] */ + if (temp > 0) + return 1; + else + return 0; +} + +USHORT +SiS_SenseLCD (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ +/* USHORT SoftSetting; */ + USHORT temp; + + temp = SiS_GetPanelID (); + if (!temp) + temp = SiS_GetLCDDDCInfo (HwDeviceExtension); + return (temp); +} + +BOOLEAN +SiS_GetLCDDDCInfo (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp; + //add lcd sense + if (HwDeviceExtension->ulCRT2LCDType == LCD_UNKNOWN) + return 0; + else { + temp = (USHORT) HwDeviceExtension->ulCRT2LCDType; + SiS_SetReg1 (SiS_P3d4, 0x36, temp); + return 1; + } +} + +BOOLEAN +SiS_GetPanelID (void) +{ + USHORT PanelTypeTable[16] = + { SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType00, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType01, + SyncPP | PanelRGB18Bit | Panel800x600 | _PanelType02, + SyncNN | PanelRGB18Bit | Panel640x480 | _PanelType03, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType04, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType05, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType06, + SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType07, + SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType08, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType09, + SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType0A, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0B, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0C, + SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType0D, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0E, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0F + }; + USHORT tempax, tempbx, temp; +/* USHORT return_flag; */ + + tempax = SiS_GetReg1 (SiS_P3c4, 0x18); + tempbx = tempax & 0x0F; + if (!(tempax & 0x10)) { + if (SiS_IF_DEF_LVDS == 1) { + tempbx = 0; + temp = SiS_GetReg1 (SiS_P3c4, 0x38); + if (temp & 0x40) + tempbx = tempbx | 0x08; + if (temp & 0x20) + tempbx = tempbx | 0x02; + if (temp & 0x01) + tempbx = tempbx | 0x01; + temp = SiS_GetReg1 (SiS_P3c4, 0x39); + if (temp & 0x80) + tempbx = tempbx | 0x04; + } else { + return 0; + } + } + + tempbx = tempbx << 1; + tempbx = PanelTypeTable[tempbx]; + tempbx = tempbx | LCDSync; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_P3d4, 0x36, temp); + temp = (tempbx & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_P3d4, 0x37, ~(LCDSyncBit | LCDRGB18Bit), temp); + return 1; +} + +USHORT +SiS_SenseCHTV (void) +{ + USHORT temp, push0e, status; + + status = 0; + push0e = SiS_GetCH7005 (0x0e); + push0e = (push0e << 8) | 0x0e; + SiS_SetCH7005 (0x0b0e); + SiS_SetCH7005 (0x0110); + SiS_SetCH7005 (0x0010); + temp = SiS_GetCH7005 (0x10); + if (temp & 0x08) + status = status | SVIDEOSense; + if (temp & 0x02) + status = status | AVIDEOSense; + SiS_SetCH7005 (push0e); + return (status); +} + +/* ========================================== */ +#ifdef TC + +int +INT1AReturnCode (union REGS regs) +{ + if (regs.x.cflag) { + /*printf("Error to find pci device!\n"); */ + return 1; + } + + switch (regs.h.ah) { + case 0: + return 0; + break; + case 0x81: + printf ("Function not support\n"); + break; + case 0x83: + printf ("bad vendor id\n"); + break; + case 0x86: + printf ("device not found\n"); + break; + case 0x87: + printf ("bad register number\n"); + break; + case 0x88: + printf ("set failed\n"); + break; + case 0x89: + printf ("buffer too small"); + break; + } + return 1; +} + +unsigned +FindPCIIOBase (unsigned index, unsigned deviceid) +{ + union REGS regs; + + regs.h.ah = 0xb1; /*PCI_FUNCTION_ID */ + regs.h.al = 0x02; /*FIND_PCI_DEVICE */ + regs.x.cx = deviceid; + regs.x.dx = 0x1039; + regs.x.si = index; /* find n-th device */ + + int86 (0x1A, ®s, ®s); + + if (INT1AReturnCode (regs) != 0) + return 0; + +/* regs.h.bh *//* bus number */ +/* regs.h.bl *//* device number */ + regs.h.ah = 0xb1; /*PCI_FUNCTION_ID */ + regs.h.al = 0x09; /*READ_CONFIG_WORD */ + regs.x.cx = deviceid; + regs.x.dx = 0x1039; + regs.x.di = 0x18; /* register number */ + int86 (0x1A, ®s, ®s); + + if (INT1AReturnCode (regs) != 0) + return 0; + return regs.x.cx; +} + +void +main (int argc, char *argv[]) +/* void main() */ +{ + SIS_HW_DEVICE_INFO HwDeviceExtension; + USHORT temp; + USHORT ModeNo; + + /*HwDeviceExtension.pjVirtualRomBase =(PUCHAR) MK_FP(0xC000,0); */ + /*HwDeviceExtension.pjVideoMemoryAddress = (PUCHAR)MK_FP(0xA000,0); */ +#ifdef CONFIG_FB_SIS_300 + HwDeviceExtension.ulIOAddress = + (FindPCIIOBase (0, 0x6300) & 0xFF80) + 0x30; + HwDeviceExtension.jChipType = SIS_630; +#endif + +#ifdef CONFIG_FB_SIS_315 +// HwDeviceExtension.ulIOAddress = (FindPCIIOBase(0,0x5315)&0xFF80) + 0x30; +// HwDeviceExtension.jChipType = SIS_550; + HwDeviceExtension.ulIOAddress = + (FindPCIIOBase (0, 0x325) & 0xFF80) + 0x30; + HwDeviceExtension.jChipType = SIS_315H; +#endif + HwDeviceExtension.ujVBChipID = VB_CHIP_301; + strcpy (HwDeviceExtension.szVBIOSVer, "0.84"); + HwDeviceExtension.bSkipDramSizing = FALSE; + HwDeviceExtension.ulVideoMemorySize = 0; + if (argc == 2) { + ModeNo = atoi (argv[1]); + } else { + ModeNo = 0x2e; + /*ModeNo=0x37; 1024x768x 4bpp */ + /*ModeNo=0x38; 1024x768x 8bpp */ + /*ModeNo=0x4A; 1024x768x 16bpp */ + /*ModeNo=0x47; 800x600x 16bpp */ + } + // SiSInit(&HwDeviceExtension); + SiSSetMode (&HwDeviceExtension, ModeNo); + +} +#endif diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h new file mode 100644 index 000000000000..724df4d5d87f --- /dev/null +++ b/drivers/video/sis/init.h @@ -0,0 +1,227 @@ +#ifndef _INIT_ +#define _INIT_ + +#include "osdef.h" +#include "initdef.h" +#include "vgatypes.h" +#include "vstruct.h" + +#include +#include +#include + + +USHORT SiS_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 SiS_SDRDRAM_TYPE[13][5] = { + {2, 12, 9, 64, 0x35}, + {1, 13, 9, 64, 0x44}, + {2, 12, 8, 32, 0x31}, + {2, 11, 9, 32, 0x25}, + {1, 12, 9, 32, 0x34}, + {1, 13, 8, 32, 0x40}, + {2, 11, 8, 16, 0x21}, + {1, 12, 8, 16, 0x30}, + {1, 11, 9, 16, 0x24}, + {1, 11, 8, 8, 0x20}, + {2, 9, 8, 4, 0x01}, + {1, 10, 8, 4, 0x10}, + {1, 9, 8, 2, 0x00} +}; + +USHORT SiS_DDRDRAM_TYPE[4][5] = { + {2, 12, 9, 64, 0x35}, + {2, 12, 8, 32, 0x31}, + {2, 11, 8, 16, 0x21}, + {2, 9, 8, 4, 0x01} +}; + +UCHAR SiS_ChannelAB, SiS_DataBusWidth; + +USHORT SiS_MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F +}; + +USHORT SiS_CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F +}; + +USHORT SiS_EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, + 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, + 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, + 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, + 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, + 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, + 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F +}; + +USHORT SiS_VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, + 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, + + 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, + 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, + 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, + 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, + 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, + 0x0B, 0x0C, 0x0D, 0x0F, 0x10 +}; + +USHORT SiS_P3c4, SiS_P3d4, SiS_P3c0, SiS_P3ce, SiS_P3c2; +USHORT SiS_P3ca, SiS_P3c6, SiS_P3c7, SiS_P3c8, SiS_P3c9, SiS_P3da; +USHORT SiS_Part1Port, SiS_Part2Port; +USHORT SiS_Part3Port, SiS_Part4Port, SiS_Part5Port; +USHORT SiS_CRT1Mode; + +USHORT flag_clearbuffer; /*0: no clear frame buffer 1:clear frame buffer */ +int SiS_RAMType; /*int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,REFIndex; */ +USHORT SiS_ModeType; +USHORT SiS_IF_DEF_LVDS, SiS_IF_DEF_TRUMPION, SiS_IF_DEF_DSTN; /*add for dstn */ +USHORT SiS_IF_DEF_CH7005, SiS_IF_DEF_HiVision; +USHORT SiS_VBInfo, SiS_LCDResInfo, SiS_LCDTypeInfo, SiS_LCDInfo, SiS_VBType; /*301b */ +USHORT SiS_SelectCRT2Rate; + +extern USHORT SiS_SetFlag; + +void SiS_SetMemoryClock (ULONG ROMAddr); +void SiS_SetDRAMModeRegister (ULONG ROMAddr); +void SiS_SetDRAMSize_310 (PSIS_HW_DEVICE_INFO); +void SiS_SetDRAMSize_300 (PSIS_HW_DEVICE_INFO HwDeviceExtension); +USHORT SiS_ChkBUSWidth_300 (ULONG FBAddress); +UCHAR SiS_Get310DRAMType (ULONG ROMAddr); + +void SiS_Delay15us (ULONG); +BOOLEAN SiS_SearchModeID (ULONG ROMAddr, USHORT ModeNo, USHORT * ModeIdIndex); +BOOLEAN SiS_CheckMemorySize (ULONG ROMAddr, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex); +UCHAR SiS_GetModePtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_SetSeqRegs (ULONG, USHORT StandTableIndex); +void SiS_SetMiscRegs (ULONG, USHORT StandTableIndex); +void SiS_SetCRTCRegs (ULONG, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT StandTableIndex); +void SiS_SetATTRegs (ULONG, USHORT StandTableIndex); +void SiS_SetGRCRegs (ULONG, USHORT StandTableIndex); +void SiS_ClearExt1Regs (void); +void SiS_SetSync (ULONG ROMAddr, USHORT RefreshRateTableIndex); +void SiS_SetCRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_SetCRT1VCLK (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO, USHORT RefreshRateTableIndex); +void SiS_SetVCLKState (ULONG ROMAddr, PSIS_HW_DEVICE_INFO, USHORT ModeNo, + USHORT RefreshRateTableIndex); +void SiS_LoadDAC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_DisplayOn (void); +void SiS_SetCRT1ModeRegs (ULONG ROMAddr, PSIS_HW_DEVICE_INFO, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex); +void SiS_WriteDAC (USHORT, USHORT, USHORT, USHORT); +void SiS_GetVBType (USHORT BaseAddr); /*301b */ +USHORT SiS_ChkBUSWidth (ULONG); +USHORT SiS_GetModeIDLength (ULONG, USHORT); +USHORT SiS_GetRefindexLength (ULONG, USHORT); +void SiS_SetInterlace (ULONG ROMAddr, USHORT ModeNo, + USHORT RefreshRateTableIndex); +USHORT SiS_CalcDelay2 (ULONG, UCHAR); +USHORT SiS_CalcDelay (ULONG, USHORT); +void SiS_Set_LVDS_TRUMPION (PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetCRT1Offset (ULONG, USHORT, USHORT, USHORT, PSIS_HW_DEVICE_INFO); +void SiS_SetCRT1FIFO (ULONG, USHORT, PSIS_HW_DEVICE_INFO); +void SiS_SetCRT1FIFO2 (ULONG, USHORT ModeNo, PSIS_HW_DEVICE_INFO, + USHORT RefreshRateTableIndex); +void SiS_CRT2AutoThreshold (USHORT BaseAddr); +void SiS_ClearBuffer (PSIS_HW_DEVICE_INFO, USHORT ModeNo); +void SiS_SetCRT1Group (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex); +void SiS_DetectMonitor (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr); +void SiS_GetSenseStatus (PSIS_HW_DEVICE_INFO HwDeviceExtension, ULONG ROMAddr); +USHORT SiS_TestMonitorType (UCHAR R_DAC, UCHAR G_DAC, UCHAR B_DAC); +USHORT SiS_SenseCHTV (VOID); +BOOLEAN SiS_Sense (USHORT Part4Port, USHORT tempbx, USHORT tempcx); +BOOLEAN SiS_GetPanelID (VOID); +BOOLEAN SiS_GetLCDDDCInfo (PSIS_HW_DEVICE_INFO); +USHORT SiS_SenseLCD (PSIS_HW_DEVICE_INFO); + +extern BOOLEAN SiS_SetCRT2Group301 (USHORT BaseAddr, ULONG ROMAddr, + USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern void SiS_PresetScratchregister (USHORT SiS_P3d4, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern void SiS_UnLockCRT2 (PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT BaseAddr); +extern void SiS_LockCRT2 (PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT BaseAddr); +extern BOOLEAN SiS_BridgeIsOn (USHORT BaseAddr); +extern BOOLEAN SiS_BridgeIsEnable (USHORT BaseAddr, PSIS_HW_DEVICE_INFO); +extern void SiS_SetTVSystem301 (VOID); +extern BOOLEAN SiS_GetLCDDDCInfo301 (PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN SiS_GetSenseStatus301 (PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT BaseAddr, ULONG ROMAddr); +extern USHORT SiS_GetVCLKLen (ULONG ROMAddr, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN SiS_SetCRT2Group302 (USHORT BaseAddr, ULONG ROMAddr, + USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern void SiS_GetVBInfo301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN SiS_GetLCDResInfo301 (ULONG ROMAddr, USHORT P3d4, USHORT ModeNo, + USHORT ModeIdIndex); +extern USHORT SiS_VBInfo, LCDResInfo, LCDTypeInfo, LCDInfo; +extern USHORT SiS_GetRatePtrCRT2 (ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex); +extern void SiS_LongWait (VOID); +extern void SiS_SetRegANDOR (USHORT Port, USHORT Index, USHORT DataAND, + USHORT DataOR); +extern USHORT SiS_GetResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +extern void SiS_SetCH7005 (USHORT tempax); +extern USHORT SiS_GetCH7005 (USHORT tempax); +extern BOOLEAN SiS_GetLVDSCRT1Ptr (ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + USHORT * ResInfo, USHORT * DisplayType); +extern BOOLEAN SiS_GetLCDACRT1Ptr (ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + USHORT * ResInfo, USHORT * DisplayType); +extern USHORT SiS_GetVCLK2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN SiS_Is301B (USHORT BaseAddr); /*301b */ + +#endif diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c new file mode 100644 index 000000000000..c05c563a736c --- /dev/null +++ b/drivers/video/sis/init301.c @@ -0,0 +1,6001 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.c,v 1.3 2000/12/02 01:16:16 dawes Exp $ */ + +#include "init301.h" +#ifdef CONFIG_FB_SIS_300 +#include "oem300.h" +#endif +#ifdef CONFIG_FB_SIS_315 +#include "oem310.h" +#endif + +BOOLEAN +SiS_SetCRT2Group301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT ModeIdIndex; + USHORT RefreshRateTableIndex; + + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + SiS_SearchModeID (ROMAddr, ModeNo, &ModeIdIndex); + SiS_SelectCRT2Rate = 4; + RefreshRateTableIndex = + SiS_GetRatePtrCRT2 (ROMAddr, ModeNo, ModeIdIndex); + SiS_SaveCRT2Info (ModeNo); + SiS_DisableBridge (HwDeviceExtension, BaseAddr); + SiS_UnLockCRT2 (HwDeviceExtension, BaseAddr); + SiS_SetCRT2ModeRegs (BaseAddr, ModeNo, HwDeviceExtension); + if (SiS_VBInfo & DisableCRT2Display) { + SiS_LockCRT2 (HwDeviceExtension, BaseAddr); + SiS_DisplayOn (); + return (FALSE); + } +/* SetDefCRT2ExtRegs(BaseAddr); */ + SiS_GetCRT2Data (ROMAddr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_GetLVDSDesData (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + } + /*end 301b */ + if (SiS_IF_DEF_LVDS == 1) { + SiS_GetLVDSDesData (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + } + + SiS_SetGroup1 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA) && (SiS_IF_DEF_LVDS == 0)) { + } else if (SiS_IF_DEF_LVDS == 0 && (!(SiS_VBInfo & SetCRT2ToLCDA))) { + SiS_SetGroup2 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + SiS_SetGroup3 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension); + SiS_SetGroup4 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + SiS_SetGroup5 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex); + } else { + if (SiS_IF_DEF_CH7005 == 1) { + SiS_SetCHTVReg (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + } + SiS_ModCRT1CRTC (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + SiS_SetCRT2ECLK (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + } + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730) || + (HwDeviceExtension->jChipType == SIS_300)) + SiS_OEM300Setting (HwDeviceExtension, BaseAddr, ROMAddr, + ModeNo); + +#endif + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || /* 05/02/01 ynlai for sis550 */ + (HwDeviceExtension->jChipType == SIS_315PRO) || + (HwDeviceExtension->jChipType == SIS_550) || /* 05/02/01 ynlai for 550 */ + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { /* 09/03/01 chiawen for 640/740 */ + SiS_OEM310Setting (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo, + ModeIdIndex); + SiS_CRT2AutoThreshold (BaseAddr); + } +#endif + + SiS_EnableBridge (HwDeviceExtension, BaseAddr); + SiS_DisplayOn (); + SiS_LockCRT2 (HwDeviceExtension, BaseAddr); + return 1; +} + +void +SiS_SetGroup1 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT temp = 0, tempax = 0, tempbx = 0, tempcx = 0; + USHORT pushbx = 0, CRT1Index = 0; + USHORT modeflag, resinfo = 0; + + if (ModeNo <= 0x13) { + } else { + CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index = CRT1Index & 0x3F; + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + } else { + SiS_SetCRT2Offset (SiS_Part1Port, ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + if (HwDeviceExtension->jChipType < SIS_315H) /* 300 series */ + SiS_SetCRT2FIFO (SiS_Part1Port, ROMAddr, ModeNo, + HwDeviceExtension); + else /* 310 series */ + SiS_SetCRT2FIFO2 (SiS_Part1Port, ROMAddr, ModeNo, + HwDeviceExtension); + + SiS_SetCRT2Sync (BaseAddr, ROMAddr, ModeNo, + RefreshRateTableIndex); + } + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_SetGroup1_LCDA (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); + } + /*end 301b */ + else if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + temp = (SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg1 (SiS_Part1Port, 0x08, temp); + temp = (((SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR (SiS_Part1Port, 0x09, ~0x0F0, temp); + + temp = (SiS_VGAHDE + 12) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg1 (SiS_Part1Port, 0x0A, temp); + + pushbx = SiS_VGAHDE + 12; /* bx BTVGA@HRS 0x0B,0x0C */ + tempcx = (SiS_VGAHT - SiS_VGAHDE) >> 2; /* cx */ + tempbx = pushbx + tempcx; + tempcx = tempcx << 1; + tempcx = tempcx + tempbx; + + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempbx = SiS_CRT1Table[CRT1Index].CR[4]; + tempbx = + tempbx | + ((SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << + 2); + tempbx = (tempbx - 1) << 3; + tempcx = SiS_CRT1Table[CRT1Index].CR[5]; + tempcx = tempcx & 0x1F; + temp = SiS_CRT1Table[CRT1Index].CR[15]; + temp = (temp & 0x04) << (6 - 2); + tempcx = ((tempcx | temp) - 1) << 3; + } + } + /*add for hardware request */ + if ((SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)) { + if (SiS_VBInfo & SetPALTV) { + tempbx = 1040; + tempcx = 1042; + } else { + tempbx = 1040; + tempcx = 1042; + } + } + + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0B, temp); + + } else { /* 310 series */ + + if (modeflag & HalfDCLK) { /* for low resolution mode */ + temp = (SiS_VGAHT / 2 - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg1 (SiS_Part1Port, 0x08, temp); + temp = (((SiS_VGAHT / 2 - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR (SiS_Part1Port, 0x09, ~0x0F0, temp); + temp = (SiS_VGAHDE / 2 + 16) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg1 (SiS_Part1Port, 0x0A, temp); + + pushbx = SiS_VGAHDE / 2 + 16; + tempcx = ((SiS_VGAHT - SiS_VGAHDE) / 2) >> 2; /* cx */ + tempbx = pushbx + tempcx; /* bx BTVGA@HRS 0x0B,0x0C */ + tempcx = tempcx + tempbx; + + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempbx = SiS_CRT1Table[CRT1Index].CR[4]; + tempbx = + tempbx | + ((SiS_CRT1Table + [CRT1Index].CR[14] & 0xC0) << 2); + tempbx = (tempbx - 3) << 3; /*(VGAHRS-3)*8 */ + tempcx = SiS_CRT1Table[CRT1Index].CR[5]; + tempcx = tempcx & 0x1F; + temp = SiS_CRT1Table[CRT1Index].CR[15]; + temp = (temp & 0x04) << (5 - 2); /*VGAHRE D[5] */ + tempcx = ((tempcx | temp) - 3) << 3; /* (VGAHRE-3)*8 */ + } + } + tempbx += 4; + tempcx += 4; + if (tempcx > (SiS_VGAHT / 2)) + tempcx = SiS_VGAHT / 2; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0B, temp); + + } else { + temp = (SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg1 (SiS_Part1Port, 0x08, temp); + temp = (((SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR (SiS_Part1Port, 0x09, ~0x0F0, temp); + temp = (SiS_VGAHDE + 16) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg1 (SiS_Part1Port, 0x0A, temp); + + pushbx = SiS_VGAHDE + 16; + tempcx = (SiS_VGAHT - SiS_VGAHDE) >> 2; /* cx */ + tempbx = pushbx + tempcx; /* bx BTVGA@HRS 0x0B,0x0C */ + tempcx = tempcx + tempbx; + + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempbx = SiS_CRT1Table[CRT1Index].CR[4]; + tempbx = + tempbx | + ((SiS_CRT1Table + [CRT1Index].CR[14] & 0xC0) << 2); + tempbx = (tempbx - 3) << 3; /*(VGAHRS-3)*8 */ + tempcx = SiS_CRT1Table[CRT1Index].CR[5]; + tempcx = tempcx & 0x1F; + temp = SiS_CRT1Table[CRT1Index].CR[15]; + temp = (temp & 0x04) << (5 - 2); /*VGAHRE D[5] */ + tempcx = ((tempcx | temp) - 3) << 3; /* (VGAHRE-3)*8 */ + tempbx += 16; + tempcx += 16; + + } + } + if (tempcx > SiS_VGAHT) + tempcx = SiS_VGAHT; + /*add for hardware request */ + if ((SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)) { + if (SiS_VBInfo & SetPALTV) { + tempbx = 1040; + tempcx = 1042; + } else { + tempbx = 1040; + tempcx = 1042; + } + } + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0B, temp); + } + + } + + tempax = (tempax & 0x00FF) | (tempbx & 0xFF00); + tempbx = pushbx; + tempbx = (tempbx & 0x00FF) | ((tempbx & 0xFF00) << 4); + tempax = tempax | (tempbx & 0xFF00); + temp = (tempax & 0xFF00) >> 8; + SiS_SetReg1 (SiS_Part1Port, 0x0C, temp); + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0D, temp); + tempcx = (SiS_VGAVT - 1); + temp = tempcx & 0x00FF; + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & 0x0C) { + temp--; + } + } + SiS_SetReg1 (SiS_Part1Port, 0x0E, temp); + tempbx = SiS_VGAVDE - 1; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0F, temp); + temp = ((tempbx & 0xFF00) << 3) >> 8; + temp = temp | ((tempcx & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x12, temp); + + tempax = SiS_VGAVDE; + tempbx = SiS_VGAVDE; + tempcx = SiS_VGAVT; + tempbx = (SiS_VGAVT + SiS_VGAVDE) >> 1; /* BTVGA2VRS 0x10,0x11 */ + tempcx = ((SiS_VGAVT - SiS_VGAVDE) >> 4) + tempbx + 1; /* BTVGA2VRE 0x11 */ + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempbx = SiS_CRT1Table[CRT1Index].CR[8]; + temp = SiS_CRT1Table[CRT1Index].CR[7]; + if (temp & 0x04) + tempbx = tempbx | 0x0100; + if (temp & 0x080) + tempbx = tempbx | 0x0200; + temp = SiS_CRT1Table[CRT1Index].CR[13]; + if (temp & 0x08) + tempbx = tempbx | 0x0400; + temp = SiS_CRT1Table[CRT1Index].CR[9]; + tempcx = (tempcx & 0xFF00) | (temp & 0x00FF); + } + } + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x10, temp); + temp = ((tempbx & 0xFF00) >> 8) << 4; + temp = ((tempcx & 0x000F) | (temp)); + SiS_SetReg1 (SiS_Part1Port, 0x11, temp); + if (SiS_IF_DEF_LVDS == 0) { + temp = 0x20; + if (SiS_LCDResInfo == Panel1280x1024) + temp = 0x20; + if (SiS_LCDResInfo == Panel1280x960) + temp = 0x24; + if (SiS_VBInfo & SetCRT2ToTV) + temp = 0x08; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (SiS_VBInfo & SetInSlaveMode) + temp = 0x2c; + else + temp = 0x20; + } + } else { + temp = 0x20; + } + if (HwDeviceExtension->jChipType < SIS_315H) /* 300 series */ + SiS_SetRegANDOR (SiS_Part1Port, 0x13, ~0x03C, temp); + else { /* 310 series */ + + temp >>= 2; + temp = 0x11; /* ynlai 05/30/2001 for delay compenation */ + SiS_SetReg1 (SiS_Part1Port, 0x2D, temp); + /*SiS_SetRegANDOR(SiS_Part1Port,0x2D,~0x00F,temp); */ + SiS_SetRegAND (SiS_Part1Port, 0x13, 0xEF); /* BDirectLCD=0 for lcd ?? */ + tempax = 0; + + if (modeflag & DoubleScanMode) + tempax |= 0x80; + if (modeflag & HalfDCLK) + tempax |= 0x40; + SiS_SetRegANDOR (SiS_Part1Port, 0x2C, ~0x0C0, tempax); + + } + + if (SiS_IF_DEF_LVDS == 0) { /* 301 */ + SiS_SetGroup1_301 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); + } else { /* LVDS */ + SiS_SetGroup1_LVDS (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); + } +} + +void +SiS_SetGroup1_301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT push1, push2; + USHORT tempax, tempbx, tempcx, temp; + USHORT resinfo, modeflag; + USHORT CRT1Index; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index = CRT1Index & 0x3F; + } + + if (!(SiS_VBInfo & SetInSlaveMode)) { + return; + } + tempax = 0xFFFF; + if (!(SiS_VBInfo & SetCRT2ToTV)) { + tempax = SiS_GetVGAHT2 (); + } + if (modeflag & Charx8Dot) + tempcx = 0x08; + else + tempcx = 0x09; + if (tempax >= SiS_VGAHT) { + tempax = SiS_VGAHT; + } + if (modeflag & HalfDCLK) { + tempax = tempax >> 1; + } + tempax = (tempax / tempcx) - 5; + tempbx = tempax; + temp = 0xFF; /* set MAX HT */ + SiS_SetReg1 (SiS_Part1Port, 0x03, temp); + + tempax = SiS_VGAHDE; /* 0x04 Horizontal Display End */ + if (modeflag & HalfDCLK) + tempax = tempax >> 1; + tempax = (tempax / tempcx) - 1; + tempbx = tempbx | ((tempax & 0x00FF) << 8); + temp = tempax & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x04, temp); + + temp = (tempbx & 0xFF00) >> 8; + if (SiS_VBInfo & SetCRT2ToTV) { + temp = temp + 2; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (resinfo == 7) + temp = temp - 2; + } + } + SiS_SetReg1 (SiS_Part1Port, 0x05, temp); /* 0x05 Horizontal Display Start */ + SiS_SetReg1 (SiS_Part1Port, 0x06, 0x03); /* 0x06 Horizontal Blank end */ + /* 0x07 horizontal Retrace Start */ + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + temp = (tempbx & 0x00FF) - 1; + if (!(modeflag & HalfDCLK)) { + temp = temp - 6; + if (SiS_SetFlag & TVSimuMode) { + temp = temp - 4; + if (ModeNo > 0x13) + temp = temp - 10; + } + } + } else { + tempcx = tempbx & 0x00FF; + tempbx = (tempbx & 0xFF00) >> 8; + tempcx = (tempcx + tempbx) >> 1; + temp = (tempcx & 0x00FF) + 2; + if (SiS_VBInfo & SetCRT2ToTV) { + temp = temp - 1; + if (!(modeflag & HalfDCLK)) { + if ((modeflag & Charx8Dot)) { + temp = temp + 4; + if (SiS_VGAHDE >= 800) { + temp = temp - 6; + } + } + } + } else { + if (!(modeflag & HalfDCLK)) { + temp = temp - 4; + if (SiS_LCDResInfo != Panel1280x960) { + if (SiS_VGAHDE >= 800) { + temp = temp - 7; + if (SiS_ModeType == ModeEGA) { + if (SiS_VGAVDE == 1024) { + temp = + temp + 15; + if + (SiS_LCDResInfo + != + Panel1280x1024) + { + temp = + temp + + 7; + } + } + } + if (SiS_VGAHDE >= 1280) { + if (SiS_LCDResInfo != + Panel1280x960) { + if (SiS_LCDInfo + & + LCDNonExpanding) + { + temp = + temp + + + 28; + } + } + } + } + } + } + } + } + + SiS_SetReg1 (SiS_Part1Port, 0x07, temp); /* 0x07 Horizontal Retrace Start */ + SiS_SetReg1 (SiS_Part1Port, 0x08, 0); /* 0x08 Horizontal Retrace End */ + + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_SetFlag & TVSimuMode) { + if ((ModeNo == 0x06) || (ModeNo == 0x10) + || (ModeNo == 0x11) || (ModeNo == 0x13) + || (ModeNo == 0x0F)) { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x5b); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x03); + } + if ((ModeNo == 0x00) || (ModeNo == 0x01)) { + if (SiS_VBInfo & SetNTSCTV) { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x2A); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x61); + } else { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x2A); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x41); + SiS_SetReg1 (SiS_Part1Port, 0x0C, 0xF0); + } + } + if ((ModeNo == 0x02) || (ModeNo == 0x03) + || (ModeNo == 0x07)) { + if (SiS_VBInfo & SetNTSCTV) { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x54); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x00); + } else { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x55); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x0C, 0xF0); + } + } + if ((ModeNo == 0x04) || (ModeNo == 0x05) + || (ModeNo == 0x0D) || (ModeNo == 0x50)) { + if (SiS_VBInfo & SetNTSCTV) { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x30); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x03); + } else { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x2f); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x02); + } + } + } + } + + SiS_SetReg1 (SiS_Part1Port, 0x18, 0x03); /* 0x18 SR08 */ + SiS_SetRegANDOR (SiS_Part1Port, 0x19, 0xF0, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x09, 0xFF); /* 0x09 Set Max VT */ + + tempbx = SiS_VGAVT; + push1 = tempbx; + tempcx = 0x121; + tempbx = SiS_VGAVDE; /* 0x0E Virtical Display End */ + if (tempbx == 357) + tempbx = 350; + if (tempbx == 360) + tempbx = 350; + if (tempbx == 375) + tempbx = 350; + if (tempbx == 405) + tempbx = 400; + if (tempbx == 420) + tempbx = 400; + if (tempbx == 525) + tempbx = 480; + push2 = tempbx; + if (SiS_VBInfo & SetCRT2ToLCD) { + if (SiS_LCDResInfo == Panel1024x768) { + if (!(SiS_SetFlag & LCDVESATiming)) { + if (tempbx == 350) + tempbx = tempbx + 5; + if (tempbx == 480) + tempbx = tempbx + 5; + } + } + } + tempbx--; + temp = tempbx & 0x00FF; + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x10, temp); /* 0x10 vertical Blank Start */ + tempbx = push2; + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0E, temp); + if (tempbx & 0x0100) { + tempcx = tempcx | 0x0002; + } + tempax = 0x000B; + if (modeflag & DoubleScanMode) { + tempax = tempax | 0x08000; + } + if (tempbx & 0x0200) { + tempcx = tempcx | 0x0040; + } + + temp = (tempax & 0xFF00) >> 8; + SiS_SetReg1 (SiS_Part1Port, 0x0B, temp); + if (tempbx & 0x0400) { + tempcx = tempcx | 0x0600; + } + SiS_SetReg1 (SiS_Part1Port, 0x11, 0x00); /* 0x11 Vertival Blank End */ + + tempax = push1; + tempax = tempax - tempbx; /* 0x0C Vertical Retrace Start */ + tempax = tempax >> 2; + push1 = tempax; /* push ax */ + + if (resinfo != 0x09) { + tempax = tempax << 1; + tempbx = tempax + tempbx; + } + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempbx = tempbx - 10; + } else { + if (SiS_SetFlag & TVSimuMode) { + if (SiS_VBInfo & SetPALTV) { + tempbx = tempbx + 40; + } + } + } + tempax = push1; + tempax = tempax >> 2; + tempax++; + tempax = tempax + tempbx; + push1 = tempax; /* push ax */ + if ((SiS_VBInfo & SetPALTV)) { + if (tempbx <= 513) { + if (tempax >= 513) { + tempbx = 513; + } + } + } + temp = (tempbx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x0C, temp); + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x10, temp); + if (tempbx & 0x0100) { + tempcx = tempcx | 0x0008; + } + if (tempbx & 0x0200) { + SiS_SetRegANDOR (SiS_Part1Port, 0x0B, 0x0FF, 0x20); + } + tempbx++; + if (tempbx & 0x0100) { + tempcx = tempcx | 0x0004; + } + if (tempbx & 0x0200) { + tempcx = tempcx | 0x0080; + } + if (tempbx & 0x0400) { + tempcx = tempcx | 0x0C00; + } + + tempbx = push1; /* pop ax */ + temp = tempbx & 0x00FF; + temp = temp & 0x0F; + SiS_SetReg1 (SiS_Part1Port, 0x0D, temp); /* 0x0D vertical Retrace End */ + if (tempbx & 0x0010) { + tempcx = tempcx | 0x2000; + } + + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0A, temp); /* 0x0A CR07 */ + temp = (tempcx & 0x0FF00) >> 8; + SiS_SetReg1 (SiS_Part1Port, 0x17, temp); /* 0x17 SR0A */ + tempax = modeflag; + temp = (tempax & 0xFF00) >> 8; + + temp = (temp >> 1) & 0x09; + SiS_SetReg1 (SiS_Part1Port, 0x16, temp); /* 0x16 SR01 */ + SiS_SetReg1 (SiS_Part1Port, 0x0F, 0); /* 0x0F CR14 */ + SiS_SetReg1 (SiS_Part1Port, 0x12, 0); /* 0x12 CR17 */ + if (SiS_LCDInfo & LCDRGB18Bit) + temp = 0x80; + else + temp = 0x00; + SiS_SetReg1 (SiS_Part1Port, 0x1A, temp); /* 0x1A SR0E */ + return; +} + +void +SiS_SetGroup1_LVDS (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT modeflag, resinfo; + USHORT push1, push2, tempax, tempbx, tempcx, temp, pushcx; + ULONG tempeax = 0, tempebx, tempecx, tempvcfact = 0; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + tempax = SiS_LCDHDES; + tempbx = SiS_HDE; + tempcx = SiS_HT; + tempcx = tempcx - tempbx; /* HT-HDE */ + if (SiS_LCDInfo & LCDNonExpanding) { + if (SiS_LCDResInfo == Panel800x600) + tempbx = 800; + if (SiS_LCDResInfo == Panel1024x768) + tempbx = 1024; + } + push1 = tempax; + tempax = tempax + tempbx; /* lcdhdee */ + tempbx = SiS_HT; + if (tempax >= tempbx) { + tempax = tempax - tempbx; + } + push2 = tempax; + /* push ax lcdhdee */ + tempcx = tempcx >> 2; /* temp */ + tempcx = tempcx + tempax; /* lcdhrs */ + if (tempcx >= tempbx) { + tempcx = tempcx - tempbx; + } + /* v ah,cl */ + tempax = tempcx; + tempax = tempax >> 3; /* BPLHRS */ + temp = tempax & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x14, temp); /* Part1_14h */ + temp = (tempax & 0x00FF) + 10; + temp = temp & 0x01F; + temp = temp | (((tempcx & 0x00ff) & 0x07) << 5); + SiS_SetReg1 (SiS_Part1Port, 0x15, temp); /* Part1_15h */ + tempbx = push2; /* lcdhdee */ + tempcx = push1; /* lcdhdes */ + temp = (tempcx & 0x00FF); + temp = temp & 0x07; /* BPLHDESKEW */ + SiS_SetReg1 (SiS_Part1Port, 0x1A, temp); /* Part1_1Ah */ + tempcx = tempcx >> 3; /* BPLHDES */ + temp = (tempcx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x16, temp); /* Part1_16h */ + if (tempbx & 0x07) + tempbx = tempbx + 8; + tempbx = tempbx >> 3; /* BPLHDEE */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x17, temp); /* Part1_17h */ + + tempcx = SiS_VGAVT; + tempbx = SiS_VGAVDE; + tempcx = tempcx - tempbx; /* GAVT-VGAVDE */ + tempbx = SiS_LCDVDES; /* VGAVDES */ + push1 = tempbx; /* push bx temppush1 */ + if (SiS_IF_DEF_TRUMPION == 0) { + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + tempax = SiS_VGAVDE; + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + if (SiS_LCDResInfo == Panel800x600) + tempax = 600; + if (SiS_LCDResInfo == Panel1024x768) + tempax = 768; + } + } else + tempax = SiS_VGAVDE; + tempbx = tempbx + tempax; + tempax = SiS_VT; /* VT */ + if (tempbx >= SiS_VT) { + tempbx = tempbx - tempax; + } + push2 = tempbx; /* push bx temppush2 */ + tempcx = tempcx >> 1; + tempbx = tempbx + tempcx; + tempbx++; /* BPLVRS */ + if (tempbx >= tempax) { + tempbx = tempbx - tempax; + } + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x18, temp); /* Part1_18h */ + tempcx = tempcx >> 3; + tempcx = tempcx + tempbx; + tempcx++; /* BPLVRE */ + temp = tempcx & 0x00FF; + temp = temp & 0x0F; + SiS_SetRegANDOR (SiS_Part1Port, 0x19, ~0x00F, temp); /* Part1_19h */ + temp = (tempbx & 0xFF00) >> 8; + temp = temp & 0x07; + temp = temp << 3; /* BPLDESKEW =0 */ + tempbx = SiS_VGAVDE; + if (tempbx != SiS_VDE) { + temp = temp | 0x40; + } + if (SiS_SetFlag & EnableLVDSDDA) { + temp = temp | 0x40; + } + if (SiS_LCDInfo & LCDRGB18Bit) { + temp = temp | 0x80; + } + SiS_SetRegANDOR (SiS_Part1Port, 0x1A, 0x07, temp); /* Part1_1Ah */ + + tempecx = SiS_VGAVT; + tempebx = SiS_VDE; + tempeax = SiS_VGAVDE; + tempecx = tempecx - tempeax; /* VGAVT-VGAVDE */ + tempeax = tempeax << 6; + temp = (USHORT) (tempeax % tempebx); + tempeax = tempeax / tempebx; + if (temp != 0) { + tempeax++; + } + tempebx = tempeax; /* BPLVCFACT */ + if (SiS_SetFlag & EnableLVDSDDA) { + tempebx = tempebx & 0x003F; + } + temp = (USHORT) (tempebx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x1E, temp); /* Part1_1Eh */ + + /*add for 301b different 301 */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + tempecx = SiS_VGAVT; + tempebx = SiS_VDE; + tempeax = SiS_VGAVDE; + tempecx = tempecx - tempeax; /* VGAVT-VGAVDE */ + tempeax = tempeax << 18; + temp = (USHORT) (tempeax % tempebx); + tempeax = tempeax / tempebx; + if (temp != 0) { + tempeax++; + } + tempebx = tempeax; /* BPLVCFACT */ + tempvcfact = tempeax; /*301b */ + temp = (USHORT) (tempebx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x37, temp); + temp = (USHORT) ((tempebx & 0x00FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x36, temp); + temp = (USHORT) ((tempebx & 0x00030000) >> 16); + if (SiS_VDE == SiS_VGAVDE) { + temp = temp | 0x04; + } + + SiS_SetReg1 (SiS_Part1Port, 0x35, temp); + } + /*end for 301b */ + + tempbx = push2; /* p bx temppush2 BPLVDEE */ + tempcx = push1; /* pop cx temppush1 NPLVDES */ + push1 = (USHORT) (tempeax & 0xFFFF); + if (!(SiS_VBInfo & SetInSlaveMode)) { + if (SiS_LCDResInfo == Panel800x600) { + if (resinfo == 7) + tempcx++; + } else { + if (SiS_LCDResInfo == Panel1024x768) { + if (resinfo == 8) + tempcx++; + } + } + } + + temp = (tempbx & 0xFF00) >> 8; + temp = temp & 0x07; + temp = temp << 3; + temp = temp | (((tempcx & 0xFF00) >> 8) & 0x07); + SiS_SetReg1 (SiS_Part1Port, 0x1D, temp); /* Part1_1Dh */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x1C, temp); /* Part1_1Ch */ + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x1B, temp); /* Part1_1Bh */ + + tempecx = SiS_VGAHDE; + tempebx = SiS_HDE; + tempeax = tempecx; + tempeax = tempeax << 6; + tempeax = tempeax << 10; + tempeax = tempeax / tempebx; + if (tempebx == tempecx) { + tempeax = 65535; + } + tempecx = tempeax; + tempeax = SiS_VGAHDE; /*change VGAHT->VGAHDE */ + tempeax = tempeax << 6; + tempeax = tempeax << 10; + tempeax = tempeax / tempecx; + tempecx = tempecx << 16; + tempeax = tempeax - 1; + tempecx = tempecx | (tempeax & 0x00FFFF); + temp = (USHORT) (tempecx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x1F, temp); /* Part1_1Fh */ + + tempeax = SiS_VGAVDE; + tempeax = tempeax << 18; /*301b */ + tempeax = tempeax / tempvcfact; + tempbx = (USHORT) (tempeax & 0x0FFFF); + if (SiS_LCDResInfo == Panel1024x768) + tempbx--; + if (SiS_SetFlag & EnableLVDSDDA) { + tempbx = 1; + } + temp = ((tempbx & 0xFF00) >> 8) << 3; + temp = temp | (USHORT) (((tempecx & 0x0000FF00) >> 8) & 0x07); + SiS_SetReg1 (SiS_Part1Port, 0x20, temp); /* Part1_20h */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x21, temp); /* Part1_21h */ + tempecx = tempecx >> 16; /* BPLHCFACT */ + if (modeflag & HalfDCLK) { + tempecx = tempecx >> 1; + } + temp = (USHORT) ((tempecx & 0x0000FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x22, temp); /* Part1_22h */ + temp = (USHORT) (tempecx & 0x000000FF); + SiS_SetReg1 (SiS_Part1Port, 0x23, temp); + /*add dstn new register */ + if (SiS_IF_DEF_DSTN) { + SiS_SetReg1 (SiS_Part1Port, 0x1E, 0x01); + SiS_SetReg1 (SiS_Part1Port, 0x25, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x26, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x27, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x28, 0x87); + SiS_SetReg1 (SiS_Part1Port, 0x29, 0x5A); + SiS_SetReg1 (SiS_Part1Port, 0x2A, 0x4B); + SiS_SetRegANDOR (SiS_Part1Port, 0x44, ~0x007, 0x03); + tempbx = SiS_HDE; /*Blps=lcdhdee(lcdhdes+HDE) +64 */ + tempbx = tempbx + 64; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x38, temp); + temp = ((tempbx & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR (SiS_Part1Port, 0x35, ~0x078, temp); + tempbx = tempbx + 32; /*Blpe=lBlps+32 */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x39, temp); + SiS_SetReg1 (SiS_Part1Port, 0x3A, 0x00); /*Bflml=0 */ + SiS_SetRegANDOR (SiS_Part1Port, 0x3C, ~0x007, 0x00); + tempbx = SiS_VDE; + tempbx = tempbx / 2; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x3B, temp); + temp = ((tempbx & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR (SiS_Part1Port, 0x3C, ~0x038, temp); + tempeax = SiS_HDE; /* BDxFIFOSTOP= (HDE*4)/128 */ + tempeax = tempeax * 4; + tempebx = 128; + temp = (USHORT) (tempeax % tempebx); + tempeax = tempeax / tempebx; + if (temp != 0) { + tempeax++; + } + temp = (USHORT) (tempeax & 0x0000003F); + SiS_SetRegANDOR (SiS_Part1Port, 0x45, ~0x0FF, temp); + SiS_SetReg1 (SiS_Part1Port, 0x3F, 0x00); /*BDxWadrst0 */ + SiS_SetReg1 (SiS_Part1Port, 0x3E, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x3D, 0x10); + SiS_SetRegANDOR (SiS_Part1Port, 0x3C, ~0x040, 0x00); + tempax = SiS_HDE; + tempax = tempax >> 4; /*BDxWadroff = HDE*4/8/8 */ + pushcx = tempax; + temp = tempax & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x43, temp); + temp = ((tempax & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR (SiS_Part1Port, 0x44, ~0x0F8, temp); + tempax = SiS_VDE; /*BDxWadrst1 = BDxWadrst0+BDxWadroff*VDE */ + tempeax = (tempax * pushcx); + tempebx = 0x00100000 + tempeax; + temp = (USHORT) tempebx & 0x000000FF; + SiS_SetReg1 (SiS_Part1Port, 0x42, temp); + temp = (USHORT) ((tempebx & 0x0000FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x41, temp); + temp = (USHORT) ((tempebx & 0x00FF0000) >> 16); + SiS_SetReg1 (SiS_Part1Port, 0x40, temp); + temp = (USHORT) ((tempebx & 0x01000000) >> 24); + temp = temp << 7; + SiS_SetRegANDOR (SiS_Part1Port, 0x3C, ~0x080, temp); + SiS_SetReg1 (SiS_Part1Port, 0x2F, 0x03); + SiS_SetReg1 (SiS_Part1Port, 0x03, 0x50); + SiS_SetReg1 (SiS_Part1Port, 0x04, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x2F, 0x01); + SiS_SetReg1 (SiS_Part1Port, 0x13, 0x00); + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); + SiS_SetReg1 (SiS_P3c4, 0x1e, 0x62); + SiS_SetReg1 (SiS_Part1Port, 0x19, 0x38); + SiS_SetReg1 (SiS_Part1Port, 0x1e, 0x7d); + } + /*end add dstn */ + + return; +} + +/*301b*/ +void +SiS_SetGroup1_LCDA (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT modeflag, resinfo; + USHORT push1, push2, tempax, tempbx, tempcx, temp; + ULONG tempeax = 0, tempebx, tempecx, tempvcfact; /*301b */ + SiS_SetRegOR (SiS_Part1Port, 0x2D, 0x20); + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + tempax = SiS_LCDHDES; + tempbx = SiS_HDE; + tempcx = SiS_HT; + + if (SiS_LCDInfo & LCDNonExpanding) { + if (SiS_LCDResInfo == Panel1280x1024) + tempbx = 1280; + if (SiS_LCDResInfo == Panel1024x768) + tempbx = 1024; + } + tempcx = tempcx - tempbx; /* HT-HDE */ + push1 = tempax; + tempax = tempax + tempbx; /* lcdhdee */ + tempbx = SiS_HT; + if (tempax >= tempbx) { + tempax = tempax - tempbx; + } + push2 = tempax; + /* push ax lcdhdee */ + tempcx = tempcx >> 2; /* temp */ + tempcx = tempcx + tempax; /* lcdhrs */ + if (tempcx >= tempbx) { + tempcx = tempcx - tempbx; + } + /* v ah,cl */ + tempax = tempcx; + tempax = tempax >> 3; /* BPLHRS */ + temp = tempax & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x14, temp); /* Part1_14h */ + temp = (tempax & 0x00FF) + 10; + temp = temp & 0x01F; + temp = temp | (((tempcx & 0x00ff) & 0x07) << 5); + SiS_SetReg1 (SiS_Part1Port, 0x15, temp); /* Part1_15h */ + tempbx = push2; /* lcdhdee */ + tempcx = push1; /* lcdhdes */ + temp = (tempcx & 0x00FF); + temp = temp & 0x07; /* BPLHDESKEW */ + SiS_SetReg1 (SiS_Part1Port, 0x1A, temp); /* Part1_1Ah */ + tempcx = tempcx >> 3; /* BPLHDES */ + temp = (tempcx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x16, temp); /* Part1_16h */ + if (tempbx & 0x07) + tempbx = tempbx + 8; + tempbx = tempbx >> 3; /* BPLHDEE */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x17, temp); /* Part1_17h */ + + tempcx = SiS_VGAVT; + tempbx = SiS_VGAVDE; + tempcx = tempcx - tempbx; /* GAVT-VGAVDE */ + tempbx = SiS_LCDVDES; /* VGAVDES */ + push1 = tempbx; /* push bx temppush1 */ + if (SiS_IF_DEF_TRUMPION == 0) { + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + tempax = SiS_VGAVDE; + } + } + + if (SiS_LCDResInfo == Panel1024x768) + tempax = 768; + if (SiS_LCDResInfo == Panel1280x1024) + tempax = 1024; + + } else + tempax = SiS_VGAVDE; + tempbx = tempbx + tempax; + tempax = SiS_VT; /* VT */ + if (tempbx >= SiS_VT) { + tempbx = tempbx - tempax; + } + push2 = tempbx; /* push bx temppush2 */ + tempcx = tempcx >> 1; + tempbx = tempbx + tempcx; + tempbx++; /* BPLVRS */ + if (tempbx >= tempax) { + tempbx = tempbx - tempax; + } + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x18, temp); /* Part1_18h */ + tempcx = tempcx >> 3; + tempcx = tempcx + tempbx; + tempcx++; /* BPLVRE */ + temp = tempcx & 0x00FF; + temp = temp & 0x0F; + SiS_SetRegANDOR (SiS_Part1Port, 0x19, ~0x00F, temp); /* Part1_19h */ + temp = (tempbx & 0xFF00) >> 8; + temp = temp & 0x07; + temp = temp << 3; /* BPLDESKEW =0 */ + tempbx = SiS_VGAVDE; + if (tempbx != SiS_VDE) { + temp = temp | 0x40; + } + if (SiS_SetFlag & EnableLVDSDDA) { + temp = temp | 0x40; + } + if (SiS_LCDInfo & LCDRGB18Bit) { + temp = temp | 0x80; + } + SiS_SetRegANDOR (SiS_Part1Port, 0x1A, 0x07, temp); /* Part1_1Ah */ + + tempbx = push2; /* p bx temppush2 BPLVDEE */ + tempcx = push1; /* pop cx temppush1 NPLVDES */ + push1 = (USHORT) (tempeax & 0xFFFF); + + if (!(SiS_VBInfo & SetInSlaveMode)) { + if (SiS_LCDResInfo == Panel800x600) { + if (resinfo == 7) + tempcx++; + } else { + if (SiS_LCDResInfo == Panel1024x768) { + if (resinfo == 8) + tempcx++; + } + } + } + + temp = (tempbx & 0xFF00) >> 8; + temp = temp & 0x07; + temp = temp << 3; + temp = temp | (((tempcx & 0xFF00) >> 8) & 0x07); + SiS_SetReg1 (SiS_Part1Port, 0x1D, temp); /* Part1_1Dh */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x1C, temp); /* Part1_1Ch */ + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x1B, temp); /* Part1_1Bh */ + + tempecx = SiS_VGAVT; + tempebx = SiS_VDE; + tempeax = SiS_VGAVDE; + tempecx = tempecx - tempeax; /* VGAVT-VGAVDE */ + tempeax = tempeax << 18; + temp = (USHORT) (tempeax % tempebx); + tempeax = tempeax / tempebx; + if (temp != 0) { + tempeax++; + } + tempebx = tempeax; /* BPLVCFACT */ + tempvcfact = tempeax; /*301b */ + temp = (USHORT) (tempebx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x37, temp); + temp = (USHORT) ((tempebx & 0x00FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x36, temp); + temp = (USHORT) ((tempebx & 0x00030000) >> 16); + if (SiS_VDE == SiS_VGAVDE) { + temp = temp | 0x04; + } + + SiS_SetReg1 (SiS_Part1Port, 0x35, temp); + + tempecx = SiS_VGAHDE; + tempebx = SiS_HDE; + tempeax = tempecx; + tempeax = tempeax << 6; + tempeax = tempeax << 10; + tempeax = tempeax / tempebx; + if (tempebx == tempecx) { + tempeax = 65535; + } + tempecx = tempeax; + tempeax = SiS_VGAHDE; /*301b to change HT->HDE */ + tempeax = tempeax << 6; + tempeax = tempeax << 10; + tempeax = tempeax / tempecx; + tempecx = tempecx << 16; + tempeax = tempeax - 1; + tempecx = tempecx | (tempeax & 0x00FFFF); + temp = (USHORT) (tempecx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x1F, temp); /* Part1_1Fh */ + + tempeax = SiS_VGAVDE; + tempeax = tempeax << 18; /*301b */ + tempeax = tempeax / tempvcfact; + tempbx = (USHORT) (tempeax & 0x0FFFF); + if (SiS_LCDResInfo == Panel1024x768) + tempbx--; + if (SiS_SetFlag & EnableLVDSDDA) { + tempbx = 1; + } + temp = ((tempbx & 0xFF00) >> 8) << 3; + temp = temp | (USHORT) (((tempecx & 0x0000FF00) >> 8) & 0x07); + SiS_SetReg1 (SiS_Part1Port, 0x20, temp); /* Part1_20h */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x21, temp); /* Part1_21h */ + tempecx = tempecx >> 16; /* BPLHCFACT */ + + temp = (USHORT) ((tempecx & 0x0000FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x22, temp); /* Part1_22h */ + temp = (USHORT) (tempecx & 0x000000FF); + SiS_SetReg1 (SiS_Part1Port, 0x23, temp); + return; +} + +/*end 301b*/ +void +SiS_SetTPData () +{ + return; +} + +void +SiS_SetCRT2Offset (USHORT SiS_Part1Port, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT offset; + UCHAR temp; + + if (SiS_VBInfo & SetInSlaveMode) { + return; + } + offset = + SiS_GetOffset (ROMAddr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + HwDeviceExtension); + temp = (UCHAR) (offset & 0xFF); + SiS_SetReg1 (SiS_Part1Port, 0x07, temp); + temp = (UCHAR) ((offset & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x09, temp); + temp = (UCHAR) (((offset >> 3) & 0xFF) + 1); + SiS_SetReg1 (SiS_Part1Port, 0x03, temp); +} + +USHORT +SiS_GetOffset (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp, colordepth; + USHORT modeinfo, index, infoflag; + USHORT ColorDepth[] = { 0x01, 0x02, 0x04 }; + + modeinfo = SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo; + infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + index = (modeinfo >> 4) & 0xFF; + } else { /* 310 series */ + + index = (modeinfo >> 8) & 0xFF; + } + temp = SiS_ScreenOffset[index]; + if (infoflag & InterlaceMode) { + temp = temp << 1; + } + colordepth = SiS_GetColorDepth (ROMAddr, ModeNo, ModeIdIndex); + + if ((ModeNo >= 0x7C) && (ModeNo <= 0x7E)) { + temp = ModeNo - 0x7C; + colordepth = ColorDepth[temp]; + temp = 0x6B; + if (infoflag & InterlaceMode) { + temp = temp << 1; + } + return (temp * colordepth); + } else + return (temp * colordepth); +} + +USHORT +SiS_GetColorDepth (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; + SHORT index; + USHORT modeflag; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + index = (modeflag & ModeInfoFlag) - ModeEGA; + if (index < 0) + index = 0; + return (ColorDepth[index]); +} + +void +SiS_SetCRT2Sync (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT RefreshRateTableIndex) +{ + USHORT tempah = 0, infoflag, flag; + + flag = 0; + infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + if (SiS_IF_DEF_LVDS == 1) { + if (SiS_VBInfo & SetCRT2ToLCD) { + tempah = SiS_LCDInfo; + if (tempah & LCDSync) { + flag = 1; + } + } + } + if (flag != 1) + tempah = infoflag >> 8; + tempah = tempah & 0xC0; + tempah = tempah | 0x20; + if (!(SiS_LCDInfo & LCDRGB18Bit)) + tempah = tempah | 0x10; + if (SiS_IF_DEF_CH7005 == 1) + tempah = tempah | 0xC0; + + SiS_SetRegANDOR (SiS_Part1Port, 0x19, 0x3F, tempah); +} + +void +SiS_SetCRT2FIFO (USHORT SiS_Part1Port, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp, index; + USHORT modeidindex, refreshratetableindex; + USHORT VCLK, MCLK, colorth = 0, data, data2; + ULONG eax; + UCHAR LatencyFactor[] = { 97, 88, 86, 79, 77, 00, /*; 64 bit BQ=2 */ + 00, 87, 85, 78, 76, 54, /*; 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 00, /*; 128 bit BQ=2 */ + 00, 79, 77, 70, 68, 48, /*; 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 00, /*; 64 bit BQ=2 */ + 00, 70, 68, 61, 59, 37, /*; 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 00, /*; 128 bit BQ=2 */ + 00, 68, 66, 59, 57, 37 + }; /*; 128 bit BQ=1 */ + + SiS_SearchModeID (ROMAddr, ModeNo, &modeidindex); + SiS_SetFlag = SiS_SetFlag & (~ProgrammingCRT2); + SiS_SelectCRT2Rate = 0; + refreshratetableindex = SiS_GetRatePtrCRT2 (ROMAddr, ModeNo, modeidindex); /* 11.GetRatePtr */ + if (ModeNo >= 0x13) { + index = SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK; + index = index & 0x3F; + VCLK = SiS_VCLKData[index].CLOCK; /* Get VCLK */ + index = SiS_GetReg1 (SiS_P3c4, 0x1A); + index = index & 07; + MCLK = SiS_MCLKData[index].CLOCK; /* Get MCLK */ + data2 = SiS_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; + } + data2 = (data2 * VCLK) / MCLK; /* bx */ + + temp = SiS_GetReg1 (SiS_P3c4, 0x14); + temp = ((temp & 0x00FF) >> 6) << 1; + if (temp == 0) + temp = 1; + temp = temp << 2; + + data2 = temp - data2; + if (data2 % (28 * 16)) { + data2 = data2 / (28 * 16); + data2++; + } else { + data2 = data2 / (28 * 16); + } + + index = 0; + temp = SiS_GetReg1 (SiS_P3c4, 0x14); + if (temp & 0x0080) + index = index + 12; + SiS_SetReg4 (0xcf8, 0x800000A0); + eax = SiS_GetReg3 (0xcfc); + temp = (USHORT) (eax >> 24); + if (!(temp & 0x01)) + index = index + 24; + + SiS_SetReg4 (0xcf8, 0x80000050); + eax = SiS_GetReg3 (0xcfc); + temp = (USHORT) (eax >> 24); + if (temp & 0x01) + index = index + 6; + temp = (temp & 0x0F) >> 1; + index = index + temp; + data = LatencyFactor[index]; + data = data + 15; + temp = SiS_GetReg1 (SiS_P3c4, 0x14); + if (!(temp & 0x80)) + data = data + 5; + data = data + data2; + + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + data = data * VCLK * colorth; + if (data % (MCLK << 4)) { + data = data / (MCLK << 4); + data++; + } else { + data = data / (MCLK << 4); + } + temp = 0x16; +/* Revision ID */ + temp = 0x13; +/* Revision ID */ + SiS_SetRegANDOR (SiS_Part1Port, 0x01, ~0x01F, temp); + SiS_SetRegANDOR (SiS_Part1Port, 0x02, ~0x01F, temp); + } +} + +void +SiS_SetCRT2FIFO2 (USHORT SiS_Part1Port, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ +#ifdef CONFIG_FB_SIS_315 + UCHAR CombCode[] = { 1, 1, 1, 4, 3, 1, 3, 4, 4, 1, 4, 4, 5, 1, 5, 4 }; + UCHAR CRT2ThLow[] = + { 39, 63, 55, 79, 78, 102, 90, 114, 55, 87, 84, 116, 103, 135, 119, + 151 }; +#endif + USHORT temp, temp1, temp2, temp3; + USHORT index; + USHORT CRT1ModeNo, CRT2ModeNo; + USHORT ModeIdIndex; + USHORT RefreshRateTableIndex; + + SiS_SetReg1 (SiS_Part1Port, 0x1, 0x3B); +/* CRT1ModeNo=(UCHAR)SiS_GetReg1(SiS_P3d4,0x34); *//* get CRT1 ModeNo */ + CRT1ModeNo = SiS_CRT1Mode; + /* CRT1ModeNo =ModeNo; */ + SiS_SearchModeID (ROMAddr, CRT1ModeNo, &ModeIdIndex); /* Get ModeID Table */ + SiS_SetFlag = SiS_SetFlag & (~ProgrammingCRT2); + + RefreshRateTableIndex = SiS_GetRatePtrCRT2 (ROMAddr, CRT1ModeNo, ModeIdIndex); /* Set REFIndex-> for crt1 refreshrate */ + index = + SiS_GetVCLK2Ptr (ROMAddr, CRT1ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + temp1 = SiS_VCLKData[index].CLOCK; /* Get VCLK */ + + temp2 = SiS_GetColorDepth (ROMAddr, CRT1ModeNo, ModeIdIndex); +#ifdef CONFIG_FB_SIS_315 + index = SiS_Get310DRAMType (ROMAddr); +#endif + temp3 = SiS_MCLKData[index].CLOCK; /* Get MCLK */ + + temp = SiS_GetReg1 (SiS_P3c4, 0x14); + if (temp & 0x02) + temp = 16; + else + temp = 8; + + temp = temp - temp1 * temp2 / temp3; /* 16-DRamBus - DCLK*BytePerPixel/MCLK */ + + if ((52 * 16 % temp) == 0) + temp = 52 * 16 / temp + 40; + else + temp = 52 * 16 / temp + 40 + 1; + + /* get DRAM latency */ + temp1 = (SiS_GetReg1 (SiS_P3c4, 0x17) >> 3) & 0x7; /* SR17[5:3] DRAM Queue depth */ + temp2 = (SiS_GetReg1 (SiS_P3c4, 0x17) >> 6) & 0x3; /* SR17[7:6] DRAM Grant length */ + +#ifdef CONFIG_FB_SIS_315 + if (SiS_Get310DRAMType (ROMAddr) < 2) { + for (temp3 = 0; temp3 < 16; temp3 += 2) { + if ((CombCode[temp3] == temp1) + && (CombCode[temp3 + 1] == temp2)) { + temp3 = CRT2ThLow[temp3 >> 1]; + } + } + } else { + for (temp3 = 0; temp3 < 16; temp3 += 2) { + if ((CombCode[temp3] == temp1) + && (CombCode[temp3 + 1] == temp2)) { + temp3 = CRT2ThLow[8 + (temp3 >> 1)]; + } + } + } +#endif + + temp += temp3; /* CRT1 Request Period */ + + CRT2ModeNo = ModeNo; /* get CRT2 ModeNo */ + SiS_SearchModeID (ROMAddr, CRT2ModeNo, &ModeIdIndex); /* Get ModeID Table */ + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + RefreshRateTableIndex = SiS_GetRatePtrCRT2 (ROMAddr, CRT1ModeNo, ModeIdIndex); /* Set REFIndex-> for crt1 refreshrate */ + index = + SiS_GetVCLK2Ptr (ROMAddr, CRT2ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + temp1 = SiS_VCLKData[index].CLOCK; /* Get VCLK */ + + temp2 = SiS_GetColorDepth (ROMAddr, CRT2ModeNo, ModeIdIndex); +#ifdef CONFIG_FB_SIS_315 + index = SiS_Get310DRAMType (ROMAddr); +#endif + temp3 = SiS_MCLKData[index].CLOCK; /* Get MCLK */ + + if ((temp * temp1 * temp2) % (16 * temp3) == 0) + temp = temp * temp1 * temp2 / (16 * temp3); /* CRT1 Request period * TCLK*BytePerPixel/(MCLK*16) */ + else + temp = temp * temp1 * temp2 / (16 * temp3) + 1; /* CRT1 Request period * TCLK*BytePerPixel/(MCLK*16) */ + + if (temp > 0x37) + temp = 0x37; + + SiS_SetRegANDOR (SiS_Part1Port, 0x02, ~0x3F, temp); + +} + +void +SiS_GetLVDSDesData (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + + USHORT modeflag; + USHORT PanelIndex, ResIndex; + SiS_LVDSDesStruct *PanelDesPtr = NULL; + if ((SiS_IF_DEF_LVDS == 0) + && ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { /*301b *//*for test */ + SiS_GetLVDSDesPtrA (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &PanelIndex, + &ResIndex); + switch (PanelIndex) { + case 0: + PanelDesPtr = LVDS1024x768Des_1; + break; + case 1: + PanelDesPtr = LVDS1280x1024Des_1; + break; + case 2: + PanelDesPtr = LVDS1280x960Des_1; + break; + case 3: + PanelDesPtr = LVDS1024x768Des_2; + break; + case 4: + PanelDesPtr = LVDS1280x1024Des_2; + break; + case 5: + PanelDesPtr = LVDS1280x960Des_2; + break; + } + } else { + SiS_GetLVDSDesPtr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &PanelIndex, + &ResIndex); + switch (PanelIndex) { + case 0: + PanelDesPtr = SiS_PanelType00_1; + break; + case 1: + PanelDesPtr = SiS_PanelType01_1; + break; + case 2: + PanelDesPtr = SiS_PanelType02_1; + break; + case 3: + PanelDesPtr = SiS_PanelType03_1; + break; + case 4: + PanelDesPtr = SiS_PanelType04_1; + break; + case 5: + PanelDesPtr = SiS_PanelType05_1; + break; + case 6: + PanelDesPtr = SiS_PanelType06_1; + break; + case 7: + PanelDesPtr = SiS_PanelType07_1; + break; + case 8: + PanelDesPtr = SiS_PanelType08_1; + break; + case 9: + PanelDesPtr = SiS_PanelType09_1; + break; + case 10: + PanelDesPtr = SiS_PanelType0a_1; + break; + case 11: + PanelDesPtr = SiS_PanelType0b_1; + break; + case 12: + PanelDesPtr = SiS_PanelType0c_1; + break; + case 13: + PanelDesPtr = SiS_PanelType0d_1; + break; + case 14: + PanelDesPtr = SiS_PanelType0e_1; + break; + case 15: + PanelDesPtr = SiS_PanelType0f_1; + break; + case 16: + PanelDesPtr = SiS_PanelType00_2; + break; + case 17: + PanelDesPtr = SiS_PanelType01_2; + break; + case 18: + PanelDesPtr = SiS_PanelType02_2; + break; + case 19: + PanelDesPtr = SiS_PanelType03_2; + break; + case 20: + PanelDesPtr = SiS_PanelType04_2; + break; + case 21: + PanelDesPtr = SiS_PanelType05_2; + break; + case 22: + PanelDesPtr = SiS_PanelType06_2; + break; + case 23: + PanelDesPtr = SiS_PanelType07_2; + break; + case 24: + PanelDesPtr = SiS_PanelType08_2; + break; + case 25: + PanelDesPtr = SiS_PanelType09_2; + break; + case 26: + PanelDesPtr = SiS_PanelType0a_2; + break; + case 27: + PanelDesPtr = SiS_PanelType0b_2; + break; + case 28: + PanelDesPtr = SiS_PanelType0c_2; + break; + case 29: + PanelDesPtr = SiS_PanelType0d_2; + break; + case 30: + PanelDesPtr = SiS_PanelType0e_2; + break; + case 31: + PanelDesPtr = SiS_PanelType0f_2; + break; + case 32: + PanelDesPtr = SiS_CHTVUNTSCDesData; + break; + case 33: + PanelDesPtr = SiS_CHTVONTSCDesData; + break; + case 34: + PanelDesPtr = SiS_CHTVUPALDesData; + break; + case 35: + PanelDesPtr = SiS_CHTVOPALDesData; + break; + } + } + SiS_LCDHDES = (PanelDesPtr + ResIndex)->LCDHDES; + SiS_LCDVDES = (PanelDesPtr + ResIndex)->LCDVDES; + if (SiS_LCDInfo & LCDNonExpanding) { + if (SiS_LCDResInfo >= Panel1024x768) { + if (ModeNo <= 0x13) { + modeflag = + SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + if (!(modeflag & HalfDCLK)) { + SiS_LCDHDES = 320; + } + } + } + } + return; + +} + +void +SiS_GetLVDSDesPtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * PanelIndex, + USHORT * ResIndex) +{ + USHORT tempbx, tempal; + + tempbx = 0; + if (SiS_IF_DEF_CH7005 == 1) { + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + tempbx = 32; + if (SiS_VBInfo & SetPALTV) + tempbx = tempbx + 2; + if (SiS_VBInfo & SetCHTVOverScan) + tempbx = tempbx + 1; + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + tempbx = SiS_LCDTypeInfo; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx + 16; + } + } + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x1F; + *PanelIndex = tempbx; + *ResIndex = tempal; +} + +/*301b*/ +void +SiS_GetLVDSDesPtrA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * PanelIndex, + USHORT * ResIndex) +{ + USHORT tempbx, tempal; + + tempbx = 0; + tempbx = SiS_LCDResInfo; + tempbx = tempbx - Panel1024x768; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx + 3; + } + + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x1F; + *PanelIndex = tempbx; + *ResIndex = tempal; +} + +/*end 301b*/ + +void +SiS_SetCRT2ModeRegs (USHORT BaseAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT i, j; + USHORT tempcl, tempah; +/*301b*/ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_SetRegANDOR (SiS_Part1Port, 0x00, ~0x050, 0x40); + SiS_SetRegAND (SiS_Part1Port, 0x2E, 0xF7); + SiS_SetRegANDOR (SiS_Part1Port, 0x13, 0xFB, 0x04); + SiS_SetRegANDOR (SiS_Part1Port, 0x2c, 0xCF, 0x30); + SiS_SetRegANDOR (SiS_Part4Port, 0x21, 0x3F, 0xC0); + SiS_SetRegANDOR (SiS_Part4Port, 0x23, 0x7F, 0x00); + } + /*end 301b */ + else { + for (i = 0, j = 4; i < 3; i++, j++) + SiS_SetReg1 (SiS_Part1Port, j, 0); + + tempcl = SiS_ModeType; + if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + if (ModeNo > 0x13) { + tempcl = tempcl - ModeVGA; + if ((tempcl > 0) || (tempcl == 0)) { + tempah = ((0x010 >> tempcl) | 0x080); + } + } else { + tempah = 0x080; + } + if (SiS_VBInfo & SetInSlaveMode) { + tempah = (tempah ^ 0x0A0); + } + } else { /* 310 series */ + + if (ModeNo > 0x13) { + tempcl = tempcl - ModeVGA; + if ((tempcl > 0) || (tempcl == 0)) { + tempah = (0x008 >> tempcl); + if (tempah == 0) + tempah = 1; + tempah |= 0x040; + } + } else { + tempah = 0x040; + } + + if (SiS_VBInfo & SetInSlaveMode) { + tempah = (tempah ^ 0x050); + } + + } + + if (SiS_VBInfo & CRT2DisplayFlag) { + tempah = 0; + } + SiS_SetReg1 (SiS_Part1Port, 0x00, tempah); + + if (SiS_IF_DEF_LVDS == 0) { /* ifdef 301 */ + tempah = 0x01; + if (!(SiS_VBInfo & SetInSlaveMode)) { + tempah = (tempah | 0x02); + } + if (!(SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah = (tempah ^ 0x05); + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + tempah = (tempah ^ 0x01); + } + } + + tempcl = tempah; /* 05/03/01 ynlai for TV display bug */ + + if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + tempah = (tempah << 5) & 0xFF; + if (SiS_VBInfo & CRT2DisplayFlag) { + tempah = 0; + } + SiS_SetReg1 (SiS_Part1Port, 0x01, tempah); + + tempah = tempah >> 5; + } else { /* 310 series */ + + if (SiS_VBInfo & CRT2DisplayFlag) { + tempah = 0; + } + tempah = + (SiS_GetReg1 (SiS_Part1Port, 0x2E) & 0xF8) | + tempah; + SiS_SetReg1 (SiS_Part1Port, 0x2E, tempah); + tempah = tempcl; + } + + if ((SiS_ModeType == ModeVGA) + && (!(SiS_VBInfo & SetInSlaveMode))) { + tempah = tempah | 0x010; + } + + if (SiS_LCDResInfo == Panel1024x768) + tempah = tempah | 0x080; + + if ((SiS_LCDResInfo == Panel1280x1024) + || (SiS_LCDResInfo == Panel1280x960)) { + tempah = tempah | 0x080; + } + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if ( + ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B))) { /*301b */ + if (SiS_SetFlag & TVSimuMode) + tempah = tempah | 0x020; + } else + tempah = tempah | 0x020; + } + } + SiS_SetRegANDOR (SiS_Part4Port, 0x0D, ~0x0BF, tempah); + tempah = 0; + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if ( + ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B))) { /*301b */ + { + SiS_SetFlag = + SiS_SetFlag | + RPLLDIV2XO; + tempah = tempah | 0x40; + } + } else { + if (!(SiS_SetFlag & TVSimuMode)) { + if (! + (SiS_VBInfo & + SetCRT2ToHiVisionTV)) + { + SiS_SetFlag = + SiS_SetFlag + | + RPLLDIV2XO; + tempah = + tempah | + 0x40; + } + } + } + } else { + SiS_SetFlag = SiS_SetFlag | RPLLDIV2XO; + tempah = tempah | 0x40; + } + } + if (SiS_LCDResInfo == Panel1280x1024) + tempah = tempah | 0x80; + if (SiS_LCDResInfo == Panel1280x960) + tempah = tempah | 0x80; + SiS_SetReg1 (SiS_Part4Port, 0x0C, tempah); + } else { + /*LVDS*/ tempah = 0; + if (!(SiS_VBInfo & SetInSlaveMode)) { + tempah = tempah | 0x02; + } + SiS_SetRegANDOR (SiS_Part1Port, 0x2e, 0xF0, tempah); + } + } +/*301b*/ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (!(SiS_VBInfo & SetCRT2ToLCDA))) { + if (SiS_IsDualEdge (BaseAddr)) + SiS_SetRegANDOR (SiS_Part1Port, 0x13, 0xFB, 0x00); + else + SiS_SetRegANDOR (SiS_Part1Port, 0x13, 0xFF, 0x00); + if (SiS_IsDualEdge (BaseAddr)) + SiS_SetRegANDOR (SiS_Part1Port, 0x2c, 0xCF, 0x00); + else + SiS_SetRegANDOR (SiS_Part1Port, 0x2c, 0xFF, 0x00); + if (SiS_IsDualEdge (BaseAddr)) + SiS_SetRegANDOR (SiS_Part4Port, 0x21, 0x3F, 0x00); + else + SiS_SetRegANDOR (SiS_Part4Port, 0x21, 0xFF, 0x00); + + if (SiS_IsDualEdge (BaseAddr)) + SiS_SetRegANDOR (SiS_Part4Port, 0x23, 0xFF, 0x80); + else + SiS_SetRegANDOR (SiS_Part4Port, 0x23, 0xFF, 0x00); + } + +/*end 301b*/ +} +void +SiS_GetCRT2Data (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + if (SiS_IF_DEF_LVDS == 0) { /*301 */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) + SiS_GetCRT2DataLVDS (ROMAddr, ModeNo, + ModeIdIndex, + RefreshRateTableIndex); + else + SiS_GetCRT2Data301 (ROMAddr, ModeNo, + ModeIdIndex, + RefreshRateTableIndex); + } else + SiS_GetCRT2Data301 (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + return; + } else { /*LVDS */ + SiS_GetCRT2DataLVDS (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + return; + } +} + +void +SiS_GetCRT2DataLVDS (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT tempax, tempbx; + USHORT CRT2Index, ResIndex; + SiS_LVDSDataStruct *LVDSData = NULL; + + SiS_GetCRT2ResInfo (ROMAddr, ModeNo, ModeIdIndex); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_GetCRT2PtrA (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &CRT2Index, &ResIndex); + switch (CRT2Index) { + case 0: + LVDSData = SiS_LVDS1024x768Data_1; + break; + case 1: + LVDSData = SiS_LVDS1280x1024Data_1; + break; + case 2: + LVDSData = SiS_LVDS1280x1024Data_1; + break; + /* case 2: LVDSData=SiS_LVDS1280x960Data_1; break; */ + case 3: + LVDSData = SiS_LVDS1024x768Data_2; + break; + case 4: + LVDSData = SiS_LVDS1280x1024Data_2; + break; + case 5: + LVDSData = SiS_LVDS1280x1024Data_2; + break; + /* case 5: LVDSData=SiS_LVDS1280x960Data_2; break; */ + } + } + + else { + SiS_GetCRT2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &CRT2Index, &ResIndex); + switch (CRT2Index) { + case 0: + LVDSData = SiS_LVDS800x600Data_1; + break; + case 1: + LVDSData = SiS_LVDS1024x768Data_1; + break; + case 2: + LVDSData = SiS_LVDS1280x1024Data_1; + break; + case 3: + LVDSData = SiS_LVDS800x600Data_2; + break; + case 4: + LVDSData = SiS_LVDS1024x768Data_2; + break; + case 5: + LVDSData = SiS_LVDS1280x1024Data_2; + break; + case 6: + LVDSData = SiS_LVDS640x480Data_1; + break; + case 7: + LVDSData = SiS_CHTVUNTSCData; + break; + case 8: + LVDSData = SiS_CHTVONTSCData; + break; + case 9: + LVDSData = SiS_CHTVUPALData; + break; + case 10: + LVDSData = SiS_CHTVOPALData; + break; + } + } + SiS_VGAHT = (LVDSData + ResIndex)->VGAHT; + SiS_VGAVT = (LVDSData + ResIndex)->VGAVT; + SiS_HT = (LVDSData + ResIndex)->LCDHT; + SiS_VT = (LVDSData + ResIndex)->LCDVT; +/*301b*/ + if ((SiS_IF_DEF_LVDS == 0) + && ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { /*for test */ + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (SiS_LCDResInfo == Panel1024x768) { + tempax = 1024; + tempbx = 768; + } else { + tempax = 1280; + tempbx = 1024; + } + SiS_HDE = tempax; + SiS_VDE = tempbx; + } + } else { + if (SiS_IF_DEF_TRUMPION == 0) { + if (SiS_VBInfo & SetCRT2ToLCD) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (SiS_LCDResInfo == Panel800x600) { + tempax = 800; + tempbx = 600; + } else if (SiS_LCDResInfo == + Panel1024x768) { + tempax = 1024; + tempbx = 768; + } else { + tempax = 1280; + tempbx = 1024; + } + SiS_HDE = tempax; + SiS_VDE = tempbx; + } + } + } + } + return; +} + +void +SiS_GetCRT2Data301 (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT tempax, tempbx, modeflag; + USHORT resinfo; + USHORT CRT2Index, ResIndex; + SiS_LCDDataStruct *LCDPtr = NULL; + SiS_TVDataStruct *TVPtr = NULL; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + SiS_NewFlickerMode = 0; + SiS_RVBHRS = 50; + SiS_RY1COE = 0; + SiS_RY2COE = 0; + SiS_RY3COE = 0; + SiS_RY4COE = 0; + + SiS_GetCRT2ResInfo (ROMAddr, ModeNo, ModeIdIndex); + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + SiS_GetRAMDAC2DATA (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + return; + } + + if (SiS_VBInfo & SetCRT2ToTV) { + SiS_GetCRT2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &CRT2Index, &ResIndex); + switch (CRT2Index) { + case 2: + TVPtr = SiS_ExtHiTVData; + break; + case 3: + TVPtr = SiS_ExtPALData; + break; + case 4: + TVPtr = SiS_ExtNTSCData; + break; + case 7: + TVPtr = SiS_St1HiTVData; + break; + case 8: + TVPtr = SiS_StPALData; + break; + case 9: + TVPtr = SiS_StNTSCData; + break; + case 12: + TVPtr = SiS_St2HiTVData; + break; + } + + SiS_RVBHCMAX = (TVPtr + ResIndex)->RVBHCMAX; + SiS_RVBHCFACT = (TVPtr + ResIndex)->RVBHCFACT; + SiS_VGAHT = (TVPtr + ResIndex)->VGAHT; + SiS_VGAVT = (TVPtr + ResIndex)->VGAVT; + SiS_HDE = (TVPtr + ResIndex)->TVHDE; + SiS_VDE = (TVPtr + ResIndex)->TVVDE; + SiS_RVBHRS = (TVPtr + ResIndex)->RVBHRS; + SiS_NewFlickerMode = (TVPtr + ResIndex)->FlickerMode; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (resinfo == 0x08) + SiS_NewFlickerMode = 0x40; + if (resinfo == 0x09) + SiS_NewFlickerMode = 0x40; + if (resinfo == 0x10) + SiS_NewFlickerMode = 0x40; + } + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (SiS_VGAVDE == 350) + SiS_SetFlag = SiS_SetFlag | TVSimuMode; + tempax = ExtHiTVHT; + tempbx = ExtHiTVVT; + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_SetFlag & TVSimuMode) { + tempax = StHiTVHT; + tempbx = StHiTVVT; + if (!(modeflag & Charx8Dot)) { + tempax = StHiTextTVHT; + tempbx = StHiTextTVVT; + } + } + } + } + if (!(SiS_VBInfo & SetCRT2ToHiVisionTV)) { + SiS_RY1COE = (TVPtr + ResIndex)->RY1COE; + SiS_RY2COE = (TVPtr + ResIndex)->RY2COE; + if (modeflag & HalfDCLK) { + SiS_RY1COE = 0x00; + SiS_RY2COE = 0xf4; + } + SiS_RY3COE = (TVPtr + ResIndex)->RY3COE; + SiS_RY4COE = (TVPtr + ResIndex)->RY4COE; + if (modeflag & HalfDCLK) { + SiS_RY3COE = 0x10; + SiS_RY4COE = 0x38; + } + if (!(SiS_VBInfo & SetPALTV)) { + tempax = NTSCHT; + tempbx = NTSCVT; + } else { + tempax = PALHT; + tempbx = PALVT; + } + } + SiS_HT = tempax; + SiS_VT = tempbx; + return; + } + + if (SiS_VBInfo & SetCRT2ToLCD) { + SiS_GetCRT2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &CRT2Index, &ResIndex); + switch (CRT2Index) { + case 0: + LCDPtr = SiS_ExtLCD1024x768Data; + break; + case 1: + LCDPtr = SiS_ExtLCD1280x1024Data; + break; + case 5: + LCDPtr = SiS_StLCD1024x768Data; + break; + case 6: + LCDPtr = SiS_StLCD1280x1024Data; + break; + case 10: + LCDPtr = SiS_St2LCD1024x768Data; + break; + case 11: + LCDPtr = SiS_St2LCD1280x1024Data; + break; + case 13: + LCDPtr = SiS_NoScaleData; + break; + case 14: + LCDPtr = SiS_LCD1280x960Data; + break; + } + + SiS_RVBHCMAX = (LCDPtr + ResIndex)->RVBHCMAX; + SiS_RVBHCFACT = (LCDPtr + ResIndex)->RVBHCFACT; + SiS_VGAHT = (LCDPtr + ResIndex)->VGAHT; + SiS_VGAVT = (LCDPtr + ResIndex)->VGAVT; + SiS_HT = (LCDPtr + ResIndex)->LCDHT; + SiS_VT = (LCDPtr + ResIndex)->LCDVT; + tempax = 1024; + if (SiS_SetFlag & LCDVESATiming) { + if (SiS_VGAVDE == 350) + tempbx = 560; + else if (SiS_VGAVDE == 400) + tempbx = 640; + else + tempbx = 768; + } else { + if (SiS_VGAVDE == 357) + tempbx = 527; + else if (SiS_VGAVDE == 420) + tempbx = 620; + else if (SiS_VGAVDE == 525) + tempbx = 775; + else if (SiS_VGAVDE == 600) + tempbx = 775; + else if (SiS_VGAVDE == 350) + tempbx = 560; + else if (SiS_VGAVDE == 400) + tempbx = 640; + else + tempbx = 768; + } + if (SiS_LCDResInfo == Panel1280x1024) { + tempax = 1280; + if (SiS_VGAVDE == 360) + tempbx = 768; + else if (SiS_VGAVDE == 375) + tempbx = 800; + else if (SiS_VGAVDE == 405) + tempbx = 864; + else + tempbx = 1024; + } + if (SiS_LCDResInfo == Panel1280x960) { + tempax = 1280; + if (SiS_VGAVDE == 350) + tempbx = 700; + else if (SiS_VGAVDE == 400) + tempbx = 800; + else if (SiS_VGAVDE == 1024) + tempbx = 960; + else + tempbx = 960; + } + if (SiS_LCDInfo & LCDNonExpanding) { + tempax = SiS_VGAHDE; + tempbx = SiS_VGAVDE; + } + SiS_HDE = tempax; + SiS_VDE = tempbx; + return; + } +} + +USHORT +SiS_GetResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT resindex; + + if (ModeNo <= 0x13) { + resindex = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; /* si+St_ResInfo */ + } else { + resindex = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; /* si+Ext_ResInfo */ + } + return (resindex); +} + +void +SiS_GetCRT2ResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT xres, yres, modeflag, resindex; + + resindex = SiS_GetResInfo (ROMAddr, ModeNo, ModeIdIndex); + if (ModeNo <= 0x13) { + xres = SiS_StResInfo[resindex].HTotal; + yres = SiS_StResInfo[resindex].VTotal; + } else { + xres = SiS_ModeResInfo[resindex].HTotal; /* xres->ax */ + yres = SiS_ModeResInfo[resindex].VTotal; /* yres->bx */ + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+St_ModeFlag */ + if (modeflag & HalfDCLK) { + xres = xres * 2; + } + if (modeflag & DoubleScanMode) { + yres = yres * 2; + } + } + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_LCDResInfo == Panel1280x1024) { + if (yres == 400) + yres = 405; + if (yres == 350) + yres = 360; + if (SiS_SetFlag & LCDVESATiming) { + if (yres == 360) + yres = 375; + } + } + if (SiS_LCDResInfo == Panel1024x768) { + if (!(SiS_SetFlag & LCDVESATiming)) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (yres == 350) + yres = 357; + if (yres == 400) + yres = 420; +/* if(!OldBios) */ + if (yres == 480) + yres = 525; + } + } + } + } else { + if (xres == 720) + xres = 640; + } + SiS_VGAHDE = xres; + SiS_HDE = xres; + SiS_VGAVDE = yres; + SiS_VDE = yres; +} + +void +SiS_GetCRT2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * CRT2Index, + USHORT * ResIndex) +{ + USHORT tempbx, tempal; + USHORT Flag; + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToLCD) { /* LCD */ + tempbx = SiS_LCDResInfo; + tempbx = tempbx - Panel1024x768; + if (!(SiS_SetFlag & LCDVESATiming)) { + tempbx += 5; +/* GetRevisionID(); */ + tempbx += 5; + } + } else { + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { /* TV */ + if (SiS_VGAVDE > 480) + SiS_SetFlag = + SiS_SetFlag & (!TVSimuMode); + tempbx = 2; + if (SiS_VBInfo & SetInSlaveMode) { + if (!(SiS_SetFlag & TVSimuMode)) + tempbx = 10; + } + } else { + if (SiS_VBInfo & SetPALTV) { + tempbx = 3; + } else { + tempbx = 4; + } + if (SiS_SetFlag & TVSimuMode) { + tempbx = tempbx + 5; + } + } + } + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x3F; + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToTV)) { + /*look */ + if (tempal == 0x06) + tempal = 0x07; + + } + /*end 301b */ + if ((0x31 <= ModeNo) && (ModeNo <= 0x35)) + tempal = 6; + if (SiS_LCDInfo & LCDNonExpanding) + tempbx = 0x0D; + if (SiS_LCDResInfo == Panel1280x960) + tempbx = 0x0E; + *CRT2Index = tempbx; + *ResIndex = tempal; + } else { /* LVDS */ + Flag = 1; + tempbx = 0; + if (SiS_IF_DEF_CH7005 == 1) { + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + Flag = 0; + tempbx = 7; + if (SiS_VBInfo & SetPALTV) + tempbx = tempbx + 2; + if (SiS_VBInfo & SetCHTVOverScan) + tempbx = tempbx + 1; + } + } + if (Flag == 1) { + tempbx = SiS_LCDResInfo - Panel800x600; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx + 3; + } + } + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x1F; + *CRT2Index = tempbx; + *ResIndex = tempal; + } +} + +void +SiS_GetCRT2PtrA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * CRT2Index, + USHORT * ResIndex) +{ + USHORT tempbx, tempal; + + tempbx = SiS_LCDResInfo - Panel1024x768; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx + 3; + } + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x1F; + *CRT2Index = tempbx; + *ResIndex = tempal; +} + +/*end 301b*/ + +USHORT +SiS_GetRatePtrCRT2 (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + SHORT LCDRefreshIndex[] = { 0x00, 0x00, 0x03, 0x01 }; + SHORT LCDARefreshIndex[] = { 0x00, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01 }; + USHORT RefreshRateTableIndex, i; + USHORT modeflag, index, temp; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + if (modeflag & HalfDCLK) + return (0); + } + } + if (ModeNo < 0x14) + return (0xFFFF); + index = SiS_GetReg1 (SiS_P3d4, 0x33); + index = index >> SiS_SelectCRT2Rate; + index = index & 0x0F; + if (SiS_LCDInfo & LCDNonExpanding) + index = 0; + if (index > 0) + index--; + + if (SiS_SetFlag & ProgrammingCRT2) { + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + index = 0; + } + } + if (SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if (SiS_IF_DEF_LVDS == 0) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) temp = + LCDARefreshIndex[SiS_LCDResInfo]; /*301b */ + else + temp = LCDRefreshIndex[SiS_LCDResInfo]; + if (index > temp) { + index = temp; + } + } else { + index = 0; + } + } + } + + RefreshRateTableIndex = SiS_EModeIDTable[ModeIdIndex].REFindex; + ModeNo = SiS_RefIndex[RefreshRateTableIndex].ModeID; + i = 0; + do { + if (SiS_RefIndex[RefreshRateTableIndex + i].ModeID != ModeNo) + break; + temp = SiS_RefIndex[RefreshRateTableIndex + i].Ext_InfoFlag; + temp = temp & ModeInfoFlag; + if (temp < SiS_ModeType) + break; + + i++; + index--; + } while (index != 0xFFFF); + + if (!(SiS_VBInfo & SetCRT2ToRAMDAC)) { + if (SiS_VBInfo & SetInSlaveMode) { + temp = + SiS_RefIndex[RefreshRateTableIndex + i - + 1].Ext_InfoFlag; + if (temp & InterlaceMode) { + i++; + } + } + } + + i--; + if ((SiS_SetFlag & ProgrammingCRT2)) { + temp = + SiS_AjustCRT2Rate (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &i); + } + return (RefreshRateTableIndex + i); /*return(0x01|(temp1<<1)); */ +} + +BOOLEAN +SiS_AjustCRT2Rate (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * i) +{ + USHORT tempax, tempbx, resinfo; + USHORT modeflag, infoflag; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ModeFlag */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + tempbx = SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID; + tempax = 0; + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempax = tempax | SupportRAMDAC2; + } + if (SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /*301b */ + tempax = tempax | SupportLCD; + if (SiS_LCDResInfo != Panel1280x1024) { + if (SiS_LCDResInfo != Panel1280x960) { + if (SiS_LCDInfo & LCDNonExpanding) { + if (resinfo >= 9) { + tempax = 0; + return (0); + } + } + } + } + } + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { /* for HiTV */ + tempax = tempax | SupportHiVisionTV; + if (SiS_VBInfo & SetInSlaveMode) { + if (resinfo == 4) + return (0); + if (resinfo == 3) { + if (SiS_SetFlag & TVSimuMode) + return (0); + } + if (resinfo > 7) + return (0); + } + } else { + if (SiS_VBInfo & + (SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | + SetCRT2ToSCART)) { + tempax = tempax | SupportTV; + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { /*301b */ + + tempax = tempax | SupportTV1024; + + } + /*end 301b */ + + if (!(SiS_VBInfo & SetPALTV)) { + if (modeflag & NoSupportSimuTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if (! + (SiS_VBInfo & + SetNotSimuMode)) { + return 0; + } + } + } + } + } + } + } else { /* for LVDS */ + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + tempax = tempax | SupportCHTV; + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + tempax = tempax | SupportLCD; + if (resinfo > 0x08) + return (0); /*1024x768 */ + if (SiS_LCDResInfo < Panel1024x768) { + if (resinfo > 0x07) + return (0); /*800x600 */ + if (resinfo == 0x04) + return (0); /*512x384 */ + } + } + } + + for (; SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID == tempbx; + (*i)--) { + infoflag = + SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag; + if (infoflag & tempax) { + return (1); + } + if ((*i) == 0) + break; + } + + for ((*i) = 0;; (*i)++) { + infoflag = + SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag; + if (SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID != tempbx) { + return (0); + } + if (infoflag & tempax) { + return (1); + } + } + return (1); +} + +void +SiS_SaveCRT2Info (USHORT ModeNo) +{ + USHORT temp1, temp2; + + SiS_SetReg1 (SiS_P3d4, 0x34, ModeNo); /* reserve CR34 for CRT1 Mode No */ + temp1 = (SiS_VBInfo & SetInSlaveMode) >> 8; + temp2 = ~(SetInSlaveMode >> 8); + SiS_SetRegANDOR (SiS_P3d4, 0x31, temp2, temp1); +} + +void +SiS_GetVBInfo301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT tempax, tempbx, temp; + USHORT modeflag; + UCHAR OutputSelect = *pSiS_OutputSelect; + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + SiS_SetFlag = 0; + + SiS_ModeType = modeflag & ModeInfoFlag; + tempbx = 0; + if (SiS_BridgeIsOn (BaseAddr)) { + temp = SiS_GetReg1 (SiS_P3d4, 0x30); + tempbx = tempbx | temp; + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + tempax = temp << 8; + tempbx = tempbx | tempax; + temp = SetCHTVOverScan | SetInSlaveMode | DisableCRT2Display; /* ynlai */ + temp = 0xFFFF ^ temp; + tempbx = tempbx & temp; +#ifdef CONFIG_FB_SIS_315 + /*301b */ + if ((SiS_VBType & VB_SIS302B)) { + temp = SiS_GetReg1 (SiS_P3d4, 0x38); + if (temp == 0x03) + tempbx = tempbx | (SetCRT2ToLCDA); + } + /*end301b */ +#endif + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_IF_DEF_HiVision) + temp = 0x80FC; + else + temp = 0x807C; + } else { + if (SiS_IF_DEF_CH7005 == 1) { + temp = SetCRT2ToTV | SetCRT2ToLCD; + } else { + temp = SetCRT2ToLCD; + } + } + if (!(tempbx & temp)) { + tempax = tempax | DisableCRT2Display; + tempbx = 0; + } + + if (SiS_IF_DEF_LVDS == 0) { + if (tempbx & SetCRT2ToLCDA) { /*301b */ + tempbx = + tempbx & (0xFF00 | SwitchToCRT2 | + SetSimuScanMode); + } else if (tempbx & SetCRT2ToRAMDAC) { + tempbx = + tempbx & (0xFF00 | SetCRT2ToRAMDAC | + SwitchToCRT2 | SetSimuScanMode); + } else if ((tempbx & SetCRT2ToLCD) && (!(SiS_VBType & VB_NoLCD))) { /*301dlvds */ + tempbx = + tempbx & (0xFF00 | SetCRT2ToLCD | + SwitchToCRT2 | SetSimuScanMode); + } else if (tempbx & SetCRT2ToSCART) { + tempbx = + tempbx & (0xFF00 | SetCRT2ToSCART | + SwitchToCRT2 | SetSimuScanMode); + tempbx = tempbx | SetPALTV; + } else if (tempbx & SetCRT2ToHiVisionTV) { + tempbx = + tempbx & (0xFF00 | SetCRT2ToHiVisionTV | + SwitchToCRT2 | SetSimuScanMode); + /* ynlai begin */ + tempbx = tempbx | SetPALTV; + /* ynlai end */ + } + } else { + if (SiS_IF_DEF_CH7005 == 1) { + if (tempbx & SetCRT2ToTV) + tempbx = + tempbx & (0xFF00 | SetCRT2ToTV | + SwitchToCRT2 | + SetSimuScanMode); + } + if (tempbx & SetCRT2ToLCD) + tempbx = + tempbx & (0xFF00 | SetCRT2ToLCD | + SwitchToCRT2 | SetSimuScanMode); + } + if (tempax & DisableCRT2Display) { + if (!(tempbx & (SwitchToCRT2 | SetSimuScanMode))) { + tempbx = SetSimuScanMode | DisableCRT2Display; + } + } + if (!(tempbx & DriverMode)) { + tempbx = tempbx | SetSimuScanMode; + } + if (!(tempbx & SetSimuScanMode)) { + if (tempbx & SwitchToCRT2) { + if (!(modeflag & CRT2Mode)) { + tempbx = tempbx | SetSimuScanMode; + } + } else { + if (! + (SiS_BridgeIsEnable + (BaseAddr, HwDeviceExtension))) { + if (!(tempbx & DriverMode)) { + if (SiS_BridgeInSlave ()) { + tempbx = + tempbx | + SetInSlaveMode; + } + } + } + } + } + if (!(tempbx & DisableCRT2Display)) { + if (tempbx & DriverMode) { + if (tempbx & SetSimuScanMode) { + if (!(modeflag & CRT2Mode)) { + tempbx = + tempbx | SetInSlaveMode; + if (SiS_IF_DEF_LVDS == 0) { + if (tempbx & + SetCRT2ToTV) { + if (! + (tempbx & + SetNotSimuMode)) + SiS_SetFlag = + SiS_SetFlag + | + TVSimuMode; + } + } + } + } + } else { + tempbx = tempbx | SetInSlaveMode; + if (SiS_IF_DEF_LVDS == 0) { + if (tempbx & SetCRT2ToTV) { + if (!(tempbx & SetNotSimuMode)) + SiS_SetFlag = + SiS_SetFlag | + TVSimuMode; + } + } + } + } + if (SiS_IF_DEF_CH7005 == 1) { + temp = SiS_GetReg1 (SiS_P3d4, 0x35); + if (temp & TVOverScan) + tempbx = tempbx | SetCHTVOverScan; + } + } +#ifdef CONFIG_FB_SIS_300 + /*add PALMN */ + if (SiS_IF_DEF_LVDS == 0) { + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + if (!(OutputSelect & EnablePALMN)) + SiS_SetRegAND (SiS_P3d4, 0x35, 0x3F); + if (tempbx & SetCRT2ToTV) { + if (tempbx & SetPALTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x35); + temp = temp & 0xC0; + if (temp == 0x40) + tempbx = tempbx & (~SetPALTV); + } + } + } + } + /*end add */ +#endif +#ifdef CONFIG_FB_SIS_315 + /*add PALMN */ + if (SiS_IF_DEF_LVDS == 0) { + if (!(OutputSelect & EnablePALMN)) + SiS_SetRegAND (SiS_P3d4, 0x38, 0x3F); + if (tempbx & SetCRT2ToTV) { + if (tempbx & SetPALTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x38); + temp = temp & 0xC0; + if (temp == 0x40) + tempbx = tempbx & (~SetPALTV); + } + } + } + /*end add */ +#endif + SiS_VBInfo = tempbx; +} + +void +SiS_GetRAMDAC2DATA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT tempax, tempbx, temp; + USHORT temp1, temp2, modeflag = 0, tempcx; + + USHORT StandTableIndex, CRT1Index; + USHORT ResInfo, DisplayType; + SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL; + + SiS_RVBHCMAX = 1; + SiS_RVBHCFACT = 1; + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + StandTableIndex = SiS_GetModePtr (ROMAddr, ModeNo, ModeIdIndex); + tempax = SiS_StandTable[StandTableIndex].CRTC[0]; + tempbx = SiS_StandTable[StandTableIndex].CRTC[6]; + temp1 = SiS_StandTable[StandTableIndex].CRTC[7]; + } else { + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + /*add crt1ptr */ + temp = + SiS_GetLVDSCRT1Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &ResInfo, + &DisplayType); + if (temp == 0) { + return; + } + switch (DisplayType) { + case 0: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1; + break; + case 1: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1; + break; + case 2: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1; + break; + case 3: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H; + break; + case 4: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H; + break; + case 5: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H; + break; + case 6: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2; + break; + case 7: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2; + break; + case 8: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2; + break; + case 9: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H; + break; + case 10: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H; + break; + case 11: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H; + break; + case 12: + LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC; + break; + case 13: + LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC; + break; + case 14: + LVDSCRT1Ptr = SiS_CHTVCRT1UPAL; + break; + case 15: + LVDSCRT1Ptr = SiS_CHTVCRT1OPAL; + break; + } + temp1 = (LVDSCRT1Ptr + ResInfo)->CR[0]; + temp2 = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8); + tempbx = (LVDSCRT1Ptr + ResInfo)->CR[6]; + tempcx = (LVDSCRT1Ptr + ResInfo)->CR[13] << 8; + tempcx = tempcx & 0x0100; + tempcx = tempcx << 2; + tempbx = tempbx | tempcx; + temp1 = (LVDSCRT1Ptr + ResInfo)->CR[7]; + } /*add 301b */ + else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + CRT1Index = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index = CRT1Index & 0x3F; + temp1 = (USHORT) SiS_CRT1Table[CRT1Index].CR[0]; + temp2 = (USHORT) SiS_CRT1Table[CRT1Index].CR[14]; + tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8); + tempbx = (USHORT) SiS_CRT1Table[CRT1Index].CR[6]; + tempcx = (USHORT) SiS_CRT1Table[CRT1Index].CR[13] << 8; + tempcx = tempcx & 0x0100; + tempcx = tempcx << 2; + tempbx = tempbx | tempcx; + temp1 = (USHORT) SiS_CRT1Table[CRT1Index].CR[7]; + } + } + if (temp1 & 0x01) + tempbx = tempbx | 0x0100; + if (temp1 & 0x20) + tempbx = tempbx | 0x0200; + tempax = tempax + 5; + if (modeflag & Charx8Dot) + tempax = tempax * 8; + else + tempax = tempax * 9; + + SiS_VGAHT = tempax; + SiS_HT = tempax; + tempbx++; + SiS_VGAVT = tempbx; + SiS_VT = tempbx; +} + +void +SiS_UnLockCRT2 (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + if (HwDeviceExtension->jChipType >= SIS_315H) { + SiS_SetRegANDOR (SiS_Part1Port, 0x2f, 0xFF, 0x01); + } else { + SiS_SetRegANDOR (SiS_Part1Port, 0x24, 0xFF, 0x01); + } +} + +void +SiS_LockCRT2 (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + if (HwDeviceExtension->jChipType >= SIS_315H) { + SiS_SetRegANDOR (SiS_Part1Port, 0x2F, 0xFE, 0x00); + } else { + SiS_SetRegANDOR (SiS_Part1Port, 0x24, 0xFE, 0x00); + } +} + +void +SiS_EnableCRT2 () +{ + SiS_SetRegANDOR (SiS_P3c4, 0x1E, 0xFF, 0x20); +} + +void +SiS_DisableBridge (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + + USHORT temp1, tempah, temp; + SiS_SetRegANDOR (SiS_P3c4, 0x11, 0xF7, 0x08); +/*SetPanelDelay(1); */ + temp1 = 0x01; + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { /*301b */ + if ((SiS_IsVAMode (BaseAddr))) + temp1 = 0x00; /*no disable vb */ + } + + if (SiS_IF_DEF_LVDS == 0) { + if (!temp1) { /*301b */ + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0x0DF, 0x00); /* disable VB */ + SiS_DisplayOff (); + if (HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */ + SiS_SetRegOR (SiS_Part1Port, 0x00, 0x80); /* alan,BScreenOff */ + } + SiS_SetRegANDOR (SiS_P3c4, 0x32, 0xDF, 0x00); + + temp = SiS_GetReg1 (SiS_Part1Port, 0); + SiS_SetRegOR (SiS_Part1Port, 0x00, 0x10); /* alan,BScreenOff */ +/* + if(HwDeviceExtension->jChipType >= SIS_315H) + { + SiS_SetRegAND(SiS_Part1Port,0x2E,0x7F); + } + */ + SiS_SetRegANDOR (SiS_P3c4, 0x1E, 0xDF, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0, temp); + } else { + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + SiS_SetRegAND (SiS_P3c4, 0x32, 0xDF); + if ((!(SiS_IsDualEdge (BaseAddr))) + && (!(SiS_IsVAMode (BaseAddr)))) + tempah = 0x7F; + else if ((!(SiS_IsDualEdge (BaseAddr))) + && (SiS_IsVAMode (BaseAddr))) + tempah = 0xBF; + else + tempah = 0x3F; + SiS_SetRegAND (SiS_Part4Port, 0x1F, + tempah); + } + } + } + } else { + if (SiS_IF_DEF_CH7005) { + SiS_SetCH7005 (0x090E); + } + SiS_DisplayOff (); + SiS_SetRegANDOR (SiS_P3c4, 0x32, 0xDF, 0x00); + SiS_SetRegANDOR (SiS_P3c4, 0x1E, 0xDF, 0x00); + SiS_UnLockCRT2 (HwDeviceExtension, BaseAddr); + SiS_SetRegANDOR (SiS_Part1Port, 0x01, 0xFF, 0x80); + SiS_SetRegANDOR (SiS_Part1Port, 0x02, 0xFF, 0x40); + } +/*SetPanelDelay(0); */ + SiS_SetRegANDOR (SiS_P3c4, 0x11, 0xFB, 0x04); +} + +void +SiS_EnableBridge (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + USHORT temp, tempah; + + SiS_SetRegANDOR (SiS_P3c4, 0x11, 0xFB, 0x00); +/*SetPanelDelay(0); */ + if (SiS_IF_DEF_LVDS == 0) { + if ((!(SiS_IsVAMode (BaseAddr))) + && ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0x1F, 0x20); + } else { + temp = SiS_GetReg1 (SiS_P3c4, 0x32); + temp = temp & 0xDF; + if (SiS_BridgeInSlave ()) { + tempah = SiS_GetReg1 (SiS_P3d4, 0x30); + if (!(tempah & SetCRT2ToRAMDAC)) { + temp = temp | 0x20; + } + } + SiS_SetReg1 (SiS_P3c4, 0x32, temp); + SiS_SetRegANDOR (SiS_P3c4, 0x1E, 0xFF, 0x20); + if (HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */ + temp = SiS_GetReg1 (SiS_Part1Port, 0x2E); + if (!(temp & 0x80)) + SiS_SetRegOR (SiS_Part1Port, 0x2E, 0x80); /* by alan,BVBDOENABLE=1 */ + + } + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0x1F, 0x20); + + if (HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */ + temp = SiS_GetReg1 (SiS_Part1Port, 0x2E); + if (!(temp & 0x80)) + SiS_SetRegOR (SiS_Part1Port, 0x2E, 0x80); /* by alan,BVBDOENABLE=1 */ + } + + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0x1F, 0x20); + SiS_VBLongWait (); + SiS_DisplayOn (); + SiS_VBLongWait (); + } + /*add301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (!(SiS_Is301B (BaseAddr))) { + temp = SiS_GetReg1 (SiS_Part1Port, 0x2E); + if (!(temp & 0x80)) + SiS_SetRegOR (SiS_Part1Port, 0x2E, + 0x80); + if ((!(SiS_IsDualEdge (BaseAddr))) + && (!(SiS_IsVAMode (BaseAddr)))) + tempah = 0x80; + else if ((!(SiS_IsDualEdge (BaseAddr))) + && (SiS_IsVAMode (BaseAddr))) + tempah = 0x40; + else + tempah = 0xC0; + SiS_SetRegOR (SiS_Part4Port, 0x1F, tempah); + } + } + /*end 301b */ + } else { + /*LVDS*/ SiS_EnableCRT2 (); + SiS_DisplayOn (); + SiS_UnLockCRT2 (HwDeviceExtension, BaseAddr); + SiS_SetRegANDOR (SiS_Part1Port, 0x02, 0xBF, 0x00); + if (SiS_BridgeInSlave ()) { + SiS_SetRegANDOR (SiS_Part1Port, 0x01, 0x1F, 0x00); + } else { + SiS_SetRegANDOR (SiS_Part1Port, 0x01, 0x1F, 0x40); + } + if (SiS_IF_DEF_CH7005) { + SiS_SetCH7005 (0x0B0E); + } + } +/*SetPanelDelay(1); */ + SiS_SetRegANDOR (SiS_P3c4, 0x11, 0xF7, 0x00); +} + +void +SiS_SetPanelDelay (USHORT DelayTime) +{ + USHORT PanelID; + + PanelID = SiS_GetReg1 (SiS_P3d4, 0x36); + PanelID = PanelID >> 4; + + if (DelayTime == 0) + SiS_LCD_Wait_Time (SiS_PanelDelayTbl[PanelID].timer[0]); + else + SiS_LCD_Wait_Time (SiS_PanelDelayTbl[PanelID].timer[1]); +} + +void +SiS_LCD_Wait_Time (UCHAR DelayTime) +{ + USHORT i, j; + ULONG temp, flag; + + flag = 0; + for (i = 0; i < DelayTime; i++) { + for (j = 0; j < 66; j++) { + temp = SiS_GetReg3 (0x61); + temp = temp & 0x10; + if (temp == flag) + continue; + flag = temp; + } + } +} + +/*301b*/ + +BOOLEAN +SiS_Is301B (USHORT BaseAddr) +{ + USHORT flag; + flag = SiS_GetReg1 (SiS_Part4Port, 0x01); + if (flag > (0x0B0)) + return (0); /*301b */ + else + return (1); +} + +BOOLEAN +SiS_IsDualEdge (USHORT BaseAddr) +{ +#ifdef CONFIG_FB_SIS_315 + USHORT flag; + flag = SiS_GetReg1 (SiS_P3d4, 0x38); + if (flag & EnableDualEdge) + return (0); + else + return (1); +#endif + return (1); +} + +BOOLEAN +SiS_IsVAMode (USHORT BaseAddr) +{ + USHORT flag; + flag = SiS_GetReg1 (SiS_P3d4, 0x38); +#ifdef CONFIG_FB_SIS_315 + if ((flag & EnableDualEdge) && (flag & SetToLCDA)) + return (0); + else + return (1); +#endif + return (1); +} + +BOOLEAN +SiS_IsDisableCRT2 (USHORT BaseAddr) +{ + USHORT flag; + flag = SiS_GetReg1 (SiS_P3d4, 0x30); + if (flag & 0x20) + return (0); /*301b */ + else + return (1); +} + +/*end 301b*/ + +BOOLEAN +SiS_BridgeIsOn (USHORT BaseAddr) +{ + USHORT flag; + + if (SiS_IF_DEF_LVDS == 1) { + return (1); + } else { + flag = SiS_GetReg1 (SiS_Part4Port, 0x00); + if ((flag == 1) || (flag == 2)) + return (1); /*301b */ + else + return (0); + } +} + +BOOLEAN +SiS_BridgeIsEnable (USHORT BaseAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT flag; + + if (SiS_BridgeIsOn (BaseAddr) == 0) { + flag = SiS_GetReg1 (SiS_Part1Port, 0x0); + if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + if (flag & 0x0a0) { + return 1; + } else { + return 0; + } + } else { /* 310 series */ + + if (flag & 0x050) { + return 1; + } else { + return 0; + } + + } + } + return 0; +} + +BOOLEAN +SiS_BridgeInSlave () +{ + USHORT flag1; + + flag1 = SiS_GetReg1 (SiS_P3d4, 0x31); + if (flag1 & (SetInSlaveMode >> 8)) { + return 1; + } else { + return 0; + } +} + +BOOLEAN +SiS_GetLCDResInfo301 (ULONG ROMAddr, USHORT SiS_P3d4, USHORT ModeNo, + USHORT ModeIdIndex) +{ + USHORT temp, modeflag, resinfo = 0; + + SiS_LCDResInfo = 0; + SiS_LCDTypeInfo = 0; + SiS_LCDInfo = 0; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ModeFlag */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; /*si+Ext_ResInfo */ + } + + if (!(SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) { + return 0; + } + if (!(SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2))) { + return 0; + } + temp = SiS_GetReg1 (SiS_P3d4, 0x36); + SiS_LCDTypeInfo = temp >> 4; + SiS_LCDResInfo = temp & 0x0F; + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_LCDResInfo < Panel1024x768) + SiS_LCDResInfo = Panel1024x768; + } else { + if (SiS_LCDResInfo < Panel800x600) + SiS_LCDResInfo = Panel800x600; + } + if (SiS_LCDResInfo > Panel640x480) + SiS_LCDResInfo = Panel1024x768; + + temp = SiS_GetReg1 (SiS_P3d4, 0x37); + SiS_LCDInfo = temp; + + if (SiS_IF_DEF_LVDS == 1) { + if (modeflag & HalfDCLK) { + if (SiS_IF_DEF_TRUMPION == 0) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (ModeNo > 0x13) { + if (SiS_LCDResInfo == + Panel1024x768) { + if (resinfo == 4) { /* 512x384 */ + SiS_SetFlag = + SiS_SetFlag + | + EnableLVDSDDA; + } + } else { + if (SiS_LCDResInfo == + Panel800x600) { + if (resinfo == 3) { /*400x300 */ + SiS_SetFlag + = + SiS_SetFlag + | + EnableLVDSDDA; + } + } + } + } + } else { + SiS_SetFlag = + SiS_SetFlag | EnableLVDSDDA; + } + } else { + SiS_SetFlag = SiS_SetFlag | EnableLVDSDDA; + } + } + } + + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_VBInfo & SetNotSimuMode) { + SiS_SetFlag = SiS_SetFlag | LCDVESATiming; + } + } else { + SiS_SetFlag = SiS_SetFlag | LCDVESATiming; + } + return 1; +} + +void +SiS_PresetScratchregister (USHORT SiS_P3d4, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + /*SiS_SetReg1(SiS_P3d4,0x30,0x21); */ + /*SiS_SetReg1(SiS_P3d4,0x31,0x41); */ + /*SiS_SetReg1(SiS_P3d4,0x32,0x28); */ + /*SiS_SetReg1(SiS_P3d4,0x33,0x22); */ + /*SiS_SetReg1(SiS_P3d4,0x35,0x43); */ + /*SiS_SetReg1(SiS_P3d4,0x36,0x01); */ + /*SiS_SetReg1(SiS_P3d4,0x37,0x00); */ +} + +void +SiS_LongWait () +{ + USHORT i; + + i = SiS_GetReg1 (SiS_P3c4, 0x1F); + if (!(i & 0xC0)) { + + for (i = 0; i < 0xFFFF; i++) { + if (!(SiS_GetReg2 (SiS_P3da) & 0x08)) + break; + } + for (i = 0; i < 0xFFFF; i++) { + if ((SiS_GetReg2 (SiS_P3da) & 0x08)) + break; + } + } +} + +void +SiS_VBLongWait () +{ + USHORT tempal, temp, i, j; + + if (!(SiS_VBInfo & SetCRT2ToTV)) { + temp = 0; + for (i = 0; i < 3; i++) { + for (j = 0; j < 100; j++) { + tempal = SiS_GetReg2 (SiS_P3da); + if (temp & 0x01) { /* VBWaitMode2 */ + if ((tempal & 0x08)) { + continue; + } + if (!(tempal & 0x08)) { + break; + } + } else { /* VBWaitMode1 */ + if (!(tempal & 0x08)) { + continue; + } + if ((tempal & 0x08)) { + break; + } + } + } + temp = temp ^ 0x01; + } + } else { + SiS_LongWait (); + } + return; +} + +BOOLEAN +SiS_WaitVBRetrace (USHORT BaseAddr) +{ + USHORT temp; + + return 0; + + temp = SiS_GetReg1 (SiS_Part1Port, 0x00); + if (!(temp & 0x80)) { + return 0; + } + + for (temp = 0; temp == 0;) { + temp = SiS_GetReg1 (SiS_Part1Port, 0x25); + temp = temp & 0x01; + } + for (; temp > 0;) { + temp = SiS_GetReg1 (SiS_Part1Port, 0x25); + temp = temp & 0x01; + } + return 1; +} + +void +SiS_SetRegANDOR (USHORT Port, USHORT Index, USHORT DataAND, USHORT DataOR) +{ + USHORT temp; + + temp = SiS_GetReg1 (Port, Index); /* SiS_Part1Port index 02 */ + temp = (temp & (DataAND)) | DataOR; + SiS_SetReg1 (Port, Index, temp); +} + +void +SiS_SetRegAND (USHORT Port, USHORT Index, USHORT DataAND) +{ + USHORT temp; + + temp = SiS_GetReg1 (Port, Index); /* SiS_Part1Port index 02 */ + temp = temp & DataAND; + SiS_SetReg1 (Port, Index, temp); +} + +void +SiS_SetRegOR (USHORT Port, USHORT Index, USHORT DataOR) +{ + USHORT temp; + + temp = SiS_GetReg1 (Port, Index); /* SiS_Part1Port index 02 */ + temp = temp | DataOR; + SiS_SetReg1 (Port, Index, temp); +} + +void +SiS_SetGroup2 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT i, j, tempax, tempbx, tempcx, temp, temp3; + USHORT push1, push2, temp1; + UCHAR *PhasePoint; + UCHAR *TimingPoint; + USHORT modeflag, resinfo, crt2crtc, resindex, xres; + ULONG longtemp, tempeax, tempebx, temp2, tempecx; + USHORT SiS_RY1COE = 0, SiS_RY2COE = 0, SiS_RY3COE = 0, SiS_RY4COE = + 0, SiS_RY5COE = 0, SiS_RY6COE = 0, SiS_RY7COE = 0; + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + crt2crtc = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + crt2crtc = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + tempcx = SiS_VBInfo; + tempax = (tempcx & 0x00FF) << 8; + tempbx = (tempcx & 0x00FF) | ((tempcx & 0x00FF) << 8); + tempbx = tempbx & 0x0410; + temp = (tempax & 0x0800) >> 8; + temp = temp >> 1; + temp = temp | (((tempbx & 0xFF00) >> 8) << 1); + temp = temp | ((tempbx & 0x00FF) >> 3); + temp = temp ^ 0x0C; + + PhasePoint = SiS_PALPhase; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { /* PALPhase */ + temp = temp ^ 0x01; + if (SiS_VBInfo & SetInSlaveMode) { + TimingPoint = SiS_HiTVSt2Timing; + if (SiS_SetFlag & TVSimuMode) { + if (modeflag & Charx8Dot) + TimingPoint = SiS_HiTVSt1Timing; + else + TimingPoint = SiS_HiTVTextTiming; + } + } else + TimingPoint = SiS_HiTVExtTiming; + } else { + if (SiS_VBInfo & SetPALTV) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) PhasePoint = SiS_PALPhase2; /* PALPhase */ + else + PhasePoint = SiS_PALPhase; + + TimingPoint = SiS_PALTiming; + } else { + temp = temp | 0x10; + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) PhasePoint = SiS_NTSCPhase2; /* PALPhase */ + else + PhasePoint = SiS_NTSCPhase; + + TimingPoint = SiS_NTSCTiming; + } + } + SiS_SetReg1 (SiS_Part2Port, 0x0, temp); + +#ifdef CONFIG_FB_SIS_300 + /*add PALMN */ + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp1 = temp1 & 0x40; + if (temp1) + PhasePoint = SiS_PALMPhase; + temp1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp1 = temp1 & 0x80; + if (temp1) + PhasePoint = SiS_PALNPhase; + } + } + } +/*end add*/ +#endif +#ifdef CONFIG_FB_SIS_315 + /*add PALMN */ + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp1 = temp1 & 0x40; + if (temp1) + PhasePoint = SiS_PALMPhase; + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp1 = temp1 & 0x80; + if (temp1) + PhasePoint = SiS_PALNPhase; + } + } + /*end add */ +#endif + for (i = 0x31, j = 0; i <= 0x34; i++, j++) { + SiS_SetReg1 (SiS_Part2Port, i, PhasePoint[j]); + } + for (i = 0x01, j = 0; i <= 0x2D; i++, j++) { + SiS_SetReg1 (SiS_Part2Port, i, TimingPoint[j]); + } + for (i = 0x39; i <= 0x45; i++, j++) { + SiS_SetReg1 (SiS_Part2Port, i, TimingPoint[j]); /* di->temp2[j] */ + } + if (SiS_VBInfo & SetCRT2ToTV) { + SiS_SetRegANDOR (SiS_Part2Port, 0x3A, 0x1F, 0x00); + } + temp = SiS_NewFlickerMode; + SiS_SetRegANDOR (SiS_Part2Port, 0x0A, 0xFF, temp); + + SiS_SetReg1 (SiS_Part2Port, 0x35, 0x00); /*301b */ + SiS_SetReg1 (SiS_Part2Port, 0x36, 0x00); + SiS_SetReg1 (SiS_Part2Port, 0x37, 0x00); + SiS_SetReg1 (SiS_Part2Port, 0x38, SiS_RY1COE); + SiS_SetReg1 (SiS_Part2Port, 0x48, SiS_RY2COE); + SiS_SetReg1 (SiS_Part2Port, 0x49, SiS_RY3COE); + SiS_SetReg1 (SiS_Part2Port, 0x4a, SiS_RY4COE); +/*add to change 630+301b filter*/ + + resindex = SiS_GetResInfo (ROMAddr, ModeNo, ModeIdIndex); + if (ModeNo <= 0x13) { + xres = SiS_StResInfo[resindex].HTotal; + } else { + xres = SiS_ModeResInfo[resindex].HTotal; /* xres->ax */ + } + if (xres == 640) { + SiS_RY1COE = 0xFF; + SiS_RY2COE = 0x03; + SiS_RY3COE = 0x02; + SiS_RY4COE = 0xF6; + SiS_RY5COE = 0xFC; + SiS_RY6COE = 0x27; + SiS_RY7COE = 0x46; + } + if (xres == 800) { + SiS_RY1COE = 0x01; + SiS_RY2COE = 0x01; + SiS_RY3COE = 0xFC; + SiS_RY4COE = 0xF8; + SiS_RY5COE = 0x08; + SiS_RY6COE = 0x26; + SiS_RY7COE = 0x38; + } + if (xres == 1024) { + SiS_RY1COE = 0xFF; + SiS_RY2COE = 0xFF; + SiS_RY3COE = 0xFC; + SiS_RY4COE = 0x00; + SiS_RY5COE = 0x0F; + SiS_RY6COE = 0x22; + SiS_RY7COE = 0x28; + } + if (xres == 720) { + SiS_RY1COE = 0x01; + SiS_RY2COE = 0x02; + SiS_RY3COE = 0xFE; + SiS_RY4COE = 0xF7; + SiS_RY5COE = 0x03; + SiS_RY6COE = 0x27; + SiS_RY7COE = 0x3c; + } + SiS_SetReg1 (SiS_Part2Port, 0x35, SiS_RY1COE); /*301b */ + SiS_SetReg1 (SiS_Part2Port, 0x36, SiS_RY2COE); + SiS_SetReg1 (SiS_Part2Port, 0x37, SiS_RY3COE); + SiS_SetReg1 (SiS_Part2Port, 0x38, SiS_RY4COE); + SiS_SetReg1 (SiS_Part2Port, 0x48, SiS_RY5COE); + SiS_SetReg1 (SiS_Part2Port, 0x49, SiS_RY6COE); + SiS_SetReg1 (SiS_Part2Port, 0x4a, SiS_RY7COE); + +/*end add*/ + + if (SiS_VBInfo & SetCRT2ToHiVisionTV) + tempax = 950; + else { + if (SiS_VBInfo & SetPALTV) + tempax = 520; + else + tempax = 440; + } + if (SiS_VDE <= tempax) { + tempax = tempax - SiS_VDE; + tempax = tempax >> 2; + tempax = (tempax & 0x00FF) | ((tempax & 0x00FF) << 8); + push1 = tempax; + temp = (tempax & 0xFF00) >> 8; + temp = temp + (USHORT) TimingPoint[0]; + SiS_SetReg1 (SiS_Part2Port, 0x01, temp); + tempax = push1; + temp = (tempax & 0xFF00) >> 8; + temp = temp + TimingPoint[1]; + SiS_SetReg1 (SiS_Part2Port, 0x02, temp); + } + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToTV) && (SiS_VGAHDE == 1024)) { + if (SiS_VBInfo & SetPALTV) { + SiS_SetReg1 (SiS_Part2Port, 0x01, 0x19); + SiS_SetReg1 (SiS_Part2Port, 0x02, 0x52); + } else { + SiS_SetReg1 (SiS_Part2Port, 0x01, 0x0B); + SiS_SetReg1 (SiS_Part2Port, 0x02, 0x11); + } + } + + tempcx = SiS_HT - 1; + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempcx = tempcx - 1; + } + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x1B, temp); + temp = (tempcx & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_Part2Port, 0x1D, ~0x0F, temp); + + tempcx = SiS_HT >> 1; + push1 = tempcx; /* push cx */ + tempcx = tempcx + 7; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempcx = tempcx - 4; + } + temp = (tempcx & 0x00FF); + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x22, 0x0F, temp); + + tempbx = TimingPoint[j] | ((TimingPoint[j + 1]) << 8); + tempbx = tempbx + tempcx; + push2 = tempbx; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x24, temp); + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x25, 0x0F, temp); + + tempbx = push2; + tempbx = tempbx + 8; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempbx = tempbx - 4; + tempcx = tempbx; + } + temp = (tempbx & 0x00FF) << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x29, 0x0F, temp); + + j = j + 2; + tempcx = tempcx + (TimingPoint[j] | ((TimingPoint[j + 1]) << 8)); + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x27, temp); + temp = ((tempcx & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x28, 0x0F, temp); + + tempcx = tempcx + 8; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempcx = tempcx - 4; + } + temp = tempcx & 0xFF; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x2A, 0x0F, temp); + + tempcx = push1; /* pop cx */ + j = j + 2; + temp = TimingPoint[j] | ((TimingPoint[j + 1]) << 8); + tempcx = tempcx - temp; + temp = tempcx & 0x00FF; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x2D, 0x0F, temp); + + tempcx = tempcx - 11; + if (!(SiS_VBInfo & SetCRT2ToTV)) { + tempax = SiS_GetVGAHT2 (); + tempcx = tempax - 1; + } + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x2E, temp); + + tempbx = SiS_VDE; + if (SiS_VGAVDE == 360) + tempbx = 746; + if (SiS_VGAVDE == 375) + tempbx = 746; + if (SiS_VGAVDE == 405) + tempbx = 853; + if (SiS_VBInfo & SetCRT2ToTV) { + tempbx = tempbx >> 1; + } + tempbx = tempbx - 2; + temp = tempbx & 0x00FF; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if (ModeNo == 0x2f) + temp = temp + 1; + } + } + SiS_SetReg1 (SiS_Part2Port, 0x2F, temp); + + temp = (tempcx & 0xFF00) >> 8; + temp = temp | (((tempbx & 0xFF00) >> 8) << 6); + if (!(SiS_VBInfo & SetCRT2ToHiVisionTV)) { + temp = temp | 0x10; + if (!(SiS_VBInfo & SetCRT2ToSVIDEO)) { + temp = temp | 0x20; + } + } + SiS_SetReg1 (SiS_Part2Port, 0x30, temp); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { /*tv gatingno */ + tempbx = SiS_VDE; + if (SiS_VBInfo & SetCRT2ToTV) { + tempbx = tempbx >> 1; + } + temp = (((tempbx - 3) & 0x0300) >> 8) << 5; + SiS_SetReg1 (SiS_Part2Port, 0x46, temp); + temp = (tempbx - 3) & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x47, temp); + } +/*end 301b*/ + + tempbx = tempbx & 0x00FF; + if (!(modeflag & HalfDCLK)) { + tempcx = SiS_VGAHDE; + if (tempcx >= SiS_HDE) { + tempbx = tempbx | 0x2000; + tempax = tempax & 0x00FF; + } + } + tempcx = 0x0101; + + if (SiS_VBInfo & (SetCRT2ToHiVisionTV | SetCRT2ToTV)) { /*301b */ + if (SiS_VGAHDE >= 1024) { + tempcx = 0x1920; + if (SiS_VGAHDE >= 1280) { + tempcx = 0x1420; + tempbx = tempbx & 0xDFFF; + } + } + } + if (!(tempbx & 0x2000)) { + if (modeflag & HalfDCLK) { + tempcx = (tempcx & 0xFF00) | ((tempcx & 0x00FF) << 1); + } + push1 = tempbx; + tempeax = SiS_VGAHDE; + tempebx = (tempcx & 0xFF00) >> 8; + longtemp = tempeax * tempebx; + tempecx = tempcx & 0x00FF; + longtemp = longtemp / tempecx; + /*301b */ + tempecx = 8 * 1024; + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempecx = tempecx * 8; + } + longtemp = longtemp * tempecx; + tempecx = SiS_HDE; + temp2 = longtemp % tempecx; + tempeax = longtemp / tempecx; + if (temp2 != 0) { + tempeax = tempeax + 1; + } + tempax = (USHORT) tempeax; + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempcx = ((tempax & 0xFF00) >> 5) >> 8; + } + /*end 301b */ + tempbx = push1; + tempbx = + (USHORT) (((tempeax & 0x0000FF00) & 0x1F00) | + (tempbx & 0x00FF)); + tempax = + (USHORT) (((tempeax & 0x000000FF) << 8) | + (tempax & 0x00FF)); + temp = (tempax & 0xFF00) >> 8; + } else { + temp = (tempax & 0x00FF) >> 8; + } + SiS_SetReg1 (SiS_Part2Port, 0x44, temp); + temp = (tempbx & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_Part2Port, 0x45, ~0x03F, temp); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + if ((tempcx & 0x00FF) == 0x01) + tempcx = 0x00; + SiS_SetRegANDOR (SiS_Part2Port, 0x46, ~0x007, tempcx); + SiS_SetRegOR (SiS_Part2Port, 0x46, 0x18); + if (SiS_VBInfo & SetPALTV) { + tempbx = 0x0364; + tempcx = 0x009c; + } else { + tempbx = 0x0346; + tempcx = 0x0078; + } + temp = (tempbx & 0x00FF); + SiS_SetReg1 (SiS_Part2Port, 0x4B, temp); + temp = (tempcx & 0x00FF); + SiS_SetReg1 (SiS_Part2Port, 0x4C, temp); + tempbx = (tempbx & 0x0300); + temp = (tempcx & 0xFF00) >> 8; + temp = (temp & 0x0003) << 2; + temp = temp | (tempbx >> 8); + SiS_SetReg1 (SiS_Part2Port, 0x4D, temp); + temp = SiS_GetReg1 (SiS_Part2Port, 0x43); + SiS_SetReg1 (SiS_Part2Port, 0x43, temp - 3); + } +/*end 301b*/ + +#ifdef CONFIG_FB_SIS_300 +/*add PALMN*/ + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp1 = temp1 & 0x40; + if (temp1) { + SiS_SetRegANDOR (SiS_Part2Port, 0x00, + 0xEF, 0x00); + temp3 = + SiS_GetReg1 (SiS_Part2Port, 0x01); + temp3 = temp3 - 1; + SiS_SetReg1 (SiS_Part2Port, 0x01, + temp3); + } + } + } + } + /*end add */ +#endif + +#ifdef CONFIG_FB_SIS_315 +/*add PALMN*/ + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp1 = temp1 & 0x40; + if (temp1) { + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0xEF, + 0x00); + temp3 = SiS_GetReg1 (SiS_Part2Port, 0x01); + temp3 = temp3 - 1; + SiS_SetReg1 (SiS_Part2Port, 0x01, temp3); + } + } + } + /*end add */ +#endif + + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (!(SiS_VBInfo & SetInSlaveMode)) { + SiS_SetReg1 (SiS_Part2Port, 0x0B, 0x00); + } + } + if (SiS_VBInfo & SetCRT2ToTV) { + return; + } + + tempbx = SiS_HDE - 1; /* RHACTE=HDE-1 */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x2C, temp); + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x2B, 0x0F, temp); + temp = 0x01; + if (SiS_LCDResInfo == Panel1280x1024) { + if (SiS_ModeType == ModeEGA) { + if (SiS_VGAHDE >= 1024) { + temp = 0x02; + if (SiS_SetFlag & LCDVESATiming) + temp = 0x01; + } + } + } + SiS_SetReg1 (SiS_Part2Port, 0x0B, temp); + + tempbx = SiS_VDE; /* RTVACTEO=(VDE-1)&0xFF */ + push1 = tempbx; + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x03, temp); + temp = ((tempbx & 0xFF00) >> 8) & 0x07; + SiS_SetRegANDOR (SiS_Part2Port, 0x0C, ~0x07, temp); + + tempcx = SiS_VT - 1; + push2 = tempcx + 1; + temp = tempcx & 0x00FF; /* RVTVT=VT-1 */ + SiS_SetReg1 (SiS_Part2Port, 0x19, temp); + temp = (tempcx & 0xFF00) >> 8; + temp = temp << 5; + if (SiS_LCDInfo & LCDRGB18Bit) { + temp = temp | 0x10; + } + if (SiS_VBInfo & SetCRT2ToLCD) { + tempbx = (tempbx & 0xFF00) | (SiS_LCDInfo & 0x0FF); + if (tempbx & LCDSync) { + tempbx = tempbx & LCDSyncBit; + tempbx = + (tempbx & 0xFF00) | ((tempbx & 0x00FF) >> + LCDSyncShift); + temp = temp | (tempbx & 0x00FF); + } + } + SiS_SetReg1 (SiS_Part2Port, 0x1A, temp); + + tempcx++; + tempbx = 768; + if (SiS_LCDResInfo != Panel1024x768) { + tempbx = 1024; + if (SiS_LCDResInfo != Panel1280x1024) { + tempbx = 1200; /*301b */ + if (SiS_LCDResInfo != Panel1600x1200) { + if (tempbx != SiS_VDE) { + tempbx = 960; + } + } + } + } + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = SiS_VDE; + tempbx--; + tempcx--; + } + tempax = 1; + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (tempbx != SiS_VDE) { + tempax = tempbx; + if (tempax < SiS_VDE) { + tempax = 0; + tempcx = 0; + } else { + tempax = tempax - SiS_VDE; + } + tempax = tempax >> 1; + } + tempcx = tempcx - tempax; /* lcdvdes */ + tempbx = tempbx - tempax; /* lcdvdee */ + } else { + tempax = tempax >> 1; + tempcx = tempcx - tempax; /* lcdvdes */ + tempbx = tempbx - tempax; /* lcdvdee */ + } + + temp = tempcx & 0x00FF; /* RVEQ1EQ=lcdvdes */ + SiS_SetReg1 (SiS_Part2Port, 0x05, temp); + temp = tempbx & 0x00FF; /* RVEQ2EQ=lcdvdee */ + SiS_SetReg1 (SiS_Part2Port, 0x06, temp); + + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 3; + temp = temp | ((tempcx & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part2Port, 0x02, temp); + + tempbx = push2; + tempax = push1; + tempcx = tempbx; + tempcx = tempcx - tempax; + tempcx = tempcx >> 4; + tempbx = tempbx + tempax; + tempbx = tempbx >> 1; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx - 10; + } + temp = tempbx & 0x00FF; /* RTVACTEE=lcdvrs */ + SiS_SetReg1 (SiS_Part2Port, 0x04, temp); + + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 4; + tempbx = tempbx + tempcx + 1; + temp = temp | (tempbx & 0x000F); + SiS_SetReg1 (SiS_Part2Port, 0x01, temp); + + if (SiS_LCDResInfo == Panel1024x768) { + if (!(SiS_SetFlag & LCDVESATiming)) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (ModeNo == 0x13) { + SiS_SetReg1 (SiS_Part2Port, 0x04, 0xB9); + SiS_SetReg1 (SiS_Part2Port, 0x05, 0xCC); + SiS_SetReg1 (SiS_Part2Port, 0x06, 0xA6); + } else { + temp = crt2crtc & 0x3F; + if (temp == 4) { + SiS_SetReg1 (SiS_Part2Port, + 0x01, 0x2B); + SiS_SetReg1 (SiS_Part2Port, + 0x02, 0x13); + SiS_SetReg1 (SiS_Part2Port, + 0x04, 0xE5); + SiS_SetReg1 (SiS_Part2Port, + 0x05, 0x08); + SiS_SetReg1 (SiS_Part2Port, + 0x06, 0xE2); + } + } + } + } + } + + SiS_SetRegANDOR (SiS_Part2Port, 0x09, 0xF0, 0x00); + SiS_SetRegANDOR (SiS_Part2Port, 0x0A, 0xF0, 0x00); + + tempcx = (SiS_HT - SiS_HDE) >> 2; /* (HT-HDE)>>2 */ + tempbx = (SiS_HDE + 7); /* lcdhdee */ + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempbx = tempbx + 2; + } + push1 = tempbx; + temp = tempbx & 0x00FF; /* RHEQPLE=lcdhdee */ + SiS_SetReg1 (SiS_Part2Port, 0x23, temp); + temp = (tempbx & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_Part2Port, 0x25, ~0x0F, temp); + /*301b */ + temp = 7; + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + temp = temp + 2; + } + SiS_SetReg1 (SiS_Part2Port, 0x1F, temp); /* RHBLKE=lcdhdes */ + SiS_SetRegANDOR (SiS_Part2Port, 0x20, 0x0F, 0x00); + + tempbx = tempbx + tempcx; + push2 = tempbx; + temp = tempbx & 0xFF; /* RHBURSTS=lcdhrs */ + if (SiS_LCDResInfo == Panel1280x1024) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (SiS_HDE == 1280) { + temp = 0x47; + } + } + } + SiS_SetReg1 (SiS_Part2Port, 0x1C, temp); + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x1D, ~0x0F0, temp); + + tempbx = push2; + tempcx = tempcx << 1; + tempbx = tempbx + tempcx; + temp = tempbx & 0x00FF; /* RHSYEXP2S=lcdhre */ + SiS_SetReg1 (SiS_Part2Port, 0x21, temp); + + SiS_SetRegANDOR (SiS_Part2Port, 0x17, 0xFB, 0x00); + SiS_SetRegANDOR (SiS_Part2Port, 0x18, 0xDF, 0x00); + + if (!(SiS_SetFlag & LCDVESATiming)) { + if (SiS_VGAVDE == 525) { + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { /*301b */ + temp = 0xC6; + } else + temp = 0xC4; + SiS_SetReg1 (SiS_Part2Port, 0x2f, temp); + SiS_SetReg1 (SiS_Part2Port, 0x30, 0xB3); + } + if (SiS_VGAVDE == 420) { + if ( + ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B))) { + temp = 0x4F; + } else + temp = 0x4E; + SiS_SetReg1 (SiS_Part2Port, 0x2f, temp); + } + } +} + +USHORT +SiS_GetVGAHT2 () +{ + ULONG tempax, tempbx; + + tempbx = ((SiS_VGAVT - SiS_VGAVDE) * SiS_RVBHCMAX) & 0xFFFF; + tempax = (SiS_VT - SiS_VDE) * SiS_RVBHCFACT; + tempax = (tempax * SiS_HT) / tempbx; + return ((USHORT) tempax); +} + +void +SiS_SetGroup3 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT i; + UCHAR *tempdi; + USHORT modeflag, temp, temp1; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + SiS_SetReg1 (SiS_Part3Port, 0x00, 0x00); + if (SiS_VBInfo & SetPALTV) { + SiS_SetReg1 (SiS_Part3Port, 0x13, 0xFA); + SiS_SetReg1 (SiS_Part3Port, 0x14, 0xC8); + } else { + SiS_SetReg1 (SiS_Part3Port, 0x13, 0xF6); + SiS_SetReg1 (SiS_Part3Port, 0x14, 0xBF); + } +#ifdef CONFIG_FB_SIS_300 + /*add PALMN */ + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp1 = temp1 & 0x40; + if (temp1) { + SiS_SetReg1 (SiS_Part3Port, 0x13, 0xFA); + SiS_SetReg1 (SiS_Part3Port, 0x14, 0xC8); + SiS_SetReg1 (SiS_Part3Port, 0x3D, 0xA8); + } + } + } + } + /*end add */ +#endif +#ifdef CONFIG_FB_SIS_315 +/*add PALMN*/ + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp1 = temp1 & 0x40; + if (temp1) { + SiS_SetReg1 (SiS_Part3Port, 0x13, 0xFA); + SiS_SetReg1 (SiS_Part3Port, 0x14, 0xC8); + SiS_SetReg1 (SiS_Part3Port, 0x3D, 0xA8); + } + } + } + /*end add */ +#endif + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempdi = SiS_HiTVGroup3Data; + if (SiS_SetFlag & TVSimuMode) { + tempdi = SiS_HiTVGroup3Simu; + if (!(modeflag & Charx8Dot)) { + tempdi = SiS_HiTVGroup3Text; + } + } + for (i = 0; i <= 0x3E; i++) { + SiS_SetReg1 (SiS_Part3Port, i, tempdi[i]); + } + } + return; +} + +void +SiS_SetGroup4 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT tempax, tempcx, tempbx, modeflag, temp, temp2, push1; + ULONG tempebx, tempeax, templong; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + temp = SiS_RVBHCFACT; + SiS_SetReg1 (SiS_Part4Port, 0x13, temp); + + tempbx = SiS_RVBHCMAX; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x14, temp); + temp2 = ((tempbx & 0xFF00) >> 8) << 7; + + tempcx = SiS_VGAHT - 1; + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x16, temp); + temp = ((tempcx & 0xFF00) >> 8) << 3; + temp2 = temp | temp2; + + tempcx = SiS_VGAVT - 1; + if (!(SiS_VBInfo & SetCRT2ToTV)) { + tempcx = tempcx - 5; + } + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x17, temp); + temp = temp2 | ((tempcx & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part4Port, 0x15, temp); + + tempcx = SiS_VBInfo; + tempbx = SiS_VGAHDE; + if (modeflag & HalfDCLK) { + tempbx = tempbx >> 1; + } + if (tempcx & SetCRT2ToHiVisionTV) { + temp = 0xA0; + if (tempbx != 1024) { + temp = 0xC0; + if (tempbx != 1280) + temp = 0; + } + } else if ((tempcx & SetCRT2ToTV) && (SiS_VGAHDE == 1024)) { /*301b */ + temp = 0xA0; + } else { + temp = 0x80; + if (SiS_VBInfo & SetCRT2ToLCD) { + temp = 0; + if (tempbx > 800) + temp = 0x60; + } + } + if (SiS_LCDResInfo != Panel1280x1024) + temp = temp | 0x0A; + SiS_SetRegANDOR (SiS_Part4Port, 0x0E, ~0xEF, temp); + + tempebx = SiS_VDE; + if (tempcx & SetCRT2ToHiVisionTV) { + /* if(!(tempax&0xE000)) tempbx=tempbx>>1; */ + if (!(temp & 0xE000)) + tempbx = tempbx >> 1; /* alan ???? */ + + } + + tempcx = SiS_RVBHRS; + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x18, temp); + + tempebx = tempebx; + tempeax = SiS_VGAVDE; + tempcx = tempcx | 0x04000; +/*tempeax=tempeax-tempebx; */ + if (tempeax <= tempebx) { + tempcx = ((tempcx & 0xFF00) ^ 0x4000) | (tempcx & 0x00ff); + tempeax = SiS_VGAVDE; + } + + else { + tempeax = tempeax - tempebx; + } + + push1 = tempcx; + templong = (tempeax * 256 * 1024) % tempebx; + tempeax = (tempeax * 256 * 1024) / tempebx; + tempebx = tempeax; + if (templong != 0) { + tempebx++; + } + tempcx = push1; + temp = (USHORT) (tempebx & 0x000000FF); + SiS_SetReg1 (SiS_Part4Port, 0x1B, temp); + temp = (USHORT) ((tempebx & 0x0000FF00) >> 8); + SiS_SetReg1 (SiS_Part4Port, 0x1A, temp); + tempbx = (USHORT) (tempebx >> 16); + temp = tempbx & 0x00FF; + temp = temp << 4; + temp = temp | ((tempcx & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part4Port, 0x19, temp); + /*301b */ + + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + temp = 0x0028; + SiS_SetReg1 (SiS_Part4Port, 0x1C, temp); + tempax = SiS_VGAHDE; + if (modeflag & HalfDCLK) { + tempax = tempax >> 1; + } + if (SiS_VBInfo & (SetCRT2ToLCD)) { + if (tempax > 800) + tempax = tempax - 800; + } + tempax = tempax - 1; + + if (SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToHiVisionTV)) { + if (SiS_VGAHDE > 800) { + if (SiS_VGAHDE == 1024) + tempax = (tempax * 25 / 32) - 1; + else + tempax = (tempax * 20 / 32) - 1; + } + } + temp = (tempax & 0xFF00) >> 8; + temp = ((temp & 0x0003) << 4); + SiS_SetReg1 (SiS_Part4Port, 0x1E, temp); + temp = (tempax & 0x00FF); + SiS_SetReg1 (SiS_Part4Port, 0x1D, temp); + + if (SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToHiVisionTV)) { + if (SiS_VGAHDE > 800) { + SiS_SetRegOR (SiS_Part4Port, 0x1E, 0x08); + } + } + temp = 0x0036; + if (SiS_VBInfo & SetCRT2ToTV) { + temp = temp | 0x0001; + } + SiS_SetRegANDOR (SiS_Part4Port, 0x1F, 0x00C0, temp); + tempbx = (SiS_HT / 2) - 2; + temp = ((tempbx & 0x0700) >> 8) << 3; + SiS_SetRegANDOR (SiS_Part4Port, 0x21, 0x00C0, temp); + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x22, temp); + } +/*end 301b*/ + SiS_SetCRT2VCLK (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); +} + +void +SiS_SetCRT2VCLK (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT vclkindex; + USHORT tempah, temp1; + + vclkindex = + SiS_GetVCLK2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempah = SiS_VBVCLKData[vclkindex].Part4_A; + SiS_SetReg1 (SiS_Part4Port, 0x0A, tempah); + tempah = SiS_VBVCLKData[vclkindex].Part4_B; + SiS_SetReg1 (SiS_Part4Port, 0x0B, tempah); + } else { + SiS_SetReg1 (SiS_Part4Port, 0x0A, 0x01); + tempah = SiS_VBVCLKData[vclkindex].Part4_B; + SiS_SetReg1 (SiS_Part4Port, 0x0B, tempah); + tempah = SiS_VBVCLKData[vclkindex].Part4_A; + SiS_SetReg1 (SiS_Part4Port, 0x0A, tempah); + + } + SiS_SetReg1 (SiS_Part4Port, 0x12, 0x00); + tempah = 0x08; + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempah = tempah | 0x020; + } + temp1 = SiS_GetReg1 (SiS_Part4Port, 0x12); + tempah = tempah | temp1; + SiS_SetReg1 (SiS_Part4Port, 0x12, tempah); +} + +USHORT +SiS_GetVCLK2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT tempbx; +#ifdef CONFIG_FB_SIS_300 + USHORT LCDXlat1VCLK[4] = { VCLK65, VCLK65, VCLK65, VCLK65 }; + USHORT LCDXlat2VCLK[4] = { VCLK108_2, VCLK108_2, VCLK108_2, VCLK108_2 }; + USHORT LVDSXlat2VCLK[4] = { VCLK65, VCLK65, VCLK65, VCLK65 }; + USHORT LVDSXlat3VCLK[4] = { VCLK65, VCLK65, VCLK65, VCLK65 }; +#else /* SIS315H */ + USHORT LCDXlat1VCLK[4] = + { VCLK65 + 2, VCLK65 + 2, VCLK65 + 2, VCLK65 + 2 }; + USHORT LCDXlat2VCLK[4] = + { VCLK108_2 + 5, VCLK108_2 + 5, VCLK108_2 + 5, VCLK108_2 + 5 }; + USHORT LVDSXlat2VCLK[4] = + { VCLK65 + 2, VCLK65 + 2, VCLK65 + 2, VCLK65 + 2 }; + USHORT LVDSXlat3VCLK[4] = + { VCLK65 + 2, VCLK65 + 2, VCLK65 + 2, VCLK65 + 2 }; +#endif + USHORT LVDSXlat1VCLK[4] = { VCLK40, VCLK40, VCLK40, VCLK40 }; + USHORT CRT2Index, VCLKIndex; + USHORT modeflag, resinfo; + UCHAR *CHTVVCLKPtr = NULL; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + CRT2Index = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT2Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + if (SiS_IF_DEF_LVDS == 0) { + CRT2Index = CRT2Index >> 6; /* for LCD */ + if ((SiS_VBInfo & SetCRT2ToLCD) || (SiS_VBInfo & SetCRT2ToLCDA)) { /*301b */ + if (SiS_LCDResInfo != Panel1024x768) { + VCLKIndex = LCDXlat2VCLK[CRT2Index]; + } else { + VCLKIndex = LCDXlat1VCLK[CRT2Index]; + } + } else { /* for TV */ + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_IF_DEF_HiVision == 1) { + if (SiS_SetFlag & RPLLDIV2XO) { + VCLKIndex = HiTVVCLKDIV2; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } else { + VCLKIndex = HiTVVCLK; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } + if (SiS_SetFlag & TVSimuMode) { + if (modeflag & Charx8Dot) { + VCLKIndex = + HiTVSimuVCLK; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } else { + VCLKIndex = + HiTVTextVCLK; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } + } + } else { + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_SetFlag & RPLLDIV2XO) { + VCLKIndex = TVVCLKDIV2; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } else { + VCLKIndex = TVVCLK; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } + } + } + } else { /* for CRT2 */ + VCLKIndex = + (UCHAR) SiS_GetReg2 ((USHORT) (SiS_P3ca + 0x02)); /* Port 3cch */ + VCLKIndex = ((VCLKIndex >> 2) & 0x03); + if (ModeNo > 0x13) { + VCLKIndex = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; /* di+Ext_CRTVCLK */ + VCLKIndex = VCLKIndex & 0x3f; + } + } + } + } else { /* LVDS */ + if (ModeNo <= 0x13) + VCLKIndex = CRT2Index; + else + VCLKIndex = CRT2Index; + if (SiS_IF_DEF_CH7005 == 1) { + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + VCLKIndex = VCLKIndex & 0x1f; + tempbx = 0; + if (SiS_VBInfo & SetPALTV) + tempbx = tempbx + 2; + if (SiS_VBInfo & SetCHTVOverScan) + tempbx = tempbx + 1; + switch (tempbx) { + case 0: + CHTVVCLKPtr = SiS_CHTVVCLKUNTSC; + break; + case 1: + CHTVVCLKPtr = SiS_CHTVVCLKONTSC; + break; + case 2: + CHTVVCLKPtr = SiS_CHTVVCLKUPAL; + break; + case 3: + CHTVVCLKPtr = SiS_CHTVVCLKOPAL; + break; + } + VCLKIndex = CHTVVCLKPtr[VCLKIndex]; + } + } else { + VCLKIndex = VCLKIndex >> 6; + if (SiS_LCDResInfo == Panel800x600) + VCLKIndex = LVDSXlat1VCLK[VCLKIndex]; + else if (SiS_LCDResInfo == Panel1024x768) + VCLKIndex = LVDSXlat2VCLK[VCLKIndex]; + else + VCLKIndex = LVDSXlat3VCLK[VCLKIndex]; + } + } +/*VCLKIndex=VCLKIndex&0x3F; */ + if (HwDeviceExtension->jChipType < SIS_315H) { /* for300 serial */ + VCLKIndex = VCLKIndex & 0x3F; + } + return (VCLKIndex); +} + +void +SiS_SetGroup5 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex) +{ + USHORT Pindex, Pdata; + + Pindex = SiS_Part5Port; + Pdata = SiS_Part5Port + 1; + if (SiS_ModeType == ModeVGA) { + if (! + (SiS_VBInfo & + (SetInSlaveMode | LoadDACFlag | CRT2DisplayFlag))) { + SiS_EnableCRT2 (); +/* LoadDAC2(ROMAddr,SiS_Part5Port,ModeNo,ModeIdIndex); */ + } + } + return; +} + +void +SiS_LoadDAC2 (ULONG ROMAddr, USHORT SiS_Part5Port, USHORT ModeNo, + USHORT ModeIdIndex) +{ + USHORT data, data2; + USHORT time, i, j, k; + USHORT m, n, o; + USHORT si, di, bx, dl; + USHORT al, ah, dh; + USHORT *table = 0; + USHORT Pindex, Pdata, modeflag; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + Pindex = SiS_Part5Port; + Pdata = SiS_Part5Port + 1; + data = modeflag & DACInfoFlag; + time = 64; + if (data == 0x00) + table = SiS_MDA_DAC; + if (data == 0x08) + table = SiS_CGA_DAC; + if (data == 0x10) + table = SiS_EGA_DAC; + if (data == 0x18) { + time = 256; + table = SiS_VGA_DAC; + } + if (time == 256) + j = 16; + else + j = time; + + SiS_SetReg3 (Pindex, 0x00); + + for (i = 0; i < j; i++) { + data = table[i]; + for (k = 0; k < 3; k++) { + data2 = 0; + if (data & 0x01) + data2 = 0x2A; + if (data & 0x02) + data2 = data2 + 0x15; + SiS_SetReg3 (Pdata, data2); + data = data >> 2; + } + } + + if (time == 256) { + for (i = 16; i < 32; i++) { + data = table[i]; + for (k = 0; k < 3; k++) + SiS_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++; + SiS_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--; + SiS_WriteDAC2 (Pdata, dl, ah, al, dh); + } /* for 3 */ + dl++; + } /* for 3 */ + si = si + 5; + } /* for 9 */ + } +} + +void +SiS_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; + } + } + SiS_SetReg3 (Pdata, (USHORT) dh); + SiS_SetReg3 (Pdata, (USHORT) bh); + SiS_SetReg3 (Pdata, (USHORT) bl); +} + +void +SiS_SetCHTVReg (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT temp, tempbx, tempcl; +/* USHORT CRT2CRTC; */ + USHORT TVType, resindex; + SiS_CHTVRegDataStruct *CHTVRegData = NULL; + + if (ModeNo <= 0x13) { + tempcl = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempcl = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + TVType = 0; + if (SiS_VBInfo & SetPALTV) + TVType = TVType + 2; + if (SiS_VBInfo & SetCHTVOverScan) + TVType = TVType + 1; + switch (TVType) { + case 0: + CHTVRegData = SiS_CHTVReg_UNTSC; + break; + case 1: + CHTVRegData = SiS_CHTVReg_ONTSC; + break; + case 2: + CHTVRegData = SiS_CHTVReg_UPAL; + break; + case 3: + CHTVRegData = SiS_CHTVReg_OPAL; + break; + } + resindex = tempcl & 0x3F; + + if (SiS_VBInfo & SetPALTV) { + SiS_SetCH7005 (0x4304); + SiS_SetCH7005 (0x6909); + } else { + SiS_SetCH7005 (0x0304); + SiS_SetCH7005 (0x7109); + } + + temp = CHTVRegData[resindex].Reg[0]; + tempbx = ((temp & 0x00FF) << 8) | 0x00; + SiS_SetCH7005 (tempbx); + temp = CHTVRegData[resindex].Reg[1]; + tempbx = ((temp & 0x00FF) << 8) | 0x07; + SiS_SetCH7005 (tempbx); + temp = CHTVRegData[resindex].Reg[2]; + tempbx = ((temp & 0x00FF) << 8) | 0x08; + SiS_SetCH7005 (tempbx); + temp = CHTVRegData[resindex].Reg[3]; + tempbx = ((temp & 0x00FF) << 8) | 0x0A; + SiS_SetCH7005 (tempbx); + temp = CHTVRegData[resindex].Reg[4]; + tempbx = ((temp & 0x00FF) << 8) | 0x0B; + SiS_SetCH7005 (tempbx); + + SiS_SetCH7005 (0x2801); + SiS_SetCH7005 (0x3103); + SiS_SetCH7005 (0x003D); + SiS_SetCHTVRegANDOR (0x0010, 0x1F); + SiS_SetCHTVRegANDOR (0x0211, 0xF8); + SiS_SetCHTVRegANDOR (0x001C, 0xEF); + + if (!(SiS_VBInfo & SetPALTV)) { + /* tempcl=CRT2CRTC; */ + tempcl = tempcl & 0x3F; + if (SiS_VBInfo & SetCHTVOverScan) { + if (tempcl == 0x04) { /* 640x480 underscan */ + SiS_SetCHTVRegANDOR (0x0020, 0xEF); + SiS_SetCHTVRegANDOR (0x0121, 0xFE); + } else { + if (tempcl == 0x05) { /* 800x600 underscan */ + SiS_SetCHTVRegANDOR (0x0118, 0xF0); + SiS_SetCHTVRegANDOR (0x0C19, 0xF0); + SiS_SetCHTVRegANDOR (0x001A, 0xF0); + SiS_SetCHTVRegANDOR (0x001B, 0xF0); + SiS_SetCHTVRegANDOR (0x001C, 0xF0); + SiS_SetCHTVRegANDOR (0x001D, 0xF0); + SiS_SetCHTVRegANDOR (0x001E, 0xF0); + SiS_SetCHTVRegANDOR (0x001F, 0xF0); + SiS_SetCHTVRegANDOR (0x0120, 0xEF); + SiS_SetCHTVRegANDOR (0x0021, 0xFE); + } + } + } else { + if (tempcl == 0x04) { /* 640x480 overscan */ + SiS_SetCHTVRegANDOR (0x0020, 0xEF); + SiS_SetCHTVRegANDOR (0x0121, 0xFE); + } else { + if (tempcl == 0x05) { /* 800x600 overscan */ + SiS_SetCHTVRegANDOR (0x0118, 0xF0); + SiS_SetCHTVRegANDOR (0x0F19, 0xF0); + SiS_SetCHTVRegANDOR (0x011A, 0xF0); + SiS_SetCHTVRegANDOR (0x0C1B, 0xF0); + SiS_SetCHTVRegANDOR (0x071C, 0xF0); + SiS_SetCHTVRegANDOR (0x011D, 0xF0); + SiS_SetCHTVRegANDOR (0x0C1E, 0xF0); + SiS_SetCHTVRegANDOR (0x071F, 0xF0); + SiS_SetCHTVRegANDOR (0x0120, 0xEF); + SiS_SetCHTVRegANDOR (0x0021, 0xFE); + } + } + } + } +} + +void +SiS_SetCHTVRegANDOR (USHORT tempax, USHORT tempbh) +{ + USHORT tempal, tempah, tempbl; + + tempal = tempax & 0x00FF; + tempah = (tempax >> 8) & 0x00FF; + tempbl = SiS_GetCH7005 (tempal); + tempbl = (((tempbl & tempbh) | tempah) << 8 | tempal); + SiS_SetCH7005 (tempbl); +} + +void +SiS_SetCH7005 (USHORT tempbx) +{ + USHORT tempah, temp; + + SiS_DDC_Port = 0x3c4; + SiS_DDC_Index = 0x11; + SiS_DDC_DataShift = 0x00; + SiS_DDC_DeviceAddr = 0xEA; + + temp = 1; + for (; temp != 0;) { + SiS_SetSwitchDDC2 (); + SiS_SetStart (); + tempah = SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + tempah = tempbx & 0x00FF; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + tempah = (tempbx & 0xFF00) >> 8; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + SiS_SetStop (); + } +} + +USHORT +SiS_GetCH7005 (USHORT tempbx) +{ + USHORT tempah, temp; + + SiS_DDC_Port = 0x3c4; + SiS_DDC_Index = 0x11; + SiS_DDC_DataShift = 0x00; + SiS_DDC_DeviceAddr = 0xEA; + SiS_DDC_ReadAddr = tempbx; + + for (;;) { + SiS_SetSwitchDDC2 (); + SiS_SetStart (); + tempah = SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + tempah = SiS_DDC_ReadAddr; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + + SiS_SetStart (); + tempah = SiS_DDC_DeviceAddr; + tempah = tempah | 0x01; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + tempah = SiS_ReadDDC2Data (tempah); + SiS_SetStop (); + return (tempah); + } +} + +void +SiS_SetSwitchDDC2 (void) +{ + USHORT i; + + SiS_SetSCLKHigh (); + for (i = 0; i < 1000; i++) { + SiS_GetReg1 (SiS_DDC_Port, 0x05); + } + SiS_SetSCLKLow (); + for (i = 0; i < 1000; i++) { + SiS_GetReg1 (SiS_DDC_Port, 0x05); + } +} + +void +SiS_SetStart (void) +{ + + SiS_SetSCLKLow (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x02); /* SetSDA(0x01); */ + SiS_SetSCLKHigh (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x00); /* SetSDA(0x00); */ + SiS_SetSCLKHigh (); +} + +void +SiS_SetStop (void) +{ + SiS_SetSCLKLow (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x00); /* SetSDA(0x00); */ + SiS_SetSCLKHigh (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x02); /* SetSDA(0x01); */ + SiS_SetSCLKHigh (); +} + +USHORT +SiS_WriteDDC2Data (USHORT tempax) +{ + USHORT i, flag, temp; + + flag = 0x80; + for (i = 0; i < 8; i++) { + SiS_SetSCLKLow (); + if (tempax & flag) { + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, + 0x02); + } else { + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, + 0x00); + } + SiS_SetSCLKHigh (); + flag = flag >> 1; + } + temp = SiS_CheckACK (); + return (temp); +} + +USHORT +SiS_ReadDDC2Data (USHORT tempax) +{ + USHORT i, temp, getdata; + + getdata = 0; + for (i = 0; i < 8; i++) { + getdata = getdata << 1; + SiS_SetSCLKLow (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x02); + SiS_SetSCLKHigh (); + temp = SiS_GetReg1 (SiS_DDC_Port, SiS_DDC_Index); + if (temp & 0x02) + getdata = getdata | 0x01; + } + return (getdata); +} + +void +SiS_SetSCLKLow (void) +{ + USHORT temp; + + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFE, 0x00); /* SetSCLKLow() */ + do { + temp = SiS_GetReg1 (SiS_DDC_Port, SiS_DDC_Index); + } while (temp & 0x01); + SiS_DDC2Delay (); +} + +void +SiS_SetSCLKHigh (void) +{ + USHORT temp; + + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFE, 0x01); /* SetSCLKHigh() */ + do { + temp = SiS_GetReg1 (SiS_DDC_Port, SiS_DDC_Index); + } while (!(temp & 0x01)); + SiS_DDC2Delay (); +} + +void +SiS_DDC2Delay (void) +{ + USHORT i; + + for (i = 0; i < DDC2DelayTime; i++) { + SiS_GetReg1 (SiS_P3c4, 0x05); + } +} + +USHORT +SiS_CheckACK (void) +{ + USHORT tempah; + + SiS_SetSCLKLow (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x02); + SiS_SetSCLKHigh (); + tempah = SiS_GetReg1 (SiS_DDC_Port, SiS_DDC_Index); + SiS_SetSCLKLow (); + if (tempah & 0x02) + return (1); + else + return (0); +} + +void +SiS_ModCRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT temp, tempah, i, modeflag, j; + USHORT ResInfo, DisplayType; + SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + temp = + SiS_GetLVDSCRT1Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &ResInfo, &DisplayType); + if (temp == 0) { + return; + } + + switch (DisplayType) { + case 0: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1; + break; + case 1: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1; + break; + case 2: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1; + break; + case 3: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H; + break; + case 4: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H; + break; + case 5: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H; + break; + case 6: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2; + break; + case 7: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2; + break; + case 8: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2; + break; + case 9: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H; + break; + case 10: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H; + break; + case 11: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H; + break; + case 12: + LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC; + break; + case 13: + LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC; + break; + case 14: + LVDSCRT1Ptr = SiS_CHTVCRT1UPAL; + break; + case 15: + LVDSCRT1Ptr = SiS_CHTVCRT1OPAL; + break; + } + + tempah = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); /*unlock cr0-7 */ + tempah = tempah & 0x7F; + SiS_SetReg1 (SiS_P3d4, 0x11, tempah); + tempah = (LVDSCRT1Ptr + ResInfo)->CR[0]; + SiS_SetReg1 (SiS_P3d4, 0x0, tempah); + for (i = 0x02, j = 1; i <= 0x05; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x06, j = 5; i <= 0x07; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x10, j = 7; i <= 0x11; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x15, j = 9; i <= 0x16; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + + for (i = 0x0A, j = 11; i <= 0x0C; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3c4, i, tempah); + } + + tempah = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempah = tempah & 0x0E0; + SiS_SetReg1 (SiS_P3c4, 0x0E, tempah); + + tempah = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempah = tempah & 0x01; + tempah = tempah << 5; + if (modeflag & DoubleScanMode) { + tempah = tempah | 0x080; + } + SiS_SetRegANDOR (SiS_P3d4, 0x09, ~0x020, tempah); + return; +} + +/*301b*/ +void +SiS_CHACRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT temp, tempah, i, modeflag, j; + USHORT ResInfo, DisplayType; + SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + temp = + SiS_GetLVDSCRT1Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &ResInfo, &DisplayType); + if (temp == 0) { + return; + } + + switch (DisplayType) { + case 0: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1; + break; + case 1: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1; + break; + case 2: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1; + break; + case 3: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H; + break; + case 4: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H; + break; + case 5: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H; + break; + case 6: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2; + break; + case 7: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2; + break; + case 8: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2; + break; + case 9: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H; + break; + case 10: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H; + break; + case 11: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H; + break; + case 12: + LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC; + break; + case 13: + LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC; + break; + case 14: + LVDSCRT1Ptr = SiS_CHTVCRT1UPAL; + break; + case 15: + LVDSCRT1Ptr = SiS_CHTVCRT1OPAL; + break; + } + + tempah = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); /*unlock cr0-7 */ + tempah = tempah & 0x7F; + SiS_SetReg1 (SiS_P3d4, 0x11, tempah); + tempah = (LVDSCRT1Ptr + ResInfo)->CR[0]; + SiS_SetReg1 (SiS_P3d4, 0x0, tempah); + for (i = 0x02, j = 1; i <= 0x05; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x06, j = 5; i <= 0x07; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x10, j = 7; i <= 0x11; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x15, j = 9; i <= 0x16; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + + for (i = 0x0A, j = 11; i <= 0x0C; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3c4, i, tempah); + } + + tempah = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempah = tempah & 0x0E0; + SiS_SetReg1 (SiS_P3c4, 0x0E, tempah); + + tempah = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempah = tempah & 0x01; + tempah = tempah << 5; + if (modeflag & DoubleScanMode) { + tempah = tempah | 0x080; + } + SiS_SetRegANDOR (SiS_P3d4, 0x09, ~0x020, tempah); + return; +} + +/*add for LCDA*/ + +BOOLEAN +SiS_GetLCDACRT1Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * ResInfo, + USHORT * DisplayType) +{ + USHORT tempbx = 0, modeflag = 0; + USHORT CRT2CRTC = 0; + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + tempbx = SiS_LCDResInfo; + tempbx -= Panel800x600; + if (SiS_LCDInfo & LCDNonExpanding) + tempbx += 6; + if (modeflag & HalfDCLK) + tempbx += +3; + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + CRT2CRTC = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + CRT2CRTC = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + } + *ResInfo = CRT2CRTC & 0x3F; + *DisplayType = tempbx; + return 1; +} + +/*end for 301b*/ + +BOOLEAN +SiS_GetLVDSCRT1Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * ResInfo, + USHORT * DisplayType) +{ + USHORT tempbx, modeflag = 0; + USHORT Flag, CRT2CRTC; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + CRT2CRTC = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + CRT2CRTC = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + if (!(SiS_VBInfo & SetInSlaveMode)) { + return 0; + } + Flag = 1; + tempbx = 0; + if (SiS_IF_DEF_CH7005 == 1) { + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + Flag = 0; + tempbx = 12; + if (SiS_VBInfo & SetPALTV) + tempbx += 2; + if (SiS_VBInfo & SetCHTVOverScan) + tempbx += 1; + } + } + if (Flag) { + tempbx = SiS_LCDResInfo; + tempbx -= Panel800x600; + if (SiS_LCDInfo & LCDNonExpanding) + tempbx += 6; + if (modeflag & HalfDCLK) + tempbx += +3; + } + + *ResInfo = CRT2CRTC & 0x3F; + *DisplayType = tempbx; + return 1; +} + +void +SiS_SetCRT2ECLK (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT tempah, tempal; + USHORT P3cc = SiS_P3c9 + 3; + USHORT vclkindex = 0; + + if (SiS_IF_DEF_TRUMPION == 0) { /*no trumpion */ + tempal = SiS_GetReg2 (P3cc); + tempal = tempal & 0x0C; + vclkindex = + SiS_GetVCLK2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + } else { /*trumpion */ + SiS_SetFlag = SiS_SetFlag & (~ProgrammingCRT2); +/* tempal=*((UCHAR *)(ROMAddr+SiS_RefIndex+0x03)); &di+Ext_CRTVCLK */ + tempal = tempal & 0x03F; + if (tempal == 0x02) { /*31.5MHz */ +/* SiS_RefIndex=SiS_RefIndex-Ext2StructSize; */ + } +/* SiS_RefIndex=GetVCLKPtr(ROMAddr,ModeNo); */ + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + } + tempal = 0x02B; + if (!(SiS_VBInfo & SetInSlaveMode)) { + tempal = tempal + 3; + } + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); + tempah = SiS_VCLKData[vclkindex].SR2B; + SiS_SetReg1 (SiS_P3c4, tempal, tempah); + tempal++; + tempah = SiS_VCLKData[vclkindex].SR2C; + SiS_SetReg1 (SiS_P3c4, tempal, tempah); + tempal++; + SiS_SetReg1 (SiS_P3c4, tempal, 0x80); + return; +} + +void +SiS_SetDefCRT2ExtRegs (USHORT BaseAddr) +{ + USHORT temp; + + if (SiS_IF_DEF_LVDS == 0) { + SiS_SetReg1 (SiS_Part1Port, 0x02, 0x40); + SiS_SetReg1 (SiS_Part4Port, 0x10, 0x80); + temp = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x16); + temp = temp & 0xC3; + SiS_SetReg1 (SiS_P3d4, 0x35, temp); + } else { + SiS_SetReg1 (SiS_P3d4, 0x32, 0x02); + SiS_SetReg1 (SiS_Part1Port, 0x02, 0x00); + } +} + +#ifdef CONFIG_FB_SIS_315 +/* + for SIS310 O.E.M. +*/ +/* +--------------------------------------------------------- + LCDResInfo 1 : 800x600 + 2 : 1024x768 + 3 : 1280x1024 + 4 : 1280x960 + 5 : 640x480 + 6 : 1600x1200 + 7 : 1920x1440 + VESA + non-VESA + non-Expanding +--------------------------------------------------------- +*/ +USHORT +GetLCDPtrIndex (void) +{ + USHORT index; + + index = (SiS_LCDResInfo & 0x0F) - 1; + index *= 3; + if (SiS_LCDInfo & LCDNonExpanding) + index += 2; + else { + if (!(SiS_LCDInfo & LCDVESATiming)) + index++; + } + + return index; +} + +/* +--------------------------------------------------------- + GetTVPtrIndex() + return 0 : NTSC Enhanced/Standard + 1 : NTSC Standard TVSimuMode + 2 : PAL Enhanced/Standard + 3 : PAL Standard TVSimuMode + 4 : HiVision Enhanced/Standard + 5 : HiVision Standard TVSimuMode +--------------------------------------------------------- +*/ +USHORT +GetTVPtrIndex (void) +{ + USHORT index; + + index = 0; + if (SiS_VBInfo & SetPALTV) + index++; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) /* Hivision TV use PAL */ + index++; + index *= 2; + + if ((SiS_VBInfo & SetInSlaveMode) && (SiS_SetFlag & TVSimuMode)) + index++; + + return index; +} + +void +SetDelayComp (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part1Port; + USHORT delay, index; + + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + delay = SiS310_CRT2DelayCompensation1; + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + delay = SiS310_CRT2DelayCompensation2; + } else if (SiS_VBInfo & SetCRT2ToLCD) { + index = GetLCDPtrIndex (); + delay = SiS310_LCDDelayCompensation1[index]; + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + delay = SiS310_LCDDelayCompensation2[index]; + } else { + index = GetTVPtrIndex (); + delay = SiS310_TVDelayCompensation1[index]; + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + delay = SiS310_TVDelayCompensation2[index]; + } + + Part1Port = BaseAddr + SIS_CRT2_PORT_04; + SiS_SetRegANDOR (Part1Port, 0x2D, ~0x0F, delay); /* index 2D D[3:0] */ + +} + +/* +*/ +void +SetAntiFlicker (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT Part2Port; + USHORT index, temp; + + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + temp = GetTVPtrIndex (); + temp = (temp >> 1); /* 0: NTSC, 1 :PAL, 2:HiTV */ + if (ModeNo <= 0x13) { + index = SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex; + } else { + index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex; + } + temp = SiS310_TVAntiFlick1[temp][index]; + temp <<= 4; + + SiS_SetRegANDOR (Part2Port, 0x0A, ~0x70, temp); /* index 0A D[6:4] */ + +} + +void +SetEdgeEnhance (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT Part2Port; + USHORT index, temp; + + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + temp = GetTVPtrIndex (); + temp = (temp >> 1); /* 0: NTSC, 1 :PAL, 2:HiTV */ + if (ModeNo <= 0x13) { + index = SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex; /* si+VB_StTVEdgeIndex */ + } else { + index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex; /* si+VB_ExtTVEdgeIndex */ + } + temp = SiS310_TVEdge1[temp][index]; + temp <<= 5; + + SiS_SetRegANDOR (Part2Port, 0x3A, ~0xE0, temp); /* index 0A D[7:5] */ + +} + +void +SetYFilter (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT Part2Port, temp1, temp2; + USHORT index, temp, i, index1; + UCHAR OutputSelect = *pSiS_OutputSelect; + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + temp = GetTVPtrIndex (); + temp >>= 1; /* 0: NTSC, 1 :PAL, 2:HiTV */ + + if (ModeNo <= 0x13) { + index = SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex; + } else { + index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex; + } + + if (SiS_VBInfo & SetCRT2ToHiVisionTV) /* Hivision TV use PAL */ + temp = 0; + + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_TVYFilter2[temp][index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_TVYFilter2[temp][index][(i - 0x48) + + 0x04]); + } + } + /*end 301b */ + else { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_TVYFilter1[temp][index][i - 0x35]); + } + } +/*add PALMN*/ + if (OutputSelect & EnablePALMN) { + index1 = SiS_GetReg1 (SiS_P3d4, 0x31); + temp1 = index1 & 0x01; + index1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp2 = index1 & 0xC0; + if (temp1) { + if (temp2 == 0x40) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_PALMFilter2 + [index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_PALMFilter2 + [index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS310_PALMFilter + [index][i - 0x35]); + } + } + if (temp2 == 0x80) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_PALNFilter2 + [index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_PALNFilter2 + [index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS310_PALNFilter + [index][i - 0x35]); + } + } + } + } + /*end PALMN */ +} + +void +SetPhaseIncr (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, temp, temp1, i; + + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + temp = GetTVPtrIndex (); + /* 0: NTSC Graphics, 1: NTSC Text, 2 :PAL Graphics, 3 :PAL Text, 4:HiTV Graphics 5:HiTV Text */ + index = temp % 2; + temp >>= 1; /* 0: NTSC, 1 :PAL, 2:HiTV */ + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); /*if PALMN Not Set */ + temp1 = temp1 & 0xC0; + if (!temp1) { + for (i = 0x31; i <= 0x34; i++) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) + SiS_SetReg1 (Part2Port, i, + SiS310_TVPhaseIncr2[temp] + [index][i - 0x31]); + else + SiS_SetReg1 (Part2Port, i, + SiS310_TVPhaseIncr1[temp][index][i + - + 0x31]); + } + } +} +void +SiS_OEM310Setting (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + SetDelayComp (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + if (SiS_VBInfo & SetCRT2ToTV) { + SetAntiFlicker (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo, + ModeIdIndex); + SetPhaseIncr (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + SetYFilter (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo, + ModeIdIndex); + SetEdgeEnhance (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo, + ModeIdIndex); + } +} + +#endif + +#ifdef CONFIG_FB_SIS_300 +/* + for SIS300 O.E.M. +*/ + +USHORT +GetRevisionID (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ +#ifdef CONFIG_FB_SIS_300 + ULONG temp1, base; + USHORT temp2 = 0; + /* add to set SR14 */ + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + base = 0x80000008; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 & 0x000000FF; + temp2 = (USHORT) (temp1); + return temp2; + } +#endif +} + +USHORT +GetOEMLCDPtr (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp, tempbx = 0, tempax; + + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToLCD) { /* LCD */ + tempax = SiS_LCDResInfo; + tempbx = SiS_LCDResInfo; + tempbx = tempbx - Panel1024x768; + if (!(SiS_SetFlag & LCDVESATiming)) { + tempbx += 4; + temp = GetRevisionID (HwDeviceExtension); + if ((HwDeviceExtension->jChipType == SIS_540) + && (temp < 1)) + tempbx += 4; + if ((HwDeviceExtension->jChipType == SIS_630) + && (temp < 3)) + tempbx += 4; + } + if ((tempax == Panel1024x768) + && (SiS_LCDInfo == LCDNonExpanding)) { + tempbx = tempbx + 3; + } + /*add OEMLCDPanelIDSupport */ + tempbx = SiS_LCDTypeInfo; + tempbx = tempbx << 1; + if (!(SiS_SetFlag & LCDVESATiming)) + tempbx = tempbx + 1; + } + } + tempbx *= 2; + return tempbx; +} + +USHORT +GetOEMTVPtr (void) +{ + USHORT index; + + index = 0; + if (!(SiS_VBInfo & SetInSlaveMode)) + index = index + 4; + + if (SiS_VBInfo & SetCRT2ToSCART) { + index = index + 2; + } else { + if (SiS_VBInfo & SetCRT2ToHiVisionTV) + index = index + 3; + else { + if (SiS_VBInfo & SetPALTV) + index = index + 1; + } + } + return index; +} + +void +SetOEMTVDelay (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part1Port; + USHORT index, temp, ModeIdIndex; + Part1Port = BaseAddr + SIS_CRT2_PORT_04; + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + temp = GetOEMTVPtr (); + index = SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex; + temp = SiS300_OEMTVDelay[temp][index]; + temp = temp & 0x3c; + SiS_SetRegANDOR (Part1Port, 0x13, ~0x3C, temp); /* index 0A D[6:4] */ +} + +void +SetOEMLCDDelay (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, temp, ModeIdIndex; + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + temp = GetOEMLCDPtr (HwDeviceExtension); + index = SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex; + temp = SiS300_OEMLCDDelay1[temp][index]; + /*add OEMLCDPanelIDSupport */ + temp = SiS300_OEMLCDDelay2[temp][index]; + temp = temp & 0x3c; + SiS_SetRegANDOR (Part2Port, 0x13, ~0x3C, temp); /* index 0A D[6:4] */ +} + +/* +*/ +void +SetOEMAntiFlicker (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, temp; + USHORT ModeIdIndex; + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + temp = GetOEMTVPtr (); + index = SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex; + temp = SiS300_OEMTVFlicker[temp][index]; + temp = temp & 0x70; + SiS_SetRegANDOR (Part2Port, 0x0A, ~0x70, temp); /* index 0A D[6:4] */ + +} + +void +SetOEMPhaseIncr (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, i, ModeIdIndex; + + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + // temp = GetTVPtrIndex(); + /* 0: NTSC Graphics, 1: NTSC Text, 2 :PAL Graphics, 3 :PAL Text, 4:HiTV Graphics 5:HiTV Text */ + // index = temp % 2; + // temp >>= 1; /* 0: NTSC, 1 :PAL, 2:HiTV */ + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + index = SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex; + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StPALPhase[index][i - + 0x31]); + } else { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StNTSCPhase[index][i - + 0x31]); + } + if (SiS_VBInfo & SetCRT2ToSCART) { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StSCARTPhase[index][i - + 0x31]); + } + } else { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtPALPhase[index][i - + 0x31]); + } else { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtNTSCPhase[index][i - + 0x31]); + } + if (SiS_VBInfo & SetCRT2ToSCART) { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtSCARTPhase[index][i - + 0x31]); + } + } +} + +void +SetOEMYFilter (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, temp1, temp2, i, ModeIdIndex, index1; + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + /*301b */ + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + index = SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex; + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StPALFilter[index][i - + 0x35]); + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StNTSCFilter[index][i - + 0x35]); + } + } else { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtPALFilter[index][i - + 0x35]); + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtNTSCFilter[index][i - + 0x35]); + } + } + + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALFilter2[index][i - + 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALFilter2[index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_NTSCFilter2[index][i - + 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_NTSCFilter2[index][ + (i - + 0x48) + + 0x04]); + } + } + } + +/*add PALMN*/ + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + index1 = SiS_GetReg1 (SiS_P3d4, 0x31); + temp1 = index1 & 0x01; + index1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp2 = index1 & 0xC0; + if (temp1) { + if (temp2 == 0x40) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALMFilter2 + [index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALMFilter2 + [index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_PALMFilter + [index][i - 0x35]); + } + } + if (temp2 == 0x80) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALNFilter2 + [index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALNFilter2 + [index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_PALNFilter + [index][i - 0x35]); + } + } + } + } + /*end PALMN */ +} + +void +SiS_OEM300Setting (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + if (SiS_VBInfo & SetCRT2ToLCD) { + SetOEMLCDDelay (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + } + if (SiS_VBInfo & SetCRT2ToTV) { + SetOEMTVDelay (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + SetOEMAntiFlicker (HwDeviceExtension, BaseAddr, ROMAddr, + ModeNo); + /* SetOEMPhaseIncr(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo); */ + SetOEMYFilter (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + } +} +#endif diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h new file mode 100644 index 000000000000..557a7cd7605d --- /dev/null +++ b/drivers/video/sis/init301.h @@ -0,0 +1,223 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */ +#ifndef _INIT301_ +#define _INIT301_ + +#include "osdef.h" +#include "initdef.h" +#include "vgatypes.h" +#include "vstruct.h" + +#include +#include +#include + +USHORT SiS_SetFlag; +USHORT SiS_RVBHCFACT, SiS_RVBHCMAX, SiS_RVBHRS; +USHORT SiS_VGAVT, SiS_VGAHT; +USHORT SiS_VT, SiS_HT; +USHORT SiS_VGAVDE, SiS_VGAHDE; +USHORT SiS_VDE, SiS_HDE; +USHORT SiS_NewFlickerMode, SiS_RY1COE, SiS_RY2COE, SiS_RY3COE, SiS_RY4COE; +USHORT SiS_LCDHDES, SiS_LCDVDES; +USHORT SiS_DDC_Port; +USHORT SiS_DDC_Index; +USHORT SiS_DDC_DataShift; +USHORT SiS_DDC_DeviceAddr; +USHORT SiS_DDC_Flag; +USHORT SiS_DDC_ReadAddr; +USHORT SiS_DDC_Buffer; + +extern USHORT SiS_CRT1Mode; +extern USHORT SiS_P3c4, SiS_P3d4; +/*extern USHORT SiS_P3c0,SiS_P3ce,SiS_P3c2;*/ +extern USHORT SiS_P3ca; +/*extern USHORT SiS_P3c6,SiS_P3c7,SiS_P3c8;*/ +extern USHORT SiS_P3c9; +extern USHORT SiS_P3da; +extern USHORT SiS_Part1Port, SiS_Part2Port; +extern USHORT SiS_Part3Port, SiS_Part4Port, SiS_Part5Port; +extern USHORT SiS_MDA_DAC[]; +extern USHORT SiS_CGA_DAC[]; +extern USHORT SiS_EGA_DAC[]; +extern USHORT SiS_VGA_DAC[]; +extern USHORT SiS_ModeType; +extern USHORT SiS_SelectCRT2Rate; +extern USHORT SiS_IF_DEF_LVDS; +extern USHORT SiS_IF_DEF_TRUMPION; +extern USHORT SiS_IF_DEF_CH7005; +extern USHORT SiS_IF_DEF_HiVision; +extern USHORT SiS_IF_DEF_DSTN; /*add for dstn */ +extern USHORT SiS_VBInfo; +extern USHORT SiS_VBType; /*301b */ +extern USHORT SiS_LCDResInfo; +extern USHORT SiS_LCDTypeInfo; +extern USHORT SiS_LCDInfo; +extern BOOLEAN SiS_SearchVBModeID (ULONG, USHORT); +extern BOOLEAN SiS_Is301B (USHORT BaseAddr); /*301b */ +extern BOOLEAN SiS_IsDisableCRT2 (USHORT BaseAddr); +extern BOOLEAN SiS_IsVAMode (USHORT BaseAddr); +extern BOOLEAN SiS_IsDualEdge (USHORT BaseAddr); +/*end 301b*/ + +void SiS_SetDefCRT2ExtRegs (USHORT BaseAddr); +USHORT SiS_GetRatePtrCRT2 (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +BOOLEAN SiS_AjustCRT2Rate (ULONG ROMAddr, USHORT ModeNo, USHORT MODEIdIndex, + USHORT RefreshRateTableIndex, USHORT * i); +void SiS_SaveCRT2Info (USHORT ModeNo); +void SiS_GetCRT2Data (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_GetCRT2DataLVDS (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_GetCRT2PtrA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * CRT2Index, USHORT * ResIndex); /*301b */ +void SiS_GetCRT2Data301 (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +USHORT SiS_GetResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_GetCRT2ResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_GetRAMDAC2DATA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_GetCRT2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * CRT2Index, + USHORT * ResIndex); +void SiS_SetCRT2ModeRegs (USHORT BaseAddr, USHORT ModeNo, PSIS_HW_DEVICE_INFO); + +void SiS_GetLVDSDesData (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_SetCRT2Offset (USHORT Part1Port, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +USHORT SiS_GetOffset (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +USHORT SiS_GetColorDepth (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +USHORT SiS_GetVCLK (ULONG ROMAddr, USHORT ModeNo); +USHORT SiS_GetVCLKPtr (ULONG ROMAddr, USHORT ModeNo); +USHORT SiS_GetColorTh (ULONG ROMAddr); +USHORT SiS_GetMCLK (ULONG ROMAddr); +USHORT SiS_GetMCLKPtr (ULONG ROMAddr); +USHORT SiS_GetDRAMType (ULONG ROMAddr); +USHORT SiS_CalcDelayVB (void); +extern USHORT SiS_GetVCLK2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetCRT2Sync (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT RefreshRateTableIndex); +void SiS_SetRegANDOR (USHORT Port, USHORT Index, USHORT DataAND, USHORT DataOR); +void SiS_SetRegOR (USHORT Port, USHORT Index, USHORT DataOR); +void SiS_SetRegAND (USHORT Port, USHORT Index, USHORT DataAND); +USHORT SiS_GetVGAHT2 (void); +void SiS_SetGroup2 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetGroup3 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetGroup4 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetGroup5 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex); +void SiS_SetCRT2VCLK (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_EnableCRT2 (void); +void SiS_LoadDAC2 (ULONG ROMAddr, USHORT Part5Port, USHORT ModeNo, + USHORT ModeIdIndex); +void SiS_WriteDAC2 (USHORT Pdata, USHORT dl, USHORT ah, USHORT al, USHORT dh); +void SiS_GetVBInfo301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +BOOLEAN SiS_GetLCDResInfo (ULONG ROMAddr, USHORT P3d4, USHORT ModeNo, + USHORT ModeIdIndex); +BOOLEAN SiS_BridgeIsOn (USHORT BaseAddr); +BOOLEAN SiS_BridgeIsEnable (USHORT BaseAddr, PSIS_HW_DEVICE_INFO); +BOOLEAN SiS_BridgeInSlave (void); +/*void SiS_PresetScratchregister(USHORT P3d4);*/ +void SiS_PresetScratchregister (USHORT SiS_P3d4, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetTVSystem (VOID); +void SiS_LongWait (VOID); +USHORT SiS_GetQueueConfig (VOID); +void SiS_VBLongWait (VOID); +USHORT SiS_GetVCLKLen (ULONG ROMAddr); +BOOLEAN SiS_WaitVBRetrace (USHORT BaseAddr); +void SiS_SetCRT2ECLK (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_GetLVDSDesPtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * PanelIndex, + USHORT * ResIndex); +void SiS_GetLVDSDesPtrA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * PanelIndex, + USHORT * ResIndex); /*301b */ +void SiS_SetTPData (VOID); +void SiS_ModCRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +extern BOOLEAN SiS_GetLVDSCRT1Ptr (ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + USHORT * ResInfo, USHORT * DisplayType); +void SiS_SetCHTVReg (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_SetCHTVRegANDOR (USHORT tempax, USHORT tempbh); +void SiS_GetCHTVRegPtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_SetCH7005 (USHORT tempax); +USHORT SiS_GetCH7005 (USHORT tempax); +void SiS_SetSwitchDDC2 (void); +void SiS_SetStart (void); +void SiS_SetStop (void); +void SiS_DDC2Delay (void); +void SiS_SetSCLKLow (void); +void SiS_SetSCLKHigh (void); +USHORT SiS_ReadDDC2Data (USHORT tempax); +USHORT SiS_WriteDDC2Data (USHORT tempax); +USHORT SiS_CheckACK (void); +void SiS_OEM310Setting (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_OEM300Setting (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo); +USHORT GetRevisionID (PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern void SiS_SetReg1 (USHORT, USHORT, USHORT); +extern void SiS_SetReg3 (USHORT, USHORT); +extern UCHAR SiS_GetReg1 (USHORT, USHORT); +extern UCHAR SiS_GetReg2 (USHORT); +extern BOOLEAN SiS_SearchModeID (ULONG ROMAddr, USHORT ModeNo, + USHORT * ModeIdIndex); +extern BOOLEAN SiS_GetRatePtr (ULONG, USHORT); +extern void SiS_SetReg4 (USHORT, ULONG); +extern ULONG SiS_GetReg3 (USHORT); +extern void SiS_DisplayOff (void); +extern void SiS_CRT2AutoThreshold (USHORT BaseAddr); +extern void SiS_DisplayOn (void); +extern UCHAR SiS_GetModePtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +extern UCHAR SiS_Get310DRAMType (ULONG ROMAddr); + +BOOLEAN SiS_SetCRT2Group301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetGroup1 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex); +void SiS_SetGroup1_LVDS (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex); +void SiS_SetGroup1_LCDA (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT RefreshRateTableIndex); /*301b */ +void SiS_SetGroup1_301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex); +void SiS_SetCRT2FIFO (USHORT Part1Port, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetCRT2FIFO2 (USHORT Part1Port, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +BOOLEAN SiS_GetLCDDDCInfo (PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_UnLockCRT2 (PSIS_HW_DEVICE_INFO, USHORT BaseAddr); +void SiS_LockCRT2 (PSIS_HW_DEVICE_INFO, USHORT BaseAddr); +void SiS_DisableBridge (PSIS_HW_DEVICE_INFO, USHORT BaseAddr); +void SiS_EnableBridge (PSIS_HW_DEVICE_INFO, USHORT BaseAddr); +void SiS_SetPanelDelay (USHORT DelayTime); +void SiS_LCD_Wait_Time (UCHAR DelayTime); + +#endif diff --git a/drivers/video/sis/initdef.h b/drivers/video/sis/initdef.h index e0ab914ec7ae..4d6247fd479a 100644 --- a/drivers/video/sis/initdef.h +++ b/drivers/video/sis/initdef.h @@ -1,138 +1,312 @@ -#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 +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/initdef.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */ +#ifndef _INITDEF_ +#define _INITDEF_ + +#define SiS300 0x0300 +#define SiS540 0x5300 +#define SiS630 0x6300 +#define SiS730 0x6300 +#define VB_SIS301 0x0001 /*301b */ +#define VB_SIS301B 0x0002 +#define VB_SIS302B 0x0004 +#define VB_NoLCD 0x8000 -#define SoftDRAMType 0x80 //5/19/2000,Mars,for soft setting dram type -#define SoftSettingAddr 0x52 -#define ModeSettingAddr 0x53 +/*end 301b*/ +#define CRT1Len 17 +#define LVDSCRT1Len 15 +#define CHTVRegDataLen 5 -#define InterlaceMode 0x80 -#define HalfDCLK 0x1000 -#define DACInfoFlag 0x18 -#define LineCompareOff 0x400 -#define ActivePAL 0x20 -#define ActivePALShift 5 +#define ModeInfoFlag 0x07 +#define IsTextMode 0x07 +#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 DACInfoFlag 0x18 +#define MemoryInfoFlag 0x1E0 +#define MemorySizeShift 0x05 - -#define SelectCRT2Rate 0x4 -#define ProgrammingCRT2 0x1 -#define CRT2DisplayFlag 0x2000 -#define SetCRT2ToRAMDAC 0x0040 #define Charx8Dot 0x0200 -#define LCDDataLen 8 +#define LineCompareOff 0x0400 +#define CRT2Mode 0x0800 +#define HalfDCLK 0x1000 +#define NoSupportSimuTV 0x2000 +#define DoubleScanMode 0x8000 + +#define SupportAllCRT2 0x0078 +#define SupportTV 0x0008 +#define SupportHiVisionTV 0x0010 +#define SupportLCD 0x0020 +#define SupportRAMDAC2 0x0040 +#define NoSupportTV 0x0070 +#define NoSupportHiVisionTV 0x0060 +#define NoSupportLCD 0x0058 +#define SupportCHTV 0x0800 +#define SupportTV1024 0x0800 /*301b */ +#define InterlaceMode 0x0080 +#define SyncPP 0x0000 +#define SyncPN 0x4000 +#define SyncNP 0x8000 +#define SyncNN 0xc000 +#define ECLKindex0 0x0000 +#define ECLKindex1 0x0100 +#define ECLKindex2 0x0200 +#define ECLKindex3 0x0300 +#define ECLKindex4 0x0400 + +#define SetSimuScanMode 0x0001 +#define SwitchToCRT2 0x0002 +#define SetCRT2ToTV 0x009C +#define SetCRT2ToAVIDEO 0x0004 +#define SetCRT2ToSVIDEO 0x0008 +#define SetCRT2ToSCART 0x0010 #define SetCRT2ToLCD 0x0020 +#define SetCRT2ToRAMDAC 0x0040 #define SetCRT2ToHiVisionTV 0x0080 -#define HiTVDataLen 12 -#define TVDataLen 16 +#define SetNTSCTV 0x0000 #define SetPALTV 0x0100 #define SetInSlaveMode 0x0200 -#define SetCRT2ToTV 0x009C +#define SetNotSimuMode 0x0400 #define SetNotSimuTVMode 0x0400 -#define SetSimuScanMode 0x0001 +#define SetDispDevSwitch 0x0800 +#define LoadDACFlag 0x1000 +#define DisableCRT2Display 0x2000 #define DriverMode 0x4000 -#define CRT2Mode 0x0800 -//#define ReIndexEnhLCD 4 +#define HotKeySwitch 0x8000 +#define SetCHTVOverScan 0x8000 +#define SetCRT2ToLCDA 0x8000 /*301b */ +#define PanelRGB18Bit 0x0100 +#define PanelRGB24Bit 0x0000 + +#define TVOverScan 0x10 +#define TVOverScanShift 4 +#define ClearBufferFlag 0x20 +#define EnableDualEdge 0x01 /*301b */ +#define SetToLCDA 0x02 + +#define SetSCARTOutput 0x01 +#define BoardTVType 0x02 +#define EnablePALMN 0x40 +#define ProgrammingCRT2 0x01 +#define TVSimuMode 0x02 +#define RPLLDIV2XO 0x04 +#define LCDVESATiming 0x08 +#define EnableLVDSDDA 0x10 +#define SetDispDevSwitchFlag 0x20 +#define CheckWinDos 0x40 +#define SetJDOSMode 0x80 + +#define Panel800x600 0x01 +#define Panel1024x768 0x02 +#define Panel1280x1024 0x03 +#define Panel1280x960 0x04 +#define Panel640x480 0x05 +#define Panel1600x1200 0x06 /*301b */ +#define LCDRGB18Bit 0x01 +#define ExtChipType 0x0e +#define ExtChip301 0x02 +#define ExtChipLVDS 0x04 +#define ExtChipTrumpion 0x06 +#define ExtChipCH7005 0x08 +#define ExtChipMitacTV 0x0a +#define LCDNonExpanding 0x10 +#define LCDNonExpandingShift 4 +#define LCDSync 0x20 +#define LCDSyncBit 0xe0 +#define LCDSyncShift 6 + +#define DDC2DelayTime 300 + +#define CRT2DisplayFlag 0x2000 +#define LCDDataLen 8 +#define HiTVDataLen 12 +#define TVDataLen 16 +#define SetPALTV 0x0100 #define HalfDCLK 0x1000 -//#define HiVisionTVHT 2100 -//#define HiVisionTVVT 2100 #define NTSCHT 1716 #define NTSCVT 525 #define PALHT 1728 #define PALVT 625 +#define StHiTVHT 892 +#define StHiTVVT 1126 +#define StHiTextTVHT 1000 +#define StHiTextTVVT 1126 +#define ExtHiTVHT 2100 +#define ExtHiTVVT 1125 -#define VCLKStartFreq 25 -//Freq of first item in VCLKTable - +#define VCLKStartFreq 25 #define SoftDramType 0x80 +#define VCLK40 0x04 #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 HiTVVCLKDIV2 0x023 +#define HiTVVCLK 0x024 +#define HiTVSimuVCLK 0x025 +#define HiTVTextVCLK 0x026 #define SwitchToCRT2 0x0002 #define LCDVESATiming 0x08 #define SetSCARTOutput 0x01 +#define AVIDEOSense 0x01 +#define SVIDEOSense 0x02 #define SCARTSense 0x04 +#define LCDSense 0x08 #define Monitor1Sense 0x20 #define Monitor2Sense 0x10 -#define SVIDEOSense 0x02 -#define AVIDEOSense 0x01 -#define LCDSense 0x08 +#define HiTVSense 0x40 #define BoardTVType 0x02 #define HotPlugFunction 0x08 #define StStructSize 0x06 -#define ExtChip301 0x02 -#define ExtChipLVDS 0x04 -#define ExtChipTrumpion 0x06 +#define SIS_CRT2_PORT_04 0x04 - 0x030 +#define SIS_CRT2_PORT_10 0x10 - 0x30 +#define SIS_CRT2_PORT_12 0x12 - 0x30 +#define SIS_CRT2_PORT_14 0x14 - 0x30 + #define LCDNonExpanding 0x10 -#define LCDNonExpandingShift 4 +#define ADR_CRT2PtrData 0x20E +#define offset_Zurac 0x210 +#define ADR_LVDSDesPtrData 0x212 +#define ADR_LVDSCRT1DataPtr 0x214 +#define ADR_CHTVVCLKPtr 0x216 +#define ADR_CHTVRegDataPtr 0x218 + #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 +#define ActiveNonExpanding 0x40 +#define ActiveNonExpandingShift 6 +#define ActivePAL 0x20 +#define ActivePALShift 5 +#define ModeSwitchStatus 0x0F +#define SoftTVType 0x40 +#define SoftSettingAddr 0x52 +#define ModeSettingAddr 0x53 + +#define SelectCRT1Rate 0x4 + +#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 + +#define PRIMARY_VGA 0 /* 1: SiS is primary vga 0:SiS is secondary vga */ +#define BIOSIDCodeAddr 0x235 +#define OEMUtilIDCodeAddr 0x237 +#define VBModeIDTableAddr 0x239 +#define OEMTVPtrAddr 0x241 +#define PhaseTableAddr 0x243 +#define NTSCFilterTableAddr 0x245 +#define PALFilterTableAddr 0x247 +#define OEMLCDPtr_1Addr 0x249 +#define OEMLCDPtr_2Addr 0x24B +#define LCDHPosTable_1Addr 0x24D +#define LCDHPosTable_2Addr 0x24F +#define LCDVPosTable_1Addr 0x251 +#define LCDVPosTable_2Addr 0x253 +#define OEMLCDPIDTableAddr 0x255 + +#define VBModeStructSize 5 +#define PhaseTableSize 4 +#define FilterTableSize 4 +#define LCDHPosTableSize 7 +#define LCDVPosTableSize 5 +#define OEMLVDSPIDTableSize 4 +#define LVDSHPosTableSize 4 +#define LVDSVPosTableSize 6 + +#define VB_ModeID 0 +#define VB_TVTableIndex 1 +#define VB_LCDTableIndex 2 +#define VB_LCDHIndex 3 +#define VB_LCDVIndex 4 + +#define OEMLCDEnable 0x0001 +#define OEMLCDDelayEnable 0x0002 +#define OEMLCDPOSEnable 0x0004 +#define OEMTVEnable 0x0100 +#define OEMTVDelayEnable 0x0200 +#define OEMTVFlickerEnable 0x0400 +#define OEMTVPhaseEnable 0x0800 +#define OEMTVFilterEnable 0x1000 + +#define OEMLCDPanelIDSupport 0x0080 + +/* ============================================================= + for 310 +============================================================== */ +#define SoftDRAMType 0x80 +#define SoftSetting_OFFSET 0x52 +#define SR07_OFFSET 0x7C +#define SR15_OFFSET 0x7D +#define SR16_OFFSET 0x81 +#define SR17_OFFSET 0x85 +#define SR19_OFFSET 0x8D +#define SR1F_OFFSET 0x99 +#define SR21_OFFSET 0x9A +#define SR22_OFFSET 0x9B +#define SR23_OFFSET 0x9C +#define SR24_OFFSET 0x9D +#define SR25_OFFSET 0x9E +#define SR31_OFFSET 0x9F +#define SR32_OFFSET 0xA0 +#define SR33_OFFSET 0xA1 + +#define CR40_OFFSET 0xA2 +#define SR25_1_OFFSET 0xF6 +#define CR49_OFFSET 0xF7 + +#define VB310Data_1_2_Offset 0xB6 +#define VB310Data_4_D_Offset 0xB7 +#define VB310Data_4_E_Offset 0xB8 +#define VB310Data_4_10_Offset 0xBB + +#define RGBSenseDataOffset 0xBD +#define YCSenseDataOffset 0xBF +#define VideoSenseDataOffset 0xC1 +#define OutputSelectOffset 0xF3 + +#define ECLK_MCLK_DISTANCE 0x14 +#define VBIOSTablePointerStart 0x100 +#define StandTablePtrOffset VBIOSTablePointerStart+0x02 +#define EModeIDTablePtrOffset VBIOSTablePointerStart+0x04 +#define CRT1TablePtrOffset VBIOSTablePointerStart+0x06 +#define ScreenOffsetPtrOffset VBIOSTablePointerStart+0x08 +#define VCLKDataPtrOffset VBIOSTablePointerStart+0x0A +#define MCLKDataPtrOffset VBIOSTablePointerStart+0x0E +#define CRT2PtrDataPtrOffset VBIOSTablePointerStart+0x10 +#define TVAntiFlickPtrOffset VBIOSTablePointerStart+0x12 +#define TVDelayPtr1Offset VBIOSTablePointerStart+0x14 +#define TVPhaseIncrPtr1Offset VBIOSTablePointerStart+0x16 +#define TVYFilterPtr1Offset VBIOSTablePointerStart+0x18 +#define LCDDelayPtr1Offset VBIOSTablePointerStart+0x20 +#define TVEdgePtr1Offset VBIOSTablePointerStart+0x24 +#define CRT2Delay1Offset VBIOSTablePointerStart+0x28 +#endif diff --git a/drivers/video/sis/oem300.h b/drivers/video/sis/oem300.h new file mode 100644 index 000000000000..0d42507b7ee8 --- /dev/null +++ b/drivers/video/sis/oem300.h @@ -0,0 +1,397 @@ +UCHAR SiS300_TVEdge1[3][2] = { + {0x0, 0x4}, + {0x0, 0x4}, + {0x0, 0x0} +}; + +UCHAR SiS300_OEMTVDelay[8][4] = { + {0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08}, + {0x2c, 0x2c, 0x2c, 0x2c}, + {0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08}, + {0x20, 0x20, 0x20, 0x20} +}; + +UCHAR SiS300_OEMTVFlicker[8][4] = { + {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} +}; + +UCHAR SiS300_OEMLCDDelay1[12][4] = { + {0x2c, 0x2c, 0x2c, 0x2c}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x2c, 0x2c, 0x2c, 0x2c}, + {0x2c, 0x2c, 0x2c, 0x2c}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x24, 0x24, 0x24, 0x24}, + {0x24, 0x24, 0x24, 0x24}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x24, 0x24, 0x24, 0x24} +}; + +UCHAR SiS300_OEMLCDDelay2[32][4] = { + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20} +}; + +UCHAR SiS300_StNTSCPhase[6][4] = { + {0x21, 0xed, 0x00, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StPALPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StSCARTPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StHiTVPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtNTSCPhase[6][4] = { + {0x21, 0xed, 0x00, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtPALPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtSCARTPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtHiTVPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StNTSCFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StPALFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StSCARTFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StHiTVFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtNTSCFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtPALFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtSCARTFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtHiTVFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_NTSCFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +UCHAR SiS300_PALFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +UCHAR SiS300_PALMFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_PALNFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_PALMFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +UCHAR SiS300_PALNFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; diff --git a/drivers/video/sis/oem310.h b/drivers/video/sis/oem310.h new file mode 100644 index 000000000000..327129b7f83d --- /dev/null +++ b/drivers/video/sis/oem310.h @@ -0,0 +1,204 @@ +UCHAR SiS310_CRT2DelayCompensation1 = 0x4; /* 301A */ + +UCHAR SiS310_LCDDelayCompensation1[] = { + 0x0, 0x0, 0x0, 0xb, 0xb, 0xb, 0x8, 0x8, + 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +UCHAR SiS310_TVDelayCompensation1[] = { 0x2, 0x2, 0x2, 0x2, 0x8, 0xb }; +UCHAR SiS310_CRT2DelayCompensation2 = 0xC; /* 301B */ +UCHAR SiS310_LCDDelayCompensation2[] = { + 0x0, 0x0, 0x0, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x8, 0x8, 0x8, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +UCHAR SiS310_TVDelayCompensation2[] = { 0x3, 0x3, 0x3, 0x3, 0x8, 0xb }; + +UCHAR SiS310_TVAntiFlick1[3][2] = { + {0x4, 0x0}, + {0x4, 0x8}, + {0x0, 0x0} +}; + +UCHAR SiS310_TVEdge1[3][2] = { + {0x0, 0x4}, + {0x0, 0x4}, + {0x0, 0x0} +}; + +UCHAR SiS310_TVYFilter1[3][8][4] = { + { + {0x0, 0xf4, 0x10, 0x38}, + {0x0, 0xf4, 0x10, 0x38}, + {0xeb, 0x4, 0x25, 0x18}, + {0xf7, 0x6, 0x19, 0x14}, + {0x0, 0xf4, 0x10, 0x38}, + {0xeb, 0x4, 0x25, 0x18}, + {0xee, 0xc, 0x22, 0x8}, + {0xeb, 0x15, 0x25, 0xf6} + } + , + { + {0x0, 0xf4, 0x10, 0x38}, + {0x0, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf3, 0x0, 0x1d, 0x20}, + {0x0, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf3, 0x0, 0x1d, 0x20}, + {0xfc, 0xfb, 0x14, 0x2a} + } + , + { + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0xf4, 0x10, 0x38}, + {0x0, 0xf4, 0x10, 0x38}, + {0xeb, 0x4, 0x25, 0x18}, + {0xf7, 0x6, 0x19, 0x14}, + {0x0, 0xf4, 0x10, 0x38}, + {0xeb, 0x4, 0x25, 0x18}, + {0xee, 0xc, 0x22, 0x8} + } +}; + +/*301b*/ +UCHAR SiS310_TVYFilter2[3][9][7] = { + { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} + } + , + { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} + } + , + { + + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22} + } +}; +/*end 301b*/ +/*add PALMN*/ + +UCHAR SiS310_PALMFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS310_PALNFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS310_PALMFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +UCHAR SiS310_PALNFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +/*end PALMN*/ +UCHAR SiS310_TVPhaseIncr1[3][2][4] = { + { + {0x21, 0xed, 0x8a, 0x8}, + {0x21, 0xed, 0x8a, 0x8} + } + , + { + {0x2a, 0x5, 0xd3, 0x0}, + {0x2a, 0x5, 0xd3, 0x0} + } + , + { + {0x2a, 0x5, 0xd3, 0x0}, + {0x2a, 0x5, 0xd3, 0x0} + } +}; + +UCHAR SiS310_TVPhaseIncr2[3][2][4] = { + { + {0x21, 0xF0, 0x7b, 0xd6}, + {0x21, 0xF0, 0x7b, 0xd6} + } + , + { + {0x2a, 0x09, 0x86, 0xe9}, + {0x2a, 0x09, 0x86, 0xe9} + } + , + { + {0x2a, 0x5, 0xd3, 0x0}, + {0x2a, 0x5, 0xd3, 0x0} + } +}; diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h new file mode 100644 index 000000000000..1c3ad2b40f20 --- /dev/null +++ b/drivers/video/sis/osdef.h @@ -0,0 +1,37 @@ +#define LINUX_KERNEL + +#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) +#define SiS_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length) + +/**********************************************************************/ + +#ifdef OutPortByte +#undef OutPortByte +#endif /* OutPortByte */ + +#ifdef OutPortWord +#undef OutPortWord +#endif /* OutPortWord */ + +#ifdef OutPortLong +#undef OutPortLong +#endif /* OutPortLong */ + +#ifdef InPortByte +#undef InPortByte +#endif /* InPortByte */ + +#ifdef InPortWord +#undef InPortWord +#endif /* InPortWord */ + +#ifdef InPortLong +#undef InPortLong +#endif /* InPortLong */ + +#define OutPortByte(p,v) outb((u8)(v),(u16)(p)) +#define OutPortWord(p,v) outw((u16)(v),(u16)(p)) +#define OutPortLong(p,v) outl((u32)(v),(u16)(p)) +#define InPortByte(p) inb((u16)(p)) +#define InPortWord(p) inw((u16)(p)) +#define InPortLong(p) inl((u16)(p)) diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h deleted file mode 100644 index 3f4843a77db1..000000000000 --- a/drivers/video/sis/sis.h +++ /dev/null @@ -1,64 +0,0 @@ -#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 deleted file mode 100644 index 5fbbee13b0bb..000000000000 --- a/drivers/video/sis/sis_300.c +++ /dev/null @@ -1,1524 +0,0 @@ -/* Recently Update by v1.09.50 */ -#include -#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 */ diff --git a/drivers/video/sis/sis_300.h b/drivers/video/sis/sis_300.h deleted file mode 100644 index c7f89e4547de..000000000000 --- a/drivers/video/sis/sis_300.h +++ /dev/null @@ -1,163 +0,0 @@ -#include -#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); diff --git a/drivers/video/sis/sis_301.c b/drivers/video/sis/sis_301.c deleted file mode 100644 index 195fd28f1e4a..000000000000 --- a/drivers/video/sis/sis_301.c +++ /dev/null @@ -1,2868 +0,0 @@ -/* Recently Update by v1.09.50 */ - -#include -#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 diff --git a/drivers/video/sis/sis_301.h b/drivers/video/sis/sis_301.h deleted file mode 100644 index 5b189551c576..000000000000 --- a/drivers/video/sis/sis_301.h +++ /dev/null @@ -1,224 +0,0 @@ -#include -#include "initdef.h" - -USHORT SetFlag,RVBHCFACT,RVBHCMAX,VGAVT,VGAHT,VT,HT,VGAVDE,VGAHDE; -USHORT VDE,HDE,RVBHRS,NewFlickerMode,RY1COE,RY2COE,RY3COE,RY4COE; -extern 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 index 20aceea7ec66..828f6f8d3755 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -1,5 +1,5 @@ /* - * SiS 300/630/540 frame buffer device For Kernal 2.4.x + * SiS 300/630/540/315H/315 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 @@ -8,7 +8,7 @@ * */ -#undef SISFBDEBUG +//#undef SISFBDEBUG #include #include @@ -27,10 +27,13 @@ #include #include #include -#include #include +#include +#include +#include #include +#include #include