Merge master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa-current
authorLinus Torvalds <torvalds@g5.osdl.org>
Tue, 13 Sep 2005 16:46:22 +0000 (09:46 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 13 Sep 2005 16:46:22 +0000 (09:46 -0700)
405 files changed:
Documentation/aoe/mkshelf.sh
Documentation/cciss.txt
Documentation/connector/cn_test.c [new file with mode: 0644]
Documentation/connector/connector.txt [new file with mode: 0644]
Documentation/dontdiff
Documentation/fb/intel810.txt
Documentation/feature-removal-schedule.txt
Documentation/firmware_class/firmware_sample_driver.c
Documentation/input/appletouch.txt [new file with mode: 0644]
Documentation/kdump/kdump.txt
Documentation/kernel-parameters.txt
Documentation/oops-tracing.txt
Documentation/pm.txt
Documentation/scsi/00-INDEX
Documentation/scsi/scsi_eh.txt [new file with mode: 0644]
Documentation/usb/proc_usb_info.txt
Documentation/x86_64/boot-options.txt
MAINTAINERS
Makefile
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/corgi_lcd.c
arch/arm/mach-pxa/corgi_ssp.c
arch/arm/mach-pxa/sharpsl.h [new file with mode: 0644]
arch/arm/mach-pxa/spitz.c [new file with mode: 0644]
arch/i386/kernel/acpi/earlyquirk.c
arch/i386/kernel/entry.S
arch/i386/kernel/io_apic.c
arch/i386/kernel/reboot.c
arch/i386/kernel/setup.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/srat.c
arch/i386/pci/acpi.c
arch/i386/pci/mmconfig.c
arch/ia64/ia32/sys_ia32.c
arch/m68knommu/platform/68328/head-de2.S [new file with mode: 0644]
arch/m68knommu/platform/68360/head-ram.S [new file with mode: 0644]
arch/m68knommu/platform/68360/head-rom.S [new file with mode: 0644]
arch/ppc/kernel/temp.c
arch/ppc/kernel/time.c
arch/ppc/kernel/vmlinux.lds.S
arch/ppc/platforms/chrp_time.c
arch/ppc/syslib/prep_nvram.c
arch/ppc64/kernel/iSeries_pci.c
arch/ppc64/kernel/maple_pci.c
arch/ppc64/kernel/pSeries_setup.c
arch/ppc64/kernel/pSeries_smp.c
arch/ppc64/kernel/pci.c
arch/ppc64/kernel/pmac_pci.c
arch/ppc64/kernel/pmac_setup.c
arch/ppc64/kernel/process.c
arch/ppc64/kernel/ptrace.c
arch/ppc64/kernel/ptrace32.c
arch/ppc64/kernel/ras.c
arch/ppc64/kernel/setup.c
arch/ppc64/kernel/signal.c
arch/ppc64/kernel/signal32.c
arch/ppc64/kernel/xics.c
arch/ppc64/mm/fault.c
arch/ppc64/xmon/privinst.h
arch/ppc64/xmon/xmon.c
arch/s390/kernel/compat_linux.c
arch/sparc/kernel/module.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/lib/mul.S
arch/sparc/lib/rem.S
arch/sparc/lib/sdiv.S
arch/sparc/lib/udiv.S
arch/sparc/lib/umul.S
arch/sparc/lib/urem.S
arch/x86_64/boot/Makefile
arch/x86_64/boot/compressed/misc.c
arch/x86_64/defconfig
arch/x86_64/ia32/ia32entry.S
arch/x86_64/ia32/sys_ia32.c
arch/x86_64/kernel/Makefile
arch/x86_64/kernel/acpi/sleep.c
arch/x86_64/kernel/aperture.c
arch/x86_64/kernel/apic.c
arch/x86_64/kernel/asm-offsets.c
arch/x86_64/kernel/crash.c
arch/x86_64/kernel/e820.c
arch/x86_64/kernel/early_printk.c
arch/x86_64/kernel/entry.S
arch/x86_64/kernel/genapic.c
arch/x86_64/kernel/genapic_cluster.c
arch/x86_64/kernel/genapic_flat.c
arch/x86_64/kernel/head.S
arch/x86_64/kernel/i8259.c
arch/x86_64/kernel/init_task.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/irq.c
arch/x86_64/kernel/mce.c
arch/x86_64/kernel/mpparse.c
arch/x86_64/kernel/msr.c [deleted file]
arch/x86_64/kernel/nmi.c
arch/x86_64/kernel/pci-gart.c
arch/x86_64/kernel/process.c
arch/x86_64/kernel/setup.c
arch/x86_64/kernel/setup64.c
arch/x86_64/kernel/smp.c
arch/x86_64/kernel/smpboot.c
arch/x86_64/kernel/suspend.c
arch/x86_64/kernel/time.c
arch/x86_64/kernel/traps.c
arch/x86_64/kernel/vsyscall.c
arch/x86_64/mm/fault.c
arch/x86_64/mm/init.c
arch/x86_64/mm/k8topology.c
arch/x86_64/mm/numa.c
arch/x86_64/mm/srat.c
arch/x86_64/pci/k8-bus.c
arch/x86_64/pci/mmconfig.c
drivers/Kconfig
drivers/Makefile
drivers/base/attribute_container.c
drivers/base/class.c
drivers/base/firmware_class.c
drivers/base/map.c
drivers/base/platform.c
drivers/block/aoe/aoe.h
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
drivers/block/cciss_scsi.c
drivers/block/pktcdvd.c
drivers/block/scsi_ioctl.c
drivers/char/amiserial.c
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Makefile
drivers/char/watchdog/i6300esb.c [new file with mode: 0644]
drivers/char/watchdog/ibmasr.c [new file with mode: 0644]
drivers/char/watchdog/mpcore_wdt.c [new file with mode: 0644]
drivers/char/watchdog/mv64x60_wdt.c [new file with mode: 0644]
drivers/char/watchdog/pcwd_pci.c
drivers/char/watchdog/s3c2410_wdt.c
drivers/char/watchdog/sbc8360.c [new file with mode: 0644]
drivers/char/watchdog/w83977f_wdt.c [new file with mode: 0644]
drivers/connector/Kconfig [new file with mode: 0644]
drivers/connector/Makefile [new file with mode: 0644]
drivers/connector/cn_queue.c [new file with mode: 0644]
drivers/connector/connector.c [new file with mode: 0644]
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/hdaps.c [new file with mode: 0644]
drivers/hwmon/sis5595.c
drivers/hwmon/smsc47m1.c
drivers/hwmon/via686a.c
drivers/hwmon/w83627hf.c
drivers/i2c/busses/i2c-keywest.c
drivers/i2c/busses/i2c-nforce2.c
drivers/ide/ide-iops.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/hpt34x.c
drivers/ieee1394/sbp2.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/spitzkbd.c [new file with mode: 0644]
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/corgi_ts.c
drivers/isdn/sc/init.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/cx88/cx88-dvb.c
drivers/mmc/wbsd.c
drivers/mmc/wbsd.h
drivers/mtd/maps/uclinux.c
drivers/net/Kconfig
drivers/net/arcnet/com90io.c
drivers/net/bnx2.c
drivers/net/fec.c
drivers/net/fec.h
drivers/net/hamradio/6pack.c
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/bpqether.c
drivers/net/hamradio/dmascc.c
drivers/net/hamradio/hdlcdrv.c
drivers/net/hamradio/mkiss.c
drivers/net/hamradio/scc.c
drivers/net/hamradio/yam.c
drivers/net/tg3.c
drivers/net/wireless/orinoco_cs.c
drivers/pcmcia/pcmcia_ioctl.c
drivers/sbus/char/bpp.c
drivers/sbus/char/display7seg.c
drivers/sbus/char/vfc_i2c.c
drivers/scsi/3w-9xxx.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_sas.c [new file with mode: 0644]
drivers/scsi/sg.c
drivers/serial/mcfserial.c
drivers/tc/zs.c
drivers/usb/class/audio.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/gadget/inode.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci.h
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-hub.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci.h
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-hub.c
drivers/usb/host/uhci-q.c
drivers/usb/input/Kconfig
drivers/usb/input/Makefile
drivers/usb/input/appletouch.c [new file with mode: 0644]
drivers/usb/input/hid-core.c
drivers/usb/misc/sisusbvga/Kconfig
drivers/usb/misc/sisusbvga/Makefile
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb.h
drivers/usb/misc/sisusbvga/sisusb_con.c [new file with mode: 0644]
drivers/usb/misc/sisusbvga/sisusb_init.c [new file with mode: 0644]
drivers/usb/misc/sisusbvga/sisusb_init.h [new file with mode: 0644]
drivers/usb/misc/sisusbvga/sisusb_struct.h [new file with mode: 0644]
drivers/usb/misc/uss720.c
drivers/usb/mon/mon_text.c
drivers/usb/serial/cp2101.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/storage/scsiglue.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/video/Kconfig
drivers/video/backlight/corgi_bl.c
drivers/video/console/Kconfig
drivers/video/console/Makefile
drivers/video/console/fbcon.c
drivers/video/console/fbcon.h
drivers/video/console/font_10x18.c
drivers/video/console/font_6x11.c
drivers/video/console/font_7x14.c
drivers/video/console/font_8x16.c
drivers/video/console/font_8x8.c
drivers/video/console/font_acorn_8x8.c
drivers/video/console/font_mini_4x6.c
drivers/video/console/font_pearl_8x8.c
drivers/video/console/font_sun12x22.c
drivers/video/console/font_sun8x16.c
drivers/video/console/fonts.c
drivers/video/i810/i810_main.c
drivers/video/matrox/matroxfb_base.c
drivers/video/pm3fb.c
drivers/w1/w1_ds2433.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/ntfs/ChangeLog
fs/ntfs/malloc.h
fs/ntfs/super.c
fs/open.c
fs/reiserfs/file.c
fs/reiserfs/inode.c
include/asm-alpha/pgtable.h
include/asm-arm/arch-pxa/akita.h [new file with mode: 0644]
include/asm-arm/arch-pxa/corgi.h
include/asm-arm/arch-pxa/sharpsl.h [new file with mode: 0644]
include/asm-arm/arch-pxa/spitz.h [new file with mode: 0644]
include/asm-arm/pgtable.h
include/asm-arm26/pgtable.h
include/asm-frv/pgtable.h
include/asm-generic/tlb.h
include/asm-h8300/pgtable.h
include/asm-i386/apic.h
include/asm-i386/numa.h [new file with mode: 0644]
include/asm-i386/pgtable.h
include/asm-i386/topology.h
include/asm-i386/unistd.h
include/asm-ia64/pgtable.h
include/asm-m32r/pgtable.h
include/asm-m68k/pgtable.h
include/asm-m68knommu/bitops.h
include/asm-m68knommu/cacheflush.h
include/asm-m68knommu/checksum.h
include/asm-m68knommu/m527xsim.h
include/asm-m68knommu/m528xsim.h
include/asm-m68knommu/mcfcache.h
include/asm-m68knommu/mcfdma.h
include/asm-m68knommu/pgtable.h
include/asm-m68knommu/scatterlist.h
include/asm-m68knommu/system.h
include/asm-mips/pgtable.h
include/asm-parisc/pgtable.h
include/asm-powerpc/siginfo.h
include/asm-ppc/mv64x60.h
include/asm-ppc/pgtable.h
include/asm-ppc/ptrace.h
include/asm-ppc/segment.h [deleted file]
include/asm-ppc64/hvcall.h
include/asm-ppc64/machdep.h
include/asm-ppc64/pci-bridge.h
include/asm-ppc64/plpar_wrappers.h
include/asm-ppc64/processor.h
include/asm-ppc64/ptrace-common.h
include/asm-ppc64/ptrace.h
include/asm-ppc64/system.h
include/asm-sh/pgtable.h
include/asm-sh64/pgtable.h
include/asm-x86_64/apic.h
include/asm-x86_64/apicdef.h
include/asm-x86_64/bug.h
include/asm-x86_64/calling.h
include/asm-x86_64/desc.h
include/asm-x86_64/dma-mapping.h
include/asm-x86_64/dwarf2.h
include/asm-x86_64/fixmap.h
include/asm-x86_64/hardirq.h
include/asm-x86_64/hw_irq.h
include/asm-x86_64/io.h
include/asm-x86_64/ipi.h
include/asm-x86_64/kdebug.h
include/asm-x86_64/local.h
include/asm-x86_64/mmzone.h
include/asm-x86_64/msr.h
include/asm-x86_64/numa.h
include/asm-x86_64/page.h
include/asm-x86_64/pci.h
include/asm-x86_64/pda.h
include/asm-x86_64/pgalloc.h
include/asm-x86_64/pgtable.h
include/asm-x86_64/processor.h
include/asm-x86_64/proto.h
include/asm-x86_64/signal.h
include/asm-x86_64/smp.h
include/asm-x86_64/system.h
include/asm-x86_64/timex.h
include/asm-x86_64/tlbflush.h
include/asm-x86_64/topology.h
include/asm-x86_64/vsyscall.h
include/asm-xtensa/pgtable.h
include/linux/connector.h [new file with mode: 0644]
include/linux/crc16.h
include/linux/dmi.h
include/linux/fb.h
include/linux/font.h
include/linux/interrupt.h
include/linux/kernel.h
include/linux/netlink.h
include/linux/nfsd/xdr4.h
include/linux/pci_ids.h
include/linux/pktcdvd.h
include/linux/sched.h
include/linux/sysctl.h
include/linux/usbdevice_fs.h
include/linux/videodev2.h
include/net/ax25.h
include/net/netrom.h
include/scsi/scsi_device.h
include/scsi/scsi_transport_fc.h
include/scsi/scsi_transport_sas.h [new file with mode: 0644]
include/video/pm3fb.h
include/video/w100fb.h
init/initramfs.c
kernel/cpuset.c
kernel/module.c
kernel/sched.c
kernel/softirq.c
kernel/timer.c
lib/Kconfig.debug
mm/bootmem.c
mm/mempolicy.c
mm/nommu.c
mm/page_alloc.c
mm/vmscan.c
net/ax25/af_ax25.c
net/ax25/ax25_ip.c
net/core/pktgen.c
net/dccp/ccids/ccid3.c
net/ipv4/ipconfig.c
net/irda/ircomm/ircomm_tty.c
net/netrom/af_netrom.c
net/netrom/nr_dev.c
net/netrom/nr_in.c
net/netrom/nr_subr.c
net/netrom/sysctl_net_netrom.c
net/rose/af_rose.c
net/rose/rose_dev.c
net/sunrpc/svcsock.c
scripts/mod/modpost.c

index 8bacf9f2c7cc971ef25aefb445f550815bb4fdf3..32615814271cce1f90e6be56d5a26eb15c12de3d 100644 (file)
@@ -8,13 +8,15 @@ fi
 n_partitions=${n_partitions:-16}
 dir=$1
 shelf=$2
+nslots=16
+maxslot=`echo $nslots 1 - p | dc`
 MAJOR=152
 
 set -e
 
-minor=`echo 10 \* $shelf \* $n_partitions | bc`
+minor=`echo $nslots \* $shelf \* $n_partitions | bc`
 endp=`echo $n_partitions - 1 | bc`
-for slot in `seq 0 9`; do
+for slot in `seq 0 $maxslot`; do
        for part in `seq 0 $endp`; do
                name=e$shelf.$slot
                test "$part" != "0" && name=${name}p$part
index c8f9a73111da8371d5ff4b49b68116ffb3353e48..68a711fb82cf8d9d612363ff04bb71719ef6729f 100644 (file)
@@ -17,7 +17,9 @@ This driver is known to work with the following cards:
        * SA P600
        * SA P800
        * SA E400
-       * SA E300
+       * SA P400i
+       * SA E200
+       * SA E200i
 
 If nodes are not already created in the /dev/cciss directory, run as root:
 
diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
new file mode 100644 (file)
index 0000000..b7de82e
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *     cn_test.c
+ * 
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 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.  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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+
+#include "connector.h"
+
+static struct cb_id cn_test_id = { 0x123, 0x456 };
+static char cn_test_name[] = "cn_test";
+static struct sock *nls;
+static struct timer_list cn_test_timer;
+
+void cn_test_callback(void *data)
+{
+       struct cn_msg *msg = (struct cn_msg *)data;
+
+       printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+              __func__, jiffies, msg->id.idx, msg->id.val,
+              msg->seq, msg->ack, msg->len, (char *)msg->data);
+}
+
+static int cn_test_want_notify(void)
+{
+       struct cn_ctl_msg *ctl;
+       struct cn_notify_req *req;
+       struct cn_msg *msg = NULL;
+       int size, size0;
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       u32 group = 1;
+
+       size0 = sizeof(*msg) + sizeof(*ctl) + 3 * sizeof(*req);
+
+       size = NLMSG_SPACE(size0);
+
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_ERR "Failed to allocate new skb with size=%u.\n",
+                      size);
+
+               return -ENOMEM;
+       }
+
+       nlh = NLMSG_PUT(skb, 0, 0x123, NLMSG_DONE, size - sizeof(*nlh));
+
+       msg = (struct cn_msg *)NLMSG_DATA(nlh);
+
+       memset(msg, 0, size0);
+
+       msg->id.idx = -1;
+       msg->id.val = -1;
+       msg->seq = 0x123;
+       msg->ack = 0x345;
+       msg->len = size0 - sizeof(*msg);
+
+       ctl = (struct cn_ctl_msg *)(msg + 1);
+
+       ctl->idx_notify_num = 1;
+       ctl->val_notify_num = 2;
+       ctl->group = group;
+       ctl->len = msg->len - sizeof(*ctl);
+
+       req = (struct cn_notify_req *)(ctl + 1);
+
+       /*
+        * Idx.
+        */
+       req->first = cn_test_id.idx;
+       req->range = 10;
+
+       /*
+        * Val 0.
+        */
+       req++;
+       req->first = cn_test_id.val;
+       req->range = 10;
+
+       /*
+        * Val 1.
+        */
+       req++;
+       req->first = cn_test_id.val + 20;
+       req->range = 10;
+
+       NETLINK_CB(skb).dst_groups = ctl->group;
+       //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);
+       netlink_unicast(nls, skb, 0, 0);
+
+       printk(KERN_INFO "Request was sent. Group=0x%x.\n", ctl->group);
+
+       return 0;
+
+nlmsg_failure:
+       printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack);
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+static u32 cn_test_timer_counter;
+static void cn_test_timer_func(unsigned long __data)
+{
+       struct cn_msg *m;
+       char data[32];
+
+       m = kmalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
+       if (m) {
+               memset(m, 0, sizeof(*m) + sizeof(data));
+
+               memcpy(&m->id, &cn_test_id, sizeof(m->id));
+               m->seq = cn_test_timer_counter;
+               m->len = sizeof(data);
+
+               m->len =
+                   scnprintf(data, sizeof(data), "counter = %u",
+                             cn_test_timer_counter) + 1;
+
+               memcpy(m + 1, data, m->len);
+
+               cn_netlink_send(m, 0, gfp_any());
+               kfree(m);
+       }
+
+       cn_test_timer_counter++;
+
+       mod_timer(&cn_test_timer, jiffies + HZ);
+}
+
+static int cn_test_init(void)
+{
+       int err;
+
+       err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);
+       if (err)
+               goto err_out;
+       cn_test_id.val++;
+       err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);
+       if (err) {
+               cn_del_callback(&cn_test_id);
+               goto err_out;
+       }
+
+       init_timer(&cn_test_timer);
+       cn_test_timer.function = cn_test_timer_func;
+       cn_test_timer.expires = jiffies + HZ;
+       cn_test_timer.data = 0;
+       add_timer(&cn_test_timer);
+
+       return 0;
+
+      err_out:
+       if (nls && nls->sk_socket)
+               sock_release(nls->sk_socket);
+
+       return err;
+}
+
+static void cn_test_fini(void)
+{
+       del_timer_sync(&cn_test_timer);
+       cn_del_callback(&cn_test_id);
+       cn_test_id.val--;
+       cn_del_callback(&cn_test_id);
+       if (nls && nls->sk_socket)
+               sock_release(nls->sk_socket);
+}
+
+module_init(cn_test_init);
+module_exit(cn_test_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Connector's test module");
diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt
new file mode 100644 (file)
index 0000000..54a0a14
--- /dev/null
@@ -0,0 +1,133 @@
+/*****************************************/
+Kernel Connector.
+/*****************************************/
+
+Kernel connector - new netlink based userspace <-> kernel space easy
+to use communication module.
+
+Connector driver adds possibility to connect various agents using
+netlink based network.  One must register callback and
+identifier. When driver receives special netlink message with
+appropriate identifier, appropriate callback will be called.
+
+From the userspace point of view it's quite straightforward:
+
+       socket();
+       bind();
+       send();
+       recv();
+
+But if kernelspace want to use full power of such connections, driver
+writer must create special sockets, must know about struct sk_buff
+handling...  Connector allows any kernelspace agents to use netlink
+based networking for inter-process communication in a significantly
+easier way:
+
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
+void cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask);
+
+struct cb_id
+{
+       __u32                   idx;
+       __u32                   val;
+};
+
+idx and val are unique identifiers which must be registered in
+connector.h for in-kernel usage.  void (*callback) (void *) - is a
+callback function which will be called when message with above idx.val
+will be received by connector core.  Argument for that function must
+be dereferenced to struct cn_msg *.
+
+struct cn_msg
+{
+       struct cb_id            id;
+
+       __u32                   seq;
+       __u32                   ack;
+
+       __u32                   len;            /* Length of the following data */
+       __u8                    data[0];
+};
+
+/*****************************************/
+Connector interfaces.
+/*****************************************/
+
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
+
+Registers new callback with connector core.
+
+struct cb_id *id               - unique connector's user identifier.
+                                 It must be registered in connector.h for legal in-kernel users.
+char *name                     - connector's callback symbolic name.
+void (*callback) (void *)      - connector's callback.
+                                 Argument must be dereferenced to struct cn_msg *.
+
+void cn_del_callback(struct cb_id *id);
+
+Unregisters new callback with connector core.
+
+struct cb_id *id               - unique connector's user identifier.
+
+void cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
+
+Sends message to the specified groups.  It can be safely called from
+any context, but may silently fail under strong memory pressure.
+
+struct cn_msg *                        - message header(with attached data).
+u32 __group                    - destination group.
+                                 If __group is zero, then appropriate group will
+                                 be searched through all registered connector users,
+                                 and message will be delivered to the group which was
+                                 created for user with the same ID as in msg.
+                                 If __group is not zero, then message will be delivered
+                                 to the specified group.
+int gfp_mask                   - GFP mask.
+
+Note: When registering new callback user, connector core assigns
+netlink group to the user which is equal to it's id.idx.
+
+/*****************************************/
+Protocol description.
+/*****************************************/
+
+Current offers transport layer with fixed header.  Recommended
+protocol which uses such header is following:
+
+msg->seq and msg->ack are used to determine message genealogy.  When
+someone sends message it puts there locally unique sequence and random
+acknowledge numbers.  Sequence number may be copied into
+nlmsghdr->nlmsg_seq too.
+
+Sequence number is incremented with each message to be sent.
+
+If we expect reply to our message, then sequence number in received
+message MUST be the same as in original message, and acknowledge
+number MUST be the same + 1.
+
+If we receive message and it's sequence number is not equal to one we
+are expecting, then it is new message.  If we receive message and it's
+sequence number is the same as one we are expecting, but it's
+acknowledge is not equal acknowledge number in original message + 1,
+then it is new message.
+
+Obviously, protocol header contains above id.
+
+connector allows event notification in the following form: kernel
+driver or userspace process can ask connector to notify it when
+selected id's will be turned on or off(registered or unregistered it's
+callback). It is done by sending special command to connector
+driver(it also registers itself with id={-1, -1}).
+
+As example of usage Documentation/connector now contains cn_test.c -
+testing module which uses connector to request notification and to
+send messages.
+
+/*****************************************/
+Reliability.
+/*****************************************/
+
+Netlink itself is not reliable protocol, that means that messages can
+be lost due to memory pressure or process' receiving queue overflowed,
+so caller is warned must be prepared. That is why struct cn_msg [main
+connector's message header] contains u32 seq and u32 ack fields.
index 96bea278bbf61eb9ae6d6cb5657f8092b543a87e..24adfe9af3ca92a169b9f7a7fc368e9098dac487 100644 (file)
@@ -55,6 +55,7 @@ aic7*seq.h*
 aicasm
 aicdb.h*
 asm
+asm-offsets.*
 asm_offsets.*
 autoconf.h*
 bbootsect
index fd68b162e4a13ce7cbf028405a14724224542e1f..4f0d6bc789ef0fadf101eaa362fa3d829dc8a588 100644 (file)
@@ -5,6 +5,7 @@ Intel 810/815 Framebuffer driver
        March 17, 2002
 
        First Released: July 2001
+       Last Update:    September 12, 2005
 ================================================================
 
 A. Introduction
@@ -44,6 +45,8 @@ B.  Features
 
        - Hardware Cursor Support
  
+       - Supports EDID probing either by DDC/I2C or through the BIOS
+
 C.  List of available options
        
    a. "video=i810fb"  
@@ -52,14 +55,17 @@ C.  List of available options
        Recommendation: required
  
    b. "xres:<value>"  
-       select horizontal resolution in pixels
+       select horizontal resolution in pixels. (This parameter will be
+       ignored if 'mode_option' is specified.  See 'o' below).
 
        Recommendation: user preference 
        (default = 640)
 
    c. "yres:<value>"
        select vertical resolution in scanlines. If Discrete Video Timings
-       is enabled, this will be ignored and computed as 3*xres/4.  
+       is enabled, this will be ignored and computed as 3*xres/4.  (This
+       parameter will be ignored if 'mode_option' is specified.  See 'o'
+       below)  
 
        Recommendation: user preference
        (default = 480)
@@ -86,7 +92,8 @@ C.  List of available options
    g. "hsync1/hsync2:<value>" 
        select the minimum and maximum Horizontal Sync Frequency of the 
        monitor in KHz.  If a using a fixed frequency monitor, hsync1 must 
-       be equal to hsync2. 
+       be equal to hsync2. If EDID probing is successful, these will be
+       ignored and values will be taken from the EDID block.
 
        Recommendation: check monitor manual for correct values
        default (29/30)
@@ -94,7 +101,8 @@ C.  List of available options
    h. "vsync1/vsync2:<value>" 
        select the minimum and maximum Vertical Sync Frequency of the monitor
        in Hz. You can also use this option to lock your monitor's refresh 
-       rate.
+       rate. If EDID probing is successful, these will be ignored and values
+       will be taken from the EDID block.
 
        Recommendation: check monitor manual for correct values
        (default = 60/60)
@@ -154,7 +162,11 @@ C.  List of available options
 
        Recommendation: do not set
        (default = not set)
-                       
+   o. <xres>x<yres>[-<bpp>][@<refresh>]
+       The driver will now accept specification of boot mode option.  If this
+       is specified, the options 'xres' and 'yres' will be ignored. See
+       Documentation/fb/modedb.txt for usage.
+
 D. Kernel booting
 
 Separate each option/option-pair by commas (,) and the option from its value
@@ -176,7 +188,10 @@ will be computed based on the hsync1/hsync2 and vsync1/vsync2 values.
 
 IMPORTANT:
 You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes
-better than 640x480 at 60Hz.
+better than 640x480 at 60Hz. HOWEVER, if your chipset/display combination
+supports I2C and has an EDID block, you can safely exclude hsync1, hsync2,
+vsync1 and vsync2 parameters.  These parameters will be taken from the EDID
+block.
 
 E.  Module options
        
@@ -217,32 +232,21 @@ F.  Setup
           This is required.  The option is under "Character Devices"
 
        d. Under "Graphics Support", select "Intel 810/815" either statically
-          or as a module.  Choose "use VESA GTF for video timings"  if you 
-          need to maximize the capability of your display.  To be on the 
+          or as a module.  Choose "use VESA Generalized Timing Formula" if
+          you need to maximize the capability of your display.  To be on the 
           safe side, you can leave this unselected.  
   
-        e. If you want a framebuffer console, enable it under "Console 
+       e. If you want support for DDC/I2C probing (Plug and Play Displays),
+          set 'Enable DDC Support' to 'y'. To make this option appear, set
+          'use VESA Generalized Timing Formula' to 'y'.
+
+        f. If you want a framebuffer console, enable it under "Console 
           Drivers"
 
-       f. Compile your kernel. 
+       g. Compile your kernel. 
                
-       g. Load the driver as described in section D and E.
+       h. Load the driver as described in section D and E.
        
-       Optional:       
-       h.  If you are going to run XFree86 with its native drivers, the 
-           standard XFree86 4.1.0 and 4.2.0 drivers should work as is.
-            However, there's a bug in the XFree86 i810 drivers.  It attempts 
-           to use XAA even when switched to the console. This will crash
-           your server. I have a fix at this site:  
-           
-           http://i810fb.sourceforge.net.  
-
-           You can either use the patch, or just replace 
-           
-            /usr/X11R6/lib/modules/drivers/i810_drv.o
-
-           with the one provided at the website.       
-
        i.  Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver
            patch to see the chipset in action (or inaction :-).
 
index 784e08c1c80a308b9916a4a1f360380482761603..b67189a8d8d471789629ae23e4c1b6e9e2b713da 100644 (file)
@@ -17,15 +17,6 @@ Who: Greg Kroah-Hartman <greg@kroah.com>
 
 ---------------------------
 
-What:  io_remap_page_range() (macro or function)
-When:  September 2005
-Why:   Replaced by io_remap_pfn_range() which allows more memory space
-       addressabilty (by using a pfn) and supports sparc & sparc64
-       iospace as part of the pfn.
-Who:   Randy Dunlap <rddunlap@osdl.org>
-
----------------------------
-
 What:  RAW driver (CONFIG_RAW_DRIVER)
 When:  December 2005
 Why:   declared obsolete since kernel 2.6.3
index e1c56a7e6583dce3b9212d0702a75d9b628c81a4..4bef8c25172c8e472b09f068e0a34e2e5e8b08ee 100644 (file)
@@ -32,14 +32,14 @@ static void sample_firmware_load(char *firmware, int size)
        u8 buf[size+1];
        memcpy(buf, firmware, size);
        buf[size] = '\0';
-       printk("firmware_sample_driver: firmware: %s\n", buf);
+       printk(KERN_INFO "firmware_sample_driver: firmware: %s\n", buf);
 }
 
 static void sample_probe_default(void)
 {
        /* uses the default method to get the firmware */
         const struct firmware *fw_entry;
-       printk("firmware_sample_driver: a ghost device got inserted :)\n");
+       printk(KERN_INFO "firmware_sample_driver: a ghost device got inserted :)\n");
 
         if(request_firmware(&fw_entry, "sample_driver_fw", &ghost_device)!=0)
        {
@@ -61,7 +61,7 @@ static void sample_probe_specific(void)
 
        /* NOTE: This currently doesn't work */
 
-       printk("firmware_sample_driver: a ghost device got inserted :)\n");
+       printk(KERN_INFO "firmware_sample_driver: a ghost device got inserted :)\n");
 
         if(request_firmware(NULL, "sample_driver_fw", &ghost_device)!=0)
        {
@@ -83,7 +83,7 @@ static void sample_probe_async_cont(const struct firmware *fw, void *context)
                return;
        }
 
-       printk("firmware_sample_driver: device pointer \"%s\"\n",
+       printk(KERN_INFO "firmware_sample_driver: device pointer \"%s\"\n",
               (char *)context);
        sample_firmware_load(fw->data, fw->size);
 }
diff --git a/Documentation/input/appletouch.txt b/Documentation/input/appletouch.txt
new file mode 100644 (file)
index 0000000..b48d11d
--- /dev/null
@@ -0,0 +1,84 @@
+Apple Touchpad Driver (appletouch)
+----------------------------------
+       Copyright (C) 2005 Stelian Pop <stelian@popies.net>
+
+appletouch is a Linux kernel driver for the USB touchpad found on post
+February 2005 Apple Alu Powerbooks.
+
+This driver is derived from Johannes Berg's appletrackpad driver[1], but it has
+been improved in some areas:
+       * appletouch is a full kernel driver, no userspace program is necessary
+       * appletouch can be interfaced with the synaptics X11 driver, in order
+         to have touchpad acceleration, scrolling, etc.
+
+Credits go to Johannes Berg for reverse-engineering the touchpad protocol,
+Frank Arnold for further improvements, and Alex Harper for some additional
+information about the inner workings of the touchpad sensors.
+
+Usage:
+------
+
+In order to use the touchpad in the basic mode, compile the driver and load
+the module. A new input device will be detected and you will be able to read
+the mouse data from /dev/input/mice (using gpm, or X11).
+
+In X11, you can configure the touchpad to use the synaptics X11 driver, which
+will give additional functionalities, like acceleration, scrolling, 2 finger
+tap for middle button mouse emulation, 3 finger tap for right button mouse
+emulation, etc. In order to do this, make sure you're using a recent version of
+the synaptics driver (tested with 0.14.2, available from [2]), and configure a
+new input device in your X11 configuration file (take a look below for an
+example). For additional configuration, see the synaptics driver documentation.
+
+       Section "InputDevice"
+               Identifier      "Synaptics Touchpad"
+               Driver          "synaptics"
+               Option          "SendCoreEvents"        "true"
+               Option          "Device"                "/dev/input/mice"
+               Option          "Protocol"              "auto-dev"
+               Option          "LeftEdge"              "0"
+               Option          "RightEdge"             "850"
+               Option          "TopEdge"               "0"
+               Option          "BottomEdge"            "645"
+               Option          "MinSpeed"              "0.4"
+               Option          "MaxSpeed"              "1"
+               Option          "AccelFactor"           "0.02"
+               Option          "FingerLow"             "0"
+               Option          "FingerHigh"            "30"
+               Option          "MaxTapMove"            "20"
+               Option          "MaxTapTime"            "100"
+               Option          "HorizScrollDelta"      "0"
+               Option          "VertScrollDelta"       "30"
+               Option          "SHMConfig"             "on"
+       EndSection
+
+       Section "ServerLayout"
+               ...
+               InputDevice     "Mouse"
+               InputDevice     "Synaptics Touchpad"
+       ...
+       EndSection
+
+Fuzz problems:
+--------------
+
+The touchpad sensors are very sensitive to heat, and will generate a lot of
+noise when the temperature changes. This is especially true when you power-on
+the laptop for the first time.
+
+The appletouch driver tries to handle this noise and auto adapt itself, but it
+is not perfect. If finger movements are not recognized anymore, try reloading
+the driver.
+
+You can activate debugging using the 'debug' module parameter. A value of 0
+deactivates any debugging, 1 activates tracing of invalid samples, 2 activates
+full tracing (each sample is being traced):
+       modprobe appletouch debug=1
+               or
+       echo "1" > /sys/module/appletouch/parameters/debug
+
+Links:
+------
+
+[1]: http://johannes.sipsolutions.net/PowerBook/touchpad/
+[2]: http://web.telia.com/~u89404340/touchpad/index.html
index 1f5f7d28c9e6bf54e2b95d97f9399aed324b177f..5f08f9ce60464bdb03e7dd6c82398c79c0bd2eba 100644 (file)
@@ -66,11 +66,11 @@ SETUP
    c) Enable "/proc/vmcore support" (Optional, in Pseudo filesystems).
        CONFIG_PROC_VMCORE=y
    d) Disable SMP support and build a UP kernel (Until it is fixed).
-       CONFIG_SMP=n
+       CONFIG_SMP=n
    e) Enable "Local APIC support on uniprocessors".
-       CONFIG_X86_UP_APIC=y
+       CONFIG_X86_UP_APIC=y
    f) Enable "IO-APIC support on uniprocessors"
-       CONFIG_X86_UP_IOAPIC=y
+       CONFIG_X86_UP_IOAPIC=y
 
   Note:   i) Options a) and b) depend upon "Configure standard kernel features
             (for small systems)" (under General setup).
@@ -95,6 +95,11 @@ SETUP
            hence have memory less than 4GB.
        iii) Specify "irqpoll" as command line parameter. This reduces driver
             initialization failures in second kernel due to shared interrupts.
+        iv) <root-dev> needs to be specified in a format corresponding to
+            the root device name in the output of mount command.
+         v) If you have built the drivers required to mount root file
+            system as modules in <second-kernel>, then, specify
+            --initrd=<initrd-for-second-kernel>.
 
 5) System reboots into the second kernel when a panic occurs. A module can be
    written to force the panic or "ALT-SysRq-c" can be used initiate a crash
index db2603ceabba6f6743438a4e74d458865ba504bb..7086f0a90d14a47d6ba3295e624a7bda414062a9 100644 (file)
@@ -164,6 +164,15 @@ running once the system is up.
                        over-ride platform specific driver.
                        See also Documentation/acpi-hotkey.txt.
 
+       enable_timer_pin_1 [i386,x86-64]
+                       Enable PIN 1 of APIC timer
+                       Can be useful to work around chipset bugs (in particular on some ATI chipsets)
+                       The kernel tries to set a reasonable default.
+
+       disable_timer_pin_1 [i386,x86-64]
+                       Disable PIN 1 of APIC timer
+                       Can be useful to work around chipset bugs.
+
        ad1816=         [HW,OSS]
                        Format: <io>,<irq>,<dma>,<dma2>
                        See also Documentation/sound/oss/AD1816.
index da711028e5f712cde905b4129e6addfc96b7ac92..66eaaab7773d551691181070daead961fca33df2 100644 (file)
@@ -205,8 +205,8 @@ Phone: 701-234-7556
 Tainted kernels:
 
 Some oops reports contain the string 'Tainted: ' after the program
-counter, this indicates that the kernel has been tainted by some
-mechanism.  The string is followed by a series of position sensitive
+counter. This indicates that the kernel has been tainted by some
+mechanism.  The string is followed by a series of position-sensitive
 characters, each representing a particular tainted value.
 
   1: 'G' if all modules loaded have a GPL or compatible license, 'P' if
@@ -214,16 +214,25 @@ characters, each representing a particular tainted value.
      MODULE_LICENSE or with a MODULE_LICENSE that is not recognised by
      insmod as GPL compatible are assumed to be proprietary.
 
-  2: 'F' if any module was force loaded by insmod -f, ' ' if all
+  2: 'F' if any module was force loaded by "insmod -f", ' ' if all
      modules were loaded normally.
 
   3: 'S' if the oops occurred on an SMP kernel running on hardware that
-      hasn't been certified as safe to run multiprocessor.
-         Currently this occurs only on various Athlons that are not
-         SMP capable.
+     hasn't been certified as safe to run multiprocessor.
+     Currently this occurs only on various Athlons that are not
+     SMP capable.
+
+  4: 'R' if a module was force unloaded by "rmmod -f", ' ' if all
+     modules were unloaded normally.
+
+  5: 'M' if any processor has reported a Machine Check Exception,
+     ' ' if no Machine Check Exceptions have occurred.
+
+  6: 'B' if a page-release function has found a bad page reference or
+     some unexpected page flags.
 
 The primary reason for the 'Tainted: ' string is to tell kernel
 debuggers if this is a clean kernel or if anything unusual has
-occurred.  Tainting is permanent, even if an offending module is
-unloading the tainted value remains to indicate that the kernel is not
+occurred.  Tainting is permanent: even if an offending module is
+unloaded, the tainted value remains to indicate that the kernel is not
 trustworthy.
index cc63ae18d147e031f69866c4aca8ebcdacfa5c5c..2ea1149bf6b044b7a77f5c70f7abe48863b60540 100644 (file)
@@ -38,6 +38,12 @@ system the associated daemon will exit gracefully.
 
 Driver Interface -- OBSOLETE, DO NOT USE!
 ----------------*************************
+
+Note: pm_register(), pm_access(), pm_dev_idle() and friends are
+obsolete. Please do not use them. Instead you should properly hook
+your driver into the driver model, and use its suspend()/resume()
+callbacks to do this kind of stuff.
+
 If you are writing a new driver or maintaining an old driver, it
 should include power management support.  Without power management
 support, a single driver may prevent a system with power management
index f9cb5bdcce4183d4f0f70413908dbab8a0c60c0c..fef92ebf266ff5f99d697843389bad322fb915f3 100644 (file)
@@ -60,6 +60,8 @@ scsi.txt
        - short blurb on using SCSI support as a module.
 scsi_mid_low_api.txt
        - info on API between SCSI layer and low level drivers
+scsi_eh.txt
+       - info on SCSI midlayer error handling infrastructure
 st.txt
        - info on scsi tape driver
 sym53c500_cs.txt
diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt
new file mode 100644 (file)
index 0000000..534a509
--- /dev/null
@@ -0,0 +1,479 @@
+
+SCSI EH
+======================================
+
+ This document describes SCSI midlayer error handling infrastructure.
+Please refer to Documentation/scsi/scsi_mid_low_api.txt for more
+information regarding SCSI midlayer.
+
+TABLE OF CONTENTS
+
+[1] How SCSI commands travel through the midlayer and to EH
+    [1-1] struct scsi_cmnd
+    [1-2] How do scmd's get completed?
+       [1-2-1] Completing a scmd w/ scsi_done
+       [1-2-2] Completing a scmd w/ timeout
+    [1-3] How EH takes over
+[2] How SCSI EH works
+    [2-1] EH through fine-grained callbacks
+       [2-1-1] Overview
+       [2-1-2] Flow of scmds through EH
+       [2-1-3] Flow of control
+    [2-2] EH through hostt->eh_strategy_handler()
+       [2-2-1] Pre hostt->eh_strategy_handler() SCSI midlayer conditions
+       [2-2-2] Post hostt->eh_strategy_handler() SCSI midlayer conditions
+       [2-2-3] Things to consider
+
+
+[1] How SCSI commands travel through the midlayer and to EH
+
+[1-1] struct scsi_cmnd
+
+ Each SCSI command is represented with struct scsi_cmnd (== scmd).  A
+scmd has two list_head's to link itself into lists.  The two are
+scmd->list and scmd->eh_entry.  The former is used for free list or
+per-device allocated scmd list and not of much interest to this EH
+discussion.  The latter is used for completion and EH lists and unless
+otherwise stated scmds are always linked using scmd->eh_entry in this
+discussion.
+
+
+[1-2] How do scmd's get completed?
+
+ Once LLDD gets hold of a scmd, either the LLDD will complete the
+command by calling scsi_done callback passed from midlayer when
+invoking hostt->queuecommand() or SCSI midlayer will time it out.
+
+
+[1-2-1] Completing a scmd w/ scsi_done
+
+ For all non-EH commands, scsi_done() is the completion callback.  It
+does the following.
+
+ 1. Delete timeout timer.  If it fails, it means that timeout timer
+    has expired and is going to finish the command.  Just return.
+
+ 2. Link scmd to per-cpu scsi_done_q using scmd->en_entry
+
+ 3. Raise SCSI_SOFTIRQ
+
+ SCSI_SOFTIRQ handler scsi_softirq calls scsi_decide_disposition() to
+determine what to do with the command.  scsi_decide_disposition()
+looks at the scmd->result value and sense data to determine what to do
+with the command.
+
+ - SUCCESS
+       scsi_finish_command() is invoked for the command.  The
+       function does some maintenance choirs and notify completion by
+       calling scmd->done() callback, which, for fs requests, would
+       be HLD completion callback - sd:sd_rw_intr, sr:rw_intr,
+       st:st_intr.
+
+ - NEEDS_RETRY
+ - ADD_TO_MLQUEUE
+       scmd is requeued to blk queue.
+
+ - otherwise
+       scsi_eh_scmd_add(scmd, 0) is invoked for the command.  See
+       [1-3] for details of this funciton.
+
+
+[1-2-2] Completing a scmd w/ timeout
+
+ The timeout handler is scsi_times_out().  When a timeout occurs, this
+function
+
+ 1. invokes optional hostt->eh_timedout() callback.  Return value can
+    be one of
+
+    - EH_HANDLED
+       This indicates that eh_timedout() dealt with the timeout.  The
+       scmd is passed to __scsi_done() and thus linked into per-cpu
+       scsi_done_q.  Normal command completion described in [1-2-1]
+       follows.
+
+    - EH_RESET_TIMER
+       This indicates that more time is required to finish the
+       command.  Timer is restarted.  This action is counted as a
+       retry and only allowed scmd->allowed + 1(!) times.  Once the
+       limit is reached, action for EH_NOT_HANDLED is taken instead.
+
+       *NOTE* This action is racy as the LLDD could finish the scmd
+       after the timeout has expired but before it's added back.  In
+       such cases, scsi_done() would think that timeout has occurred
+       and return without doing anything.  We lose completion and the
+       command will time out again.
+
+    - EH_NOT_HANDLED
+       This is the same as when eh_timedout() callback doesn't exist.
+       Step #2 is taken.
+
+ 2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the
+    command.  See [1-3] for more information.
+
+
+[1-3] How EH takes over
+
+ scmds enter EH via scsi_eh_scmd_add(), which does the following.
+
+ 1. Turns on scmd->eh_eflags as requested.  It's 0 for error
+    completions and SCSI_EH_CANCEL_CMD for timeouts.
+
+ 2. Links scmd->eh_entry to shost->eh_cmd_q
+
+ 3. Sets SHOST_RECOVERY bit in shost->shost_state
+
+ 4. Increments shost->host_failed
+
+ 5. Wakes up SCSI EH thread if shost->host_busy == shost->host_failed
+
+ As can be seen above, once any scmd is added to shost->eh_cmd_q,
+SHOST_RECOVERY shost_state bit is turned on.  This prevents any new
+scmd to be issued from blk queue to the host; eventually, all scmds on
+the host either complete normally, fail and get added to eh_cmd_q, or
+time out and get added to shost->eh_cmd_q.
+
+ If all scmds either complete or fail, the number of in-flight scmds
+becomes equal to the number of failed scmds - i.e. shost->host_busy ==
+shost->host_failed.  This wakes up SCSI EH thread.  So, once woken up,
+SCSI EH thread can expect that all in-flight commands have failed and
+are linked on shost->eh_cmd_q.
+
+ Note that this does not mean lower layers are quiescent.  If a LLDD
+completed a scmd with error status, the LLDD and lower layers are
+assumed to forget about the scmd at that point.  However, if a scmd
+has timed out, unless hostt->eh_timedout() made lower layers forget
+about the scmd, which currently no LLDD does, the command is still
+active as long as lower layers are concerned and completion could
+occur at any time.  Of course, all such completions are ignored as the
+timer has already expired.
+
+ We'll talk about how SCSI EH takes actions to abort - make LLDD
+forget about - timed out scmds later.
+
+
+[2] How SCSI EH works
+
+ LLDD's can implement SCSI EH actions in one of the following two
+ways.
+
+ - Fine-grained EH callbacks
+       LLDD can implement fine-grained EH callbacks and let SCSI
+       midlayer drive error handling and call appropriate callbacks.
+       This will be dicussed further in [2-1].
+
+ - eh_strategy_handler() callback
+       This is one big callback which should perform whole error
+       handling.  As such, it should do all choirs SCSI midlayer
+       performs during recovery.  This will be discussed in [2-2].
+
+ Once recovery is complete, SCSI EH resumes normal operation by
+calling scsi_restart_operations(), which
+
+ 1. Checks if door locking is needed and locks door.
+
+ 2. Clears SHOST_RECOVERY shost_state bit
+
+ 3. Wakes up waiters on shost->host_wait.  This occurs if someone
+    calls scsi_block_when_processing_errors() on the host.
+    (*QUESTION* why is it needed?  All operations will be blocked
+    anyway after it reaches blk queue.)
+
+ 4. Kicks queues in all devices on the host in the asses
+
+
+[2-1] EH through fine-grained callbacks
+
+[2-1-1] Overview
+
+ If eh_strategy_handler() is not present, SCSI midlayer takes charge
+of driving error handling.  EH's goals are two - make LLDD, host and
+device forget about timed out scmds and make them ready for new
+commands.  A scmd is said to be recovered if the scmd is forgotten by
+lower layers and lower layers are ready to process or fail the scmd
+again.
+
+ To achieve these goals, EH performs recovery actions with increasing
+severity.  Some actions are performed by issueing SCSI commands and
+others are performed by invoking one of the following fine-grained
+hostt EH callbacks.  Callbacks may be omitted and omitted ones are
+considered to fail always.
+
+int (* eh_abort_handler)(struct scsi_cmnd *);
+int (* eh_device_reset_handler)(struct scsi_cmnd *);
+int (* eh_bus_reset_handler)(struct scsi_cmnd *);
+int (* eh_host_reset_handler)(struct scsi_cmnd *);
+
+ Higher-severity actions are taken only when lower-severity actions
+cannot recover some of failed scmds.  Also, note that failure of the
+highest-severity action means EH failure and results in offlining of
+all unrecovered devices.
+
+ During recovery, the following rules are followed
+
+ - Recovery actions are performed on failed scmds on the to do list,
+   eh_work_q.  If a recovery action succeeds for a scmd, recovered
+   scmds are removed from eh_work_q.
+
+   Note that single recovery action on a scmd can recover multiple
+   scmds.  e.g. resetting a device recovers all failed scmds on the
+   device.
+
+ - Higher severity actions are taken iff eh_work_q is not empty after
+   lower severity actions are complete.
+
+ - EH reuses failed scmds to issue commands for recovery.  For
+   timed-out scmds, SCSI EH ensures that LLDD forgets about a scmd
+   before reusing it for EH commands.
+
+ When a scmd is recovered, the scmd is moved from eh_work_q to EH
+local eh_done_q using scsi_eh_finish_cmd().  After all scmds are
+recovered (eh_work_q is empty), scsi_eh_flush_done_q() is invoked to
+either retry or error-finish (notify upper layer of failure) recovered
+scmds.
+
+ scmds are retried iff its sdev is still online (not offlined during
+EH), REQ_FAILFAST is not set and ++scmd->retries is less than
+scmd->allowed.
+
+
+[2-1-2] Flow of scmds through EH
+
+ 1. Error completion / time out
+    ACTION: scsi_eh_scmd_add() is invoked for scmd
+       - set scmd->eh_eflags
+       - add scmd to shost->eh_cmd_q
+       - set SHOST_RECOVERY
+       - shost->host_failed++
+    LOCKING: shost->host_lock
+
+ 2. EH starts
+    ACTION: move all scmds to EH's local eh_work_q.  shost->eh_cmd_q
+           is cleared.
+    LOCKING: shost->host_lock (not strictly necessary, just for
+             consistency)
+
+ 3. scmd recovered
+    ACTION: scsi_eh_finish_cmd() is invoked to EH-finish scmd
+       - shost->host_failed--
+       - clear scmd->eh_eflags
+       - scsi_setup_cmd_retry()
+       - move from local eh_work_q to local eh_done_q
+    LOCKING: none
+
+ 4. EH completes
+    ACTION: scsi_eh_flush_done_q() retries scmds or notifies upper
+           layer of failure.
+       - scmd is removed from eh_done_q and scmd->eh_entry is cleared
+       - if retry is necessary, scmd is requeued using
+          scsi_queue_insert()
+       - otherwise, scsi_finish_command() is invoked for scmd
+    LOCKING: queue or finish function performs appropriate locking
+
+
+[2-1-3] Flow of control
+
+ EH through fine-grained callbacks start from scsi_unjam_host().
+
+<<scsi_unjam_host>>
+
+    1. Lock shost->host_lock, splice_init shost->eh_cmd_q into local
+       eh_work_q and unlock host_lock.  Note that shost->eh_cmd_q is
+       cleared by this action.
+
+    2. Invoke scsi_eh_get_sense.
+
+    <<scsi_eh_get_sense>>
+
+       This action is taken for each error-completed
+       (!SCSI_EH_CANCEL_CMD) commands without valid sense data.  Most
+       SCSI transports/LLDDs automatically acquire sense data on
+       command failures (autosense).  Autosense is recommended for
+       performance reasons and as sense information could get out of
+       sync inbetween occurrence of CHECK CONDITION and this action.
+
+       Note that if autosense is not supported, scmd->sense_buffer
+       contains invalid sense data when error-completing the scmd
+       with scsi_done().  scsi_decide_disposition() always returns
+       FAILED in such cases thus invoking SCSI EH.  When the scmd
+       reaches here, sense data is acquired and
+       scsi_decide_disposition() is called again.
+
+       1. Invoke scsi_request_sense() which issues REQUEST_SENSE
+           command.  If fails, no action.  Note that taking no action
+           causes higher-severity recovery to be taken for the scmd.
+
+       2. Invoke scsi_decide_disposition() on the scmd
+
+          - SUCCESS
+               scmd->retries is set to scmd->allowed preventing
+               scsi_eh_flush_done_q() from retrying the scmd and
+               scsi_eh_finish_cmd() is invoked.
+
+          - NEEDS_RETRY
+               scsi_eh_finish_cmd() invoked
+
+          - otherwise
+               No action.
+
+    3. If !list_empty(&eh_work_q), invoke scsi_eh_abort_cmds().
+
+    <<scsi_eh_abort_cmds>>
+
+       This action is taken for each timed out command.
+       hostt->eh_abort_handler() is invoked for each scmd.  The
+       handler returns SUCCESS if it has succeeded to make LLDD and
+       all related hardware forget about the scmd.
+
+       If a timedout scmd is successfully aborted and the sdev is
+       either offline or ready, scsi_eh_finish_cmd() is invoked for
+       the scmd.  Otherwise, the scmd is left in eh_work_q for
+       higher-severity actions.
+
+       Note that both offline and ready status mean that the sdev is
+       ready to process new scmds, where processing also implies
+       immediate failing; thus, if a sdev is in one of the two
+       states, no further recovery action is needed.
+
+       Device readiness is tested using scsi_eh_tur() which issues
+       TEST_UNIT_READY command.  Note that the scmd must have been
+       aborted successfully before reusing it for TEST_UNIT_READY.
+
+    4. If !list_empty(&eh_work_q), invoke scsi_eh_ready_devs()
+
+    <<scsi_eh_ready_devs>>
+
+       This function takes four increasingly more severe measures to
+       make failed sdevs ready for new commands.
+
+       1. Invoke scsi_eh_stu()
+
+       <<scsi_eh_stu>>
+
+           For each sdev which has failed scmds with valid sense data
+           of which scsi_check_sense()'s verdict is FAILED,
+           START_STOP_UNIT command is issued w/ start=1.  Note that
+           as we explicitly choose error-completed scmds, it is known
+           that lower layers have forgotten about the scmd and we can
+           reuse it for STU.
+
+           If STU succeeds and the sdev is either offline or ready,
+           all failed scmds on the sdev are EH-finished with
+           scsi_eh_finish_cmd().
+
+           *NOTE* If hostt->eh_abort_handler() isn't implemented or
+           failed, we may still have timed out scmds at this point
+           and STU doesn't make lower layers forget about those
+           scmds.  Yet, this function EH-finish all scmds on the sdev
+           if STU succeeds leaving lower layers in an inconsistent
+           state.  It seems that STU action should be taken only when
+           a sdev has no timed out scmd.
+
+       2. If !list_empty(&eh_work_q), invoke scsi_eh_bus_device_reset().
+
+       <<scsi_eh_bus_device_reset>>
+
+           This action is very similar to scsi_eh_stu() except that,
+           instead of issuing STU, hostt->eh_device_reset_handler()
+           is used.  Also, as we're not issuing SCSI commands and
+           resetting clears all scmds on the sdev, there is no need
+           to choose error-completed scmds.
+
+       3. If !list_empty(&eh_work_q), invoke scsi_eh_bus_reset()
+
+       <<scsi_eh_bus_reset>>
+
+           hostt->eh_bus_reset_handler() is invoked for each channel
+           with failed scmds.  If bus reset succeeds, all failed
+           scmds on all ready or offline sdevs on the channel are
+           EH-finished.
+
+       4. If !list_empty(&eh_work_q), invoke scsi_eh_host_reset()
+
+       <<scsi_eh_host_reset>>
+
+           This is the last resort.  hostt->eh_host_reset_handler()
+           is invoked.  If host reset succeeds, all failed scmds on
+           all ready or offline sdevs on the host are EH-finished.
+
+       5. If !list_empty(&eh_work_q), invoke scsi_eh_offline_sdevs()
+
+       <<scsi_eh_offline_sdevs>>
+
+           Take all sdevs which still have unrecovered scmds offline
+           and EH-finish the scmds.
+
+    5. Invoke scsi_eh_flush_done_q().
+
+       <<scsi_eh_flush_done_q>>
+
+           At this point all scmds are recovered (or given up) and
+           put on eh_done_q by scsi_eh_finish_cmd().  This function
+           flushes eh_done_q by either retrying or notifying upper
+           layer of failure of the scmds.
+
+
+[2-2] EH through hostt->eh_strategy_handler()
+
+ hostt->eh_strategy_handler() is invoked in the place of
+scsi_unjam_host() and it is responsible for whole recovery process.
+On completion, the handler should have made lower layers forget about
+all failed scmds and either ready for new commands or offline.  Also,
+it should perform SCSI EH maintenance choirs to maintain integrity of
+SCSI midlayer.  IOW, of the steps described in [2-1-2], all steps
+except for #1 must be implemented by eh_strategy_handler().
+
+
+[2-2-1] Pre hostt->eh_strategy_handler() SCSI midlayer conditions
+
+ The following conditions are true on entry to the handler.
+
+ - Each failed scmd's eh_flags field is set appropriately.
+
+ - Each failed scmd is linked on scmd->eh_cmd_q by scmd->eh_entry.
+
+ - SHOST_RECOVERY is set.
+
+ - shost->host_failed == shost->host_busy
+
+
+[2-2-2] Post hostt->eh_strategy_handler() SCSI midlayer conditions
+
+ The following conditions must be true on exit from the handler.
+
+ - shost->host_failed is zero.
+
+ - Each scmd's eh_eflags field is cleared.
+
+ - Each scmd is in such a state that scsi_setup_cmd_retry() on the
+   scmd doesn't make any difference.
+
+ - shost->eh_cmd_q is cleared.
+
+ - Each scmd->eh_entry is cleared.
+
+ - Either scsi_queue_insert() or scsi_finish_command() is called on
+   each scmd.  Note that the handler is free to use scmd->retries and
+   ->allowed to limit the number of retries.
+
+
+[2-2-3] Things to consider
+
+ - Know that timed out scmds are still active on lower layers.  Make
+   lower layers forget about them before doing anything else with
+   those scmds.
+
+ - For consistency, when accessing/modifying shost data structure,
+   grab shost->host_lock.
+
+ - On completion, each failed sdev must have forgotten about all
+   active scmds.
+
+ - On completion, each failed sdev must be ready for new commands or
+   offline.
+
+
+--
+Tejun Heo
+htejun@gmail.com
+11th September 2005
index 729c72d34c89237912a3bb5dc501405dfeff0384..f86550fe38ee21afc0381a991ac4e58b07426f57 100644 (file)
@@ -20,7 +20,7 @@ the /proc/bus/usb/BBB/DDD files.
 
          to /etc/fstab.  This will mount usbfs at each reboot.
          You can then issue `cat /proc/bus/usb/devices` to extract
-         USB device information, and user mode drivers can use usbfs 
+         USB device information, and user mode drivers can use usbfs
          to interact with USB devices.
 
          There are a number of mount options supported by usbfs.
@@ -32,7 +32,7 @@ the /proc/bus/usb/BBB/DDD files.
          still see references to the older "usbdevfs" name.
 
 For more information on mounting the usbfs file system, see the
-"USB Device Filesystem" section of the USB Guide. The latest copy 
+"USB Device Filesystem" section of the USB Guide. The latest copy
 of the USB Guide can be found at http://www.linux-usb.org/
 
 
@@ -133,7 +133,7 @@ B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
     are the only transfers that reserve bandwidth.  Control and bulk
     transfers use all other bandwidth, including reserved bandwidth that
     is not used for transfers (such as for short packets).
-    
+
     The percentage is how much of the "reserved" bandwidth is scheduled by
     those transfers.  For a low or full speed bus (loosely, "USB 1.1"),
     90% of the bus bandwidth is reserved.  For a high speed bus (loosely,
@@ -197,7 +197,7 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
 | | |__NumberOfInterfaces
 | |__ "*" indicates the active configuration (others are " ")
 |__Config info tag
-    
+
     USB devices may have multiple configurations, each of which act
     rather differently.  For example, a bus-powered configuration
     might be much less capable than one that is self-powered.  Only
@@ -228,7 +228,7 @@ I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
     For example, default settings may not use more than a small
     amount of periodic bandwidth.  To use significant fractions
     of bus bandwidth, drivers must select a non-default altsetting.
-    
+
     Only one setting for an interface may be active at a time, and
     only one driver may bind to an interface at a time.  Most devices
     have only one alternate setting per interface.
@@ -297,18 +297,21 @@ S:  SerialNumber=dce0
 C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
 I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
 E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
+
 T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
 D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 P:  Vendor=0451 ProdID=1446 Rev= 1.00
 C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
 I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
 E:  Ad=81(I) Atr=03(Int.) MxPS=   1 Ivl=255ms
+
 T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
 D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 P:  Vendor=04b4 ProdID=0001 Rev= 0.00
 C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
 I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
 E:  Ad=81(I) Atr=03(Int.) MxPS=   3 Ivl= 10ms
+
 T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
 D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 P:  Vendor=0565 ProdID=0001 Rev= 1.08
index 678e8f192db2917c741ca0b88ddc97f761a4a8d7..ffe1c062088b9daa52954b2dd6054975f52b9a7b 100644 (file)
@@ -11,6 +11,11 @@ Machine check
                If your BIOS doesn't do that it's a good idea to enable though
                to make sure you log even machine check events that result
                in a reboot.
+   mce=tolerancelevel (number)
+               0: always panic, 1: panic if deadlock possible,
+               2: try to avoid panic, 3: never panic or exit (for testing)
+               default is 1
+               Can be also set using sysfs which is preferable.
 
    nomce (for compatibility with i386): same as mce=off
 
index f038dca34ee826b543db0d54f40623e954e5bf72..a67bf7d315d7ee14923789fc66eb08649178f4ce 100644 (file)
@@ -964,6 +964,13 @@ L: lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.nu/
 S:     Maintained
 
+HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
+P:     Robert Love
+M:     rlove@rlove.org
+M:     linux-kernel@vger.kernel.org
+W:     http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/
+S:     Maintained
+
 HARMONY SOUND DRIVER
 P:     Kyle McMartin
 M:     kyle@parisc-linux.org
index 45e5a38fbc7aee34f68a852e4a6530609ccc52f2..4e0d7c68d2231fa1605378f8d637e19e347008b7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 13
-EXTRAVERSION =
+SUBLEVEL = 14
+EXTRAVERSION =-rc1
 NAME=Affluent Albatross
 
 # *DOCUMENTATION*
index 405a55f2287cc8b0b459f431effca8bc25d4ebdb..3e5f69bb5ac40764427b4d0d09ee1bedb040c1e9 100644 (file)
@@ -20,40 +20,66 @@ config ARCH_PXA_IDP
        select PXA25x
 
 config PXA_SHARPSL
-       bool "SHARP SL-5600 and SL-C7xx Models"
-       select PXA25x
+       bool "SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models"
        select SHARP_SCOOP
        select SHARP_PARAM
        help
          Say Y here if you intend to run this kernel on a
-         Sharp SL-5600 (Poodle), Sharp SL-C700 (Corgi),
-         SL-C750 (Shepherd) or a Sharp SL-C760 (Husky)
-         handheld computer.
+         Sharp Zaurus SL-5600 (Poodle), SL-C700 (Corgi),
+         SL-C750 (Shepherd), SL-C760 (Husky), SL-C1000 (Akita),
+         SL-C3000 (Spitz) or SL-C3100 (Borzoi) handheld computer.
 
 endchoice
 
+if PXA_SHARPSL
+
+choice
+       prompt "Select target Sharp Zaurus device range"
+
+config PXA_SHARPSL_25x
+       bool "Sharp PXA25x models (SL-5600 and SL-C7xx)"
+       select PXA25x
+
+config PXA_SHARPSL_27x
+       bool "Sharp PXA270 models (SL-Cxx00)"
+       select PXA27x
+
+endchoice
+
+endif
+
 endmenu
 
 config MACH_POODLE
        bool "Enable Sharp SL-5600 (Poodle) Support"
-       depends PXA_SHARPSL
+       depends PXA_SHARPSL_25x
        select SHARP_LOCOMO
 
 config MACH_CORGI
        bool "Enable Sharp SL-C700 (Corgi) Support"
-       depends PXA_SHARPSL
+       depends PXA_SHARPSL_25x
        select PXA_SHARP_C7xx
 
 config MACH_SHEPHERD
        bool "Enable Sharp SL-C750 (Shepherd) Support"
-       depends PXA_SHARPSL
+       depends PXA_SHARPSL_25x
        select PXA_SHARP_C7xx
 
 config MACH_HUSKY
        bool "Enable Sharp SL-C760 (Husky) Support"
-       depends PXA_SHARPSL
+       depends PXA_SHARPSL_25x
        select PXA_SHARP_C7xx
 
+config MACH_SPITZ
+       bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
+       depends PXA_SHARPSL_27x
+       select PXA_SHARP_Cxx00
+
+config MACH_BORZOI
+       bool "Enable Sharp Zaurus SL-3100 (Borzoi) Support"
+       depends PXA_SHARPSL_27x
+       select PXA_SHARP_Cxx00
+
 config PXA25x
        bool
        help
@@ -74,4 +100,9 @@ config PXA_SHARP_C7xx
        help
          Enable support for all Sharp C7xx models
 
+config PXA_SHARP_Cxx00
+       bool
+       help
+         Enable common support for Sharp Cxx00 models
+
 endif
index 33dae99ec2d843290105013226519a47e3a50daf..f609a0f232cb6424918bda6f494e633b24f45382 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
 obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
 obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
 obj-$(CONFIG_PXA_SHARP_C7xx)   += corgi.o corgi_ssp.o corgi_lcd.o ssp.o
+obj-$(CONFIG_PXA_SHARP_Cxx00)  += spitz.o corgi_ssp.o corgi_lcd.o ssp.o
 obj-$(CONFIG_MACH_POODLE)      += poodle.o
 
 # Support for blinky lights
index 07b5dd453565402d9ec8c69b691681bae063be5a..426c2bc517eb7ca8fd42a06fa2e6b0d971b24324 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/hardware/scoop.h>
 
 #include "generic.h"
+#include "sharpsl.h"
 
 
 /*
@@ -94,14 +95,30 @@ struct platform_device corgissp_device = {
        .id             = -1,
 };
 
+struct corgissp_machinfo corgi_ssp_machinfo = {
+       .port           = 1,
+       .cs_lcdcon      = CORGI_GPIO_LCDCON_CS,
+       .cs_ads7846     = CORGI_GPIO_ADS7846_CS,
+       .cs_max1111     = CORGI_GPIO_MAX1111_CS,
+       .clk_lcdcon     = 76,
+       .clk_ads7846    = 2,
+       .clk_max1111    = 8,
+};
+
 
 /*
  * Corgi Backlight Device
  */
+static struct corgibl_machinfo corgi_bl_machinfo = {
+       .max_intensity = 0x2f,
+       .set_bl_intensity = corgi_bl_set_intensity,
+};
+
 static struct platform_device corgibl_device = {
        .name           = "corgi-bl",
        .dev            = {
                .parent = &corgifb_device.dev,
+               .platform_data  = &corgi_bl_machinfo,
        },
        .id             = -1,
 };
@@ -119,12 +136,29 @@ static struct platform_device corgikbd_device = {
 /*
  * Corgi Touch Screen Device
  */
+static struct resource corgits_resources[] = {
+       [0] = {
+               .start          = CORGI_IRQ_GPIO_TP_INT,
+               .end            = CORGI_IRQ_GPIO_TP_INT,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct corgits_machinfo  corgi_ts_machinfo = {
+       .get_hsync_len   = corgi_get_hsync_len,
+       .put_hsync       = corgi_put_hsync,
+       .wait_hsync      = corgi_wait_hsync,
+};
+
 static struct platform_device corgits_device = {
        .name           = "corgi-ts",
        .dev            = {
                .parent = &corgissp_device.dev,
+               .platform_data  = &corgi_ts_machinfo,
        },
        .id             = -1,
+       .num_resources  = ARRAY_SIZE(corgits_resources),
+       .resource       = corgits_resources,
 };
 
 
@@ -225,7 +259,10 @@ static struct platform_device *devices[] __initdata = {
 
 static void __init corgi_init(void)
 {
+       corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
+
        pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
+       pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
        pxa_set_udc_info(&udc_info);
        pxa_set_mci_info(&corgi_mci_platform_data);
 
index deac29c0029019136f87df697ac9d2e1f46334bb..c5efcd04fcbc8011c01961ca334a080dcf62005a 100644 (file)
@@ -1,10 +1,14 @@
 /*
  * linux/drivers/video/w100fb.c
  *
- * Corgi LCD Specific Code for ATI Imageon w100 (Wallaby)
+ * Corgi/Spitz LCD Specific Code
  *
  * Copyright (C) 2005 Richard Purdie
  *
+ * Connectivity:
+ *   Corgi - LCD to ATI Imageon w100 (Wallaby)
+ *   Spitz - LCD to PXA Framebuffer
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
+#include <linux/module.h>
+#include <asm/mach-types.h>
+#include <asm/arch/akita.h>
 #include <asm/arch/corgi.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/sharpsl.h>
+#include <asm/arch/spitz.h>
+#include <asm/hardware/scoop.h>
 #include <asm/mach/sharpsl_param.h>
-#include <video/w100fb.h>
+#include "generic.h"
 
 /* Register Addresses */
 #define RESCTL_ADRS     0x00
@@ -134,10 +146,10 @@ static void lcdtg_set_common_voltage(u8 base_data, u8 data)
 }
 
 /* Set Phase Adjuct */
-static void lcdtg_set_phadadj(struct w100fb_par *par)
+static void lcdtg_set_phadadj(int mode)
 {
        int adj;
-       switch(par->xres) {
+       switch(mode) {
                case 480:
                case 640:
                        /* Setting for VGA */
@@ -161,7 +173,7 @@ static void lcdtg_set_phadadj(struct w100fb_par *par)
 
 static int lcd_inited;
 
-static void lcdtg_hw_init(struct w100fb_par *par)
+static void lcdtg_hw_init(int mode)
 {
        if (!lcd_inited) {
                int comadj;
@@ -215,7 +227,7 @@ static void lcdtg_hw_init(struct w100fb_par *par)
                corgi_ssp_lcdtg_send(PICTRL_ADRS, 0);
 
                /* Set Phase Adjuct */
-               lcdtg_set_phadadj(par);
+               lcdtg_set_phadadj(mode);
 
                /* Initialize for Input Signals from ATI */
                corgi_ssp_lcdtg_send(POLCTRL_ADRS, POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE
@@ -224,10 +236,10 @@ static void lcdtg_hw_init(struct w100fb_par *par)
 
                lcd_inited=1;
        } else {
-               lcdtg_set_phadadj(par);
+               lcdtg_set_phadadj(mode);
        }
 
-       switch(par->xres) {
+       switch(mode) {
                case 480:
                case 640:
                        /* Set Lcd Resolution (VGA) */
@@ -242,7 +254,7 @@ static void lcdtg_hw_init(struct w100fb_par *par)
        }
 }
 
-static void lcdtg_suspend(struct w100fb_par *par)
+static void lcdtg_suspend(void)
 {
        /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
        mdelay(34);
@@ -276,15 +288,30 @@ static void lcdtg_suspend(struct w100fb_par *par)
        lcd_inited = 0;
 }
 
-static struct w100_tg_info corgi_lcdtg_info = {
-       .change=lcdtg_hw_init,
-       .suspend=lcdtg_suspend,
-       .resume=lcdtg_hw_init,
-};
 
 /*
  * Corgi w100 Frame Buffer Device
  */
+#ifdef CONFIG_PXA_SHARP_C7xx
+
+#include <video/w100fb.h>
+
+static void w100_lcdtg_suspend(struct w100fb_par *par)
+{
+       lcdtg_suspend();
+}
+
+static void w100_lcdtg_init(struct w100fb_par *par)
+{
+       lcdtg_hw_init(par->xres);
+}
+
+
+static struct w100_tg_info corgi_lcdtg_info = {
+       .change  = w100_lcdtg_init,
+       .suspend = w100_lcdtg_suspend,
+       .resume  = w100_lcdtg_init,
+};
 
 static struct w100_mem_info corgi_fb_mem = {
        .ext_cntl          = 0x00040003,
@@ -394,3 +421,145 @@ struct platform_device corgifb_device = {
        },
 
 };
+#endif
+
+
+/*
+ * Spitz PXA Frame Buffer Device
+ */
+#ifdef CONFIG_PXA_SHARP_Cxx00
+
+#include <asm/arch/pxafb.h>
+
+void spitz_lcd_power(int on)
+{
+       if (on)
+               lcdtg_hw_init(480);
+       else
+               lcdtg_suspend();
+}
+
+#endif
+
+
+/*
+ * Corgi/Spitz Touchscreen to LCD interface
+ */
+static unsigned long (*get_hsync_time)(struct device *dev);
+
+static void inline sharpsl_wait_sync(int gpio)
+{
+       while((GPLR(gpio) & GPIO_bit(gpio)) == 0);
+       while((GPLR(gpio) & GPIO_bit(gpio)) != 0);
+}
+
+#ifdef CONFIG_PXA_SHARP_C7xx
+unsigned long corgi_get_hsync_len(void)
+{
+       if (!get_hsync_time)
+               get_hsync_time = symbol_get(w100fb_get_hsynclen);
+       if (!get_hsync_time)
+               return 0;
+
+       return get_hsync_time(&corgifb_device.dev);
+}
+
+void corgi_put_hsync(void)
+{
+       if (get_hsync_time)
+               symbol_put(w100fb_get_hsynclen);
+}
+
+void corgi_wait_hsync(void)
+{
+       sharpsl_wait_sync(CORGI_GPIO_HSYNC);
+}
+#endif
+
+#ifdef CONFIG_PXA_SHARP_Cxx00
+unsigned long spitz_get_hsync_len(void)
+{
+       if (!get_hsync_time)
+               get_hsync_time = symbol_get(pxafb_get_hsync_time);
+       if (!get_hsync_time)
+               return 0;
+
+       return pxafb_get_hsync_time(&pxafb_device.dev);
+}
+
+void spitz_put_hsync(void)
+{
+       if (get_hsync_time)
+               symbol_put(pxafb_get_hsync_time);
+}
+
+void spitz_wait_hsync(void)
+{
+       sharpsl_wait_sync(SPITZ_GPIO_HSYNC);
+}
+#endif
+
+/*
+ * Corgi/Spitz Backlight Power
+ */
+#ifdef CONFIG_PXA_SHARP_C7xx
+void corgi_bl_set_intensity(int intensity)
+{
+       if (intensity > 0x10)
+               intensity += 0x10;
+
+       /* Bits 0-4 are accessed via the SSP interface */
+       corgi_ssp_blduty_set(intensity & 0x1f);
+
+       /* Bit 5 is via SCOOP */
+       if (intensity & 0x0020)
+               set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
+       else
+               reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
+}
+#endif
+
+
+#if defined(CONFIG_MACH_SPITZ) || defined(CONFIG_MACH_BORZOI)
+void spitz_bl_set_intensity(int intensity)
+{
+       if (intensity > 0x10)
+               intensity += 0x10;
+
+       /* Bits 0-4 are accessed via the SSP interface */
+       corgi_ssp_blduty_set(intensity & 0x1f);
+
+       /* Bit 5 is via SCOOP */
+       if (intensity & 0x0020)
+               reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT);
+       else
+               set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT);
+
+       if (intensity)
+               set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON);
+       else
+               reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON);
+}
+#endif
+
+#ifdef CONFIG_MACH_AKITA
+void akita_bl_set_intensity(int intensity)
+{
+       if (intensity > 0x10)
+               intensity += 0x10;
+
+       /* Bits 0-4 are accessed via the SSP interface */
+       corgi_ssp_blduty_set(intensity & 0x1f);
+
+       /* Bit 5 is via IO-Expander */
+       if (intensity & 0x0020)
+               akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT);
+       else
+               akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT);
+
+       if (intensity)
+               akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON);
+       else
+               akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON);
+}
+#endif
index 366a9bde3d8be08880231795926d834839d35ddc..0ef42828705526b5fc06823144791e3a93351fbb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  SSP control code for Sharp Corgi devices
  *
- *  Copyright (c) 2004 Richard Purdie
+ *  Copyright (c) 2004-2005 Richard Purdie
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 
 #include <asm/arch/ssp.h>
-#include <asm/arch/corgi.h>
 #include <asm/arch/pxa-regs.h>
+#include "sharpsl.h"
 
 static DEFINE_SPINLOCK(corgi_ssp_lock);
 static struct ssp_dev corgi_ssp_dev;
 static struct ssp_state corgi_ssp_state;
+static struct corgissp_machinfo *ssp_machinfo;
 
 /*
  * There are three devices connected to the SSP interface:
@@ -48,12 +50,12 @@ unsigned long corgi_ssp_ads7846_putget(ulong data)
        unsigned long ret,flag;
 
        spin_lock_irqsave(&corgi_ssp_lock, flag);
-       GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+       GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
 
        ssp_write_word(&corgi_ssp_dev,data);
        ret = ssp_read_word(&corgi_ssp_dev);
 
-       GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+       GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
        spin_unlock_irqrestore(&corgi_ssp_lock, flag);
 
        return ret;
@@ -66,12 +68,12 @@ unsigned long corgi_ssp_ads7846_putget(ulong data)
 void corgi_ssp_ads7846_lock(void)
 {
        spin_lock(&corgi_ssp_lock);
-       GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+       GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
 }
 
 void corgi_ssp_ads7846_unlock(void)
 {
-       GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+       GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
        spin_unlock(&corgi_ssp_lock);
 }
 
@@ -97,23 +99,27 @@ EXPORT_SYMBOL(corgi_ssp_ads7846_get);
  */
 unsigned long corgi_ssp_dac_put(ulong data)
 {
-       unsigned long flag;
+       unsigned long flag, sscr1 = SSCR1_SPH;
 
        spin_lock_irqsave(&corgi_ssp_lock, flag);
-       GPCR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);
+
+       if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi())
+               sscr1 = 0;
 
        ssp_disable(&corgi_ssp_dev);
-       ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), SSCR1_SPH, 0, SSCR0_SerClkDiv(76));
+       ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), sscr1, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_lcdcon));
        ssp_enable(&corgi_ssp_dev);
 
+       GPCR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
        ssp_write_word(&corgi_ssp_dev,data);
        /* Read null data back from device to prevent SSP overflow */
        ssp_read_word(&corgi_ssp_dev);
+       GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
 
        ssp_disable(&corgi_ssp_dev);
-       ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+       ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
        ssp_enable(&corgi_ssp_dev);
-       GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);
+
        spin_unlock_irqrestore(&corgi_ssp_lock, flag);
 
        return 0;
@@ -141,9 +147,9 @@ int corgi_ssp_max1111_get(ulong data)
        int voltage,voltage1,voltage2;
 
        spin_lock_irqsave(&corgi_ssp_lock, flag);
-       GPCR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS);
+       GPCR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
        ssp_disable(&corgi_ssp_dev);
-       ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(8));
+       ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_max1111));
        ssp_enable(&corgi_ssp_dev);
 
        udelay(1);
@@ -161,9 +167,9 @@ int corgi_ssp_max1111_get(ulong data)
        voltage2=ssp_read_word(&corgi_ssp_dev);
 
        ssp_disable(&corgi_ssp_dev);
-       ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+       ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
        ssp_enable(&corgi_ssp_dev);
-       GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS);
+       GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
        spin_unlock_irqrestore(&corgi_ssp_lock, flag);
 
        if (voltage1 & 0xc0 || voltage2 & 0x3f)
@@ -179,25 +185,31 @@ EXPORT_SYMBOL(corgi_ssp_max1111_get);
 /*
  *  Support Routines
  */
-int __init corgi_ssp_probe(struct device *dev)
+
+void __init corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo)
+{
+       ssp_machinfo = machinfo;
+}
+
+static int __init corgi_ssp_probe(struct device *dev)
 {
        int ret;
 
        /* Chip Select - Disable All */
-       GPDR0 |= GPIO_bit(CORGI_GPIO_LCDCON_CS); /* output */
-       GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);  /* High - Disable LCD Control/Timing Gen */
-       GPDR0 |= GPIO_bit(CORGI_GPIO_MAX1111_CS); /* output */
-       GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS);  /* High - Disable MAX1111*/
-       GPDR0 |= GPIO_bit(CORGI_GPIO_ADS7846_CS);  /* output */
-       GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);   /* High - Disable ADS7846*/
+       GPDR(ssp_machinfo->cs_lcdcon) |= GPIO_bit(ssp_machinfo->cs_lcdcon); /* output */
+       GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
+       GPDR(ssp_machinfo->cs_max1111) |= GPIO_bit(ssp_machinfo->cs_max1111); /* output */
+       GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);  /* High - Disable MAX1111*/
+       GPDR(ssp_machinfo->cs_ads7846) |= GPIO_bit(ssp_machinfo->cs_ads7846);  /* output */
+       GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);   /* High - Disable ADS7846*/
 
-       ret=ssp_init(&corgi_ssp_dev,1);
+       ret = ssp_init(&corgi_ssp_dev,ssp_machinfo->port);
 
        if (ret)
                printk(KERN_ERR "Unable to register SSP handler!\n");
        else {
                ssp_disable(&corgi_ssp_dev);
-               ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+               ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
                ssp_enable(&corgi_ssp_dev);
        }
 
@@ -222,9 +234,9 @@ static int corgi_ssp_suspend(struct device *dev, pm_message_t state, u32 level)
 static int corgi_ssp_resume(struct device *dev, u32 level)
 {
        if (level == RESUME_POWER_ON) {
-               GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);  /* High - Disable LCD Control/Timing Gen */
-               GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); /* High - Disable MAX1111*/
-               GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); /* High - Disable ADS7846*/
+               GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
+               GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
+               GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/
                ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
                ssp_enable(&corgi_ssp_dev);
        }
diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h
new file mode 100644 (file)
index 0000000..3977a77
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SharpSL SSP Driver
+ */
+
+struct corgissp_machinfo {
+       int port;
+       int cs_lcdcon;
+       int cs_ads7846;
+       int cs_max1111;
+       int clk_lcdcon;
+       int clk_ads7846;
+       int clk_max1111;
+};
+
+void corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo);
+
+/*
+ * SharpSL Backlight
+ */
+
+void corgi_bl_set_intensity(int intensity);
+void spitz_bl_set_intensity(int intensity);
+void akita_bl_set_intensity(int intensity);
+
+/*
+ * SharpSL Touchscreen Driver
+ */
+
+unsigned long corgi_get_hsync_len(void);
+unsigned long spitz_get_hsync_len(void);
+void corgi_put_hsync(void);
+void spitz_put_hsync(void);
+void corgi_wait_hsync(void);
+void spitz_wait_hsync(void);
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
new file mode 100644 (file)
index 0000000..568afe3
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Support for Sharp SL-Cxx00 Series of PDAs
+ * Models: SL-C3000 (Spitz), SL-C1000 (Akita) and SL-C3100 (Borzoi)
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches/lubbock.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/host.h>
+
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irq.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/udc.h>
+#include <asm/arch/ohci.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/akita.h>
+#include <asm/arch/spitz.h>
+#include <asm/arch/sharpsl.h>
+
+#include <asm/mach/sharpsl_param.h>
+#include <asm/hardware/scoop.h>
+
+#include "generic.h"
+#include "sharpsl.h"
+
+/*
+ * Spitz SCOOP Device #1
+ */
+static struct resource spitz_scoop_resources[] = {
+       [0] = {
+               .start          = 0x10800000,
+               .end            = 0x10800fff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct scoop_config spitz_scoop_setup = {
+       .io_dir         = SPITZ_SCP_IO_DIR,
+       .io_out         = SPITZ_SCP_IO_OUT,
+       .suspend_clr = SPITZ_SCP_SUS_CLR,
+       .suspend_set = SPITZ_SCP_SUS_SET,
+};
+
+struct platform_device spitzscoop_device = {
+       .name           = "sharp-scoop",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &spitz_scoop_setup,
+       },
+       .num_resources  = ARRAY_SIZE(spitz_scoop_resources),
+       .resource       = spitz_scoop_resources,
+};
+
+/*
+ * Spitz SCOOP Device #2
+ */
+static struct resource spitz_scoop2_resources[] = {
+       [0] = {
+               .start          = 0x08800040,
+               .end            = 0x08800fff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct scoop_config spitz_scoop2_setup = {
+       .io_dir         = SPITZ_SCP2_IO_DIR,
+       .io_out         = SPITZ_SCP2_IO_OUT,
+       .suspend_clr = SPITZ_SCP2_SUS_CLR,
+       .suspend_set = SPITZ_SCP2_SUS_SET,
+};
+
+struct platform_device spitzscoop2_device = {
+       .name           = "sharp-scoop",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &spitz_scoop2_setup,
+       },
+       .num_resources  = ARRAY_SIZE(spitz_scoop2_resources),
+       .resource       = spitz_scoop2_resources,
+};
+
+static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = {
+{
+       .dev        = &spitzscoop_device.dev,
+       .irq        = SPITZ_IRQ_GPIO_CF_IRQ,
+       .cd_irq     = SPITZ_IRQ_GPIO_CF_CD,
+       .cd_irq_str = "PCMCIA0 CD",
+},{
+       .dev        = &spitzscoop2_device.dev,
+       .irq        = SPITZ_IRQ_GPIO_CF2_IRQ,
+       .cd_irq     = -1,
+},
+};
+
+
+/*
+ * Spitz SSP Device
+ *
+ * Set the parent as the scoop device because a lot of SSP devices
+ * also use scoop functions and this makes the power up/down order
+ * work correctly.
+ */
+struct platform_device spitzssp_device = {
+       .name           = "corgi-ssp",
+       .dev            = {
+               .parent = &spitzscoop_device.dev,
+       },
+       .id             = -1,
+};
+
+struct corgissp_machinfo spitz_ssp_machinfo = {
+       .port           = 2,
+       .cs_lcdcon      = SPITZ_GPIO_LCDCON_CS,
+       .cs_ads7846     = SPITZ_GPIO_ADS7846_CS,
+       .cs_max1111     = SPITZ_GPIO_MAX1111_CS,
+       .clk_lcdcon     = 520,
+       .clk_ads7846    = 14,
+       .clk_max1111    = 56,
+};
+
+
+/*
+ * Spitz Backlight Device
+ */
+static struct corgibl_machinfo spitz_bl_machinfo = {
+       .max_intensity = 0x2f,
+};
+
+static struct platform_device spitzbl_device = {
+       .name           = "corgi-bl",
+       .dev            = {
+               .platform_data  = &spitz_bl_machinfo,
+       },
+       .id             = -1,
+};
+
+
+/*
+ * Spitz Keyboard Device
+ */
+static struct platform_device spitzkbd_device = {
+       .name           = "spitz-keyboard",
+       .id             = -1,
+};
+
+
+/*
+ * Spitz Touch Screen Device
+ */
+static struct resource spitzts_resources[] = {
+       [0] = {
+               .start          = SPITZ_IRQ_GPIO_TP_INT,
+               .end            = SPITZ_IRQ_GPIO_TP_INT,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct corgits_machinfo  spitz_ts_machinfo = {
+       .get_hsync_len   = spitz_get_hsync_len,
+       .put_hsync       = spitz_put_hsync,
+       .wait_hsync      = spitz_wait_hsync,
+};
+
+static struct platform_device spitzts_device = {
+       .name           = "corgi-ts",
+       .dev            = {
+               .parent = &spitzssp_device.dev,
+               .platform_data  = &spitz_ts_machinfo,
+       },
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(spitzts_resources),
+       .resource       = spitzts_resources,
+};
+
+
+/*
+ * MMC/SD Device
+ *
+ * The card detect interrupt isn't debounced so we delay it by 250ms
+ * to give the card a chance to fully insert/eject.
+ */
+
+static struct pxamci_platform_data spitz_mci_platform_data;
+
+static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+       int err;
+
+       /* setup GPIO for PXA27x MMC controller */
+       pxa_gpio_mode(GPIO32_MMCCLK_MD);
+       pxa_gpio_mode(GPIO112_MMCCMD_MD);
+       pxa_gpio_mode(GPIO92_MMCDAT0_MD);
+       pxa_gpio_mode(GPIO109_MMCDAT1_MD);
+       pxa_gpio_mode(GPIO110_MMCDAT2_MD);
+       pxa_gpio_mode(GPIO111_MMCDAT3_MD);
+       pxa_gpio_mode(SPITZ_GPIO_nSD_DETECT | GPIO_IN);
+       pxa_gpio_mode(SPITZ_GPIO_nSD_WP | GPIO_IN);
+
+       spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250);
+
+       err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int, SA_INTERRUPT,
+                            "MMC card detect", data);
+       if (err) {
+               printk(KERN_ERR "spitz_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+               return -1;
+       }
+
+       set_irq_type(SPITZ_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
+
+       return 0;
+}
+
+/* Power control is shared with one of the CF slots so we have a mess */
+static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
+{
+       struct pxamci_platform_data* p_d = dev->platform_data;
+
+       unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR);
+
+       if (( 1 << vdd) & p_d->ocr_mask) {
+               /* printk(KERN_DEBUG "%s: on\n", __FUNCTION__); */
+               set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+               mdelay(2);
+               write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | 0x04);
+       } else {
+               /* printk(KERN_DEBUG "%s: off\n", __FUNCTION__); */
+               write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr & ~0x04);
+
+               if (!(cpr | 0x02)) {
+                       mdelay(1);
+                       reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+               }
+       }
+}
+
+static int spitz_mci_get_ro(struct device *dev)
+{
+       return GPLR(SPITZ_GPIO_nSD_WP) & GPIO_bit(SPITZ_GPIO_nSD_WP);
+}
+
+static void spitz_mci_exit(struct device *dev, void *data)
+{
+       free_irq(SPITZ_IRQ_GPIO_nSD_DETECT, data);
+}
+
+static struct pxamci_platform_data spitz_mci_platform_data = {
+       .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
+       .init           = spitz_mci_init,
+       .get_ro         = spitz_mci_get_ro,
+       .setpower       = spitz_mci_setpower,
+       .exit           = spitz_mci_exit,
+};
+
+
+/*
+ * Spitz PXA Framebuffer
+ */
+static struct pxafb_mach_info spitz_pxafb_info __initdata = {
+        .pixclock       = 19231,
+        .xres           = 480,
+        .yres           = 640,
+        .bpp            = 16,
+        .hsync_len      = 40,
+        .left_margin    = 46,
+        .right_margin   = 125,
+        .vsync_len      = 3,
+        .upper_margin   = 1,
+        .lower_margin   = 0,
+        .sync           = 0,
+        .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
+        .lccr3          = LCCR3_PixRsEdg | LCCR3_OutEnH,
+        .pxafb_lcd_power = spitz_lcd_power,
+};
+
+
+static struct platform_device *devices[] __initdata = {
+       &spitzscoop_device,
+       &spitzssp_device,
+       &spitzkbd_device,
+       &spitzts_device,
+       &spitzbl_device,
+       &spitzbattery_device,
+};
+
+static void __init common_init(void)
+{
+       PMCR = 0x00;
+
+       /* setup sleep mode values */
+       PWER  = 0x00000002;
+       PFER  = 0x00000000;
+       PRER  = 0x00000002;
+       PGSR0 = 0x0158C000;
+       PGSR1 = 0x00FF0080;
+       PGSR2 = 0x0001C004;
+
+       /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
+       PCFR |= PCFR_OPDE;
+
+       corgi_ssp_set_machinfo(&spitz_ssp_machinfo);
+
+       pxa_gpio_mode(SPITZ_GPIO_HSYNC | GPIO_IN);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+       pxa_set_mci_info(&spitz_mci_platform_data);
+       pxafb_device.dev.parent = &spitzssp_device.dev;
+       set_pxa_fb_info(&spitz_pxafb_info);
+}
+
+static void __init spitz_init(void)
+{
+       scoop_num = 2;
+       scoop_devs = &spitz_pcmcia_scoop[0];
+       spitz_bl_machinfo.set_bl_intensity = spitz_bl_set_intensity;
+
+       common_init();
+
+       platform_device_register(&spitzscoop2_device);
+}
+
+static void __init fixup_spitz(struct machine_desc *desc,
+               struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+       sharpsl_save_param();
+       mi->nr_banks = 1;
+       mi->bank[0].start = 0xa0000000;
+       mi->bank[0].node = 0;
+       mi->bank[0].size = (64*1024*1024);
+}
+
+#ifdef CONFIG_MACH_SPITZ
+MACHINE_START(SPITZ, "SHARP Spitz")
+       .phys_ram       = 0xa0000000,
+       .phys_io        = 0x40000000,
+       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .fixup          = fixup_spitz,
+       .map_io         = pxa_map_io,
+       .init_irq       = pxa_init_irq,
+       .init_machine   = spitz_init,
+       .timer          = &pxa_timer,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_BORZOI
+MACHINE_START(BORZOI, "SHARP Borzoi")
+       .phys_ram       = 0xa0000000,
+       .phys_io        = 0x40000000,
+       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .fixup          = fixup_spitz,
+       .map_io         = pxa_map_io,
+       .init_irq       = pxa_init_irq,
+       .init_machine   = spitz_init,
+       .timer          = &pxa_timer,
+MACHINE_END
+#endif
index f1b9d2a46dab860c0cbf100e1bf6b9b0b220c024..1ae2aeeda18bddbbc23ec37702d2ed4878ee23d0 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/pci.h>
 #include <asm/pci-direct.h>
 #include <asm/acpi.h>
+#include <asm/apic.h>
 
 static int __init check_bridge(int vendor, int device)
 {
@@ -15,6 +16,15 @@ static int __init check_bridge(int vendor, int device)
        if (vendor == PCI_VENDOR_ID_NVIDIA) {
                acpi_skip_timer_override = 1;
        }
+#ifdef CONFIG_X86_LOCAL_APIC
+       /*
+        * ATI IXP chipsets get double timer interrupts.
+        * For now just do this for all ATI chipsets.
+        * FIXME: this needs to be checked for the non ACPI case too.
+        */
+       if (vendor == PCI_VENDOR_ID_ATI)
+               disable_timer_pin_1 = 1;
+#endif
        return 0;
 }
 
index 3aad03839660de38dd8c24361ecbd6814de5eb52..9e24f7b207ee1636eabcafc48f6f630b56ed8d3e 100644 (file)
@@ -319,7 +319,7 @@ work_notifysig:                             # deal with pending signals and
                                        # vm86-space
        xorl %edx, %edx
        call do_notify_resume
-       jmp restore_all
+       jmp resume_userspace
 
        ALIGN
 work_notifysig_v86:
@@ -329,7 +329,7 @@ work_notifysig_v86:
        movl %eax, %esp
        xorl %edx, %edx
        call do_notify_resume
-       jmp restore_all
+       jmp resume_userspace
 
        # perform syscall exit tracing
        ALIGN
index 35d3ce26a544aed8d45b3428444d0211c3593e3c..378313b0cce9ac9ba8de933303e5e432959cfa05 100644 (file)
@@ -60,6 +60,8 @@ int sis_apic_bug = -1;
  */
 int nr_ioapic_registers[MAX_IO_APICS];
 
+int disable_timer_pin_1 __initdata;
+
 /*
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
@@ -2211,6 +2213,8 @@ static inline void check_timer(void)
                                setup_nmi();
                                enable_8259A_irq(0);
                        }
+                       if (disable_timer_pin_1 > 0)
+                               clear_IO_APIC_pin(0, pin1);
                        return;
                }
                clear_IO_APIC_pin(0, pin1);
index 1cbb9c0f47040d9eb430e738f81871ff18aeacee..350ea6680f63782dcfb237480f83c42b9229005a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/efi.h>
 #include <linux/dmi.h>
+#include <linux/ctype.h>
 #include <asm/uaccess.h>
 #include <asm/apic.h>
 #include <asm/desc.h>
@@ -28,8 +29,6 @@ static int reboot_thru_bios;
 
 #ifdef CONFIG_SMP
 static int reboot_cpu = -1;
-/* shamelessly grabbed from lib/vsprintf.c for readability */
-#define is_digit(c)    ((c) >= '0' && (c) <= '9')
 #endif
 static int __init reboot_setup(char *str)
 {
@@ -49,9 +48,9 @@ static int __init reboot_setup(char *str)
                        break;
 #ifdef CONFIG_SMP
                case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
-                       if (is_digit(*(str+1))) {
+                       if (isdigit(*(str+1))) {
                                reboot_cpu = (int) (*(str+1) - '0');
-                               if (is_digit(*(str+2))) 
+                               if (isdigit(*(str+2)))
                                        reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
                        }
                                /* we will leave sorting out the final value 
index f3d808451d253ecc08ae6ab30b68eba39f351e69..dc39ca6a7eca82f546c649cb6b2e1b3c6a20b4a2 100644 (file)
@@ -851,6 +851,11 @@ static void __init parse_cmdline_early (char ** cmdline_p)
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
+               if (!memcmp(from, "disable_timer_pin_1", 19))
+                       disable_timer_pin_1 = 1;
+               if (!memcmp(from, "enable_timer_pin_1", 18))
+                       disable_timer_pin_1 = -1;
+
                /* disable IO-APIC */
                else if (!memcmp(from, "noapic", 6))
                        disable_ioapic_setup();
index c70cd2a083045ea7ff12069a1fce5e9444cd6257..5f0a95d76a4f16fa3c95ba57c131c6eb3c967046 100644 (file)
@@ -202,7 +202,7 @@ static void __devinit smp_store_cpu_info(int id)
                                goto valid_k7;
 
                /* If we get here, it's not a certified SMP capable AMD system. */
-               tainted |= TAINT_UNSAFE_SMP;
+               add_taint(TAINT_UNSAFE_SMP);
        }
 
 valid_k7:
index 7b3b27d64409381a9a557a58b6543feade5e6b9f..516bf5653b0266ea1f4beb9258bd6577c0b3e6ab 100644 (file)
@@ -213,12 +213,18 @@ static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_c
                node_end_pfn[nid] = memory_chunk->end_pfn;
 }
 
+static u8 pxm_to_nid_map[MAX_PXM_DOMAINS];/* _PXM to logical node ID map */
+
+int pxm_to_node(int pxm)
+{
+       return pxm_to_nid_map[pxm];
+}
+
 /* Parse the ACPI Static Resource Affinity Table */
 static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
 {
        u8 *start, *end, *p;
        int i, j, nid;
-       u8 pxm_to_nid_map[MAX_PXM_DOMAINS];/* _PXM to logical node ID map */
        u8 nid_to_pxm_map[MAX_NUMNODES];/* logical node ID to _PXM map */
 
        start = (u8 *)(&(sratp->reserved) + 1); /* skip header */
index 42913f43feb0edca0015a1f2013c609cc361d802..2941674f35eb5aae272a3000edd491993ec1b0aa 100644 (file)
@@ -3,16 +3,31 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <asm/hw_irq.h>
+#include <asm/numa.h>
 #include "pci.h"
 
 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
 {
+       struct pci_bus *bus;
+
        if (domain != 0) {
                printk(KERN_WARNING "PCI: Multiple domains not supported\n");
                return NULL;
        }
 
-       return pcibios_scan_root(busnum);
+       bus = pcibios_scan_root(busnum);
+#ifdef CONFIG_ACPI_NUMA
+       if (bus != NULL) {
+               int pxm = acpi_get_pxm(device->handle);
+               if (pxm >= 0) {
+                       bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm);
+                       printk("bus %d -> pxm %d -> node %ld\n",
+                               busnum, pxm, (long)(bus->sysdata));
+               }
+       }
+#endif
+       
+       return bus;
 }
 
 extern int pci_routeirq;
index 60f0e7a1162aafa3be94b2806384106dc1aee172..dfbf80cff8346af0504df3601e6e251becc7de06 100644 (file)
@@ -127,13 +127,6 @@ static int __init pci_mmcfg_init(void)
            (pci_mmcfg_config[0].base_address == 0))
                goto out;
 
-       /* Kludge for now. Don't use mmconfig on AMD systems because
-          those have some busses where mmconfig doesn't work,
-          and we don't parse ACPI MCFG well enough to handle that. 
-          Remove when proper handling is added. */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-               goto out; 
-
        printk(KERN_INFO "PCI: Using MMCONFIG\n");
        raw_pci_ops = &pci_mmcfg;
        pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
index e29a8a55486a5e35fdc8eac3a2bb0acefc5cb062..3fa67ecebc838043c99fab4589e9d334dbd31604 100644 (file)
@@ -2327,7 +2327,7 @@ sys32_sendfile (int out_fd, int in_fd, int __user *offset, unsigned int count)
        ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *) &of : NULL, count);
        set_fs(old_fs);
 
-       if (!ret && offset && put_user(of, offset))
+       if (offset && put_user(of, offset))
                return -EFAULT;
 
        return ret;
diff --git a/arch/m68knommu/platform/68328/head-de2.S b/arch/m68knommu/platform/68328/head-de2.S
new file mode 100644 (file)
index 0000000..94c5a16
--- /dev/null
@@ -0,0 +1,135 @@
+#include <linux/config.h>
+
+#if defined(CONFIG_RAM32MB)
+#define        MEM_END 0x02000000      /* Memory size 32Mb */
+#elif defined(CONFIG_RAM16MB)
+#define        MEM_END 0x01000000      /* Memory size 16Mb */
+#else
+#define        MEM_END 0x00800000      /* Memory size 8Mb */
+#endif
+
+#undef CRT_DEBUG
+
+.macro PUTC CHAR
+#ifdef CRT_DEBUG
+       moveq   #\CHAR, %d7
+       jsr     putc
+#endif
+.endm
+
+       .global _start
+       .global _rambase
+       .global _ramvec
+       .global _ramstart
+       .global _ramend
+       
+       .data
+
+/*
+ *     Set up the usable of RAM stuff
+ */
+_rambase:
+       .long   0
+_ramvec:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+
+       .text
+
+_start:
+
+/*
+ * Setup initial stack
+ */
+       /* disable all interrupts */
+       movew   #0x2700, %sr
+       movel   #-1, 0xfffff304
+       movel   #MEM_END-4, %sp
+
+       PUTC    '\r'
+       PUTC    '\n'
+       PUTC    'A'
+       PUTC    'B'
+
+/*
+ *     Determine end of RAM
+ */
+
+       movel   #MEM_END, %a0
+       movel   %a0, _ramend
+
+       PUTC    'C'
+
+/*
+ *     Move ROM filesystem above bss :-)
+ */
+
+       moveal  #_sbss, %a0                     /* romfs at the start of bss */
+       moveal  #_ebss, %a1                     /* Set up destination  */
+       movel   %a0, %a2                        /* Copy of bss start */
+
+       movel   8(%a0), %d1                     /* Get size of ROMFS */
+       addql   #8, %d1                         /* Allow for rounding */
+       andl    #0xfffffffc, %d1        /* Whole words */
+
+       addl    %d1, %a0                        /* Copy from end */
+       addl    %d1, %a1                        /* Copy from end */
+       movel   %a1, _ramstart          /* Set start of ram */
+
+1:
+       movel   -(%a0), %d0                     /* Copy dword */
+       movel   %d0, -(%a1)
+       cmpl    %a0, %a2                        /* Check if at end */
+       bne     1b
+
+       PUTC    'D'
+
+/*
+ * Initialize BSS segment to 0
+ */
+
+       lea     _sbss, %a0
+       lea     _ebss, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+2:     cmpal   %a0, %a1
+       beq     1f
+       clrl    (%a0)+
+       bra     2b
+1:
+
+       PUTC    'E'
+
+/*
+ * Load the current task pointer and stack
+ */
+
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+       PUTC    'F'
+       PUTC    '\r'
+       PUTC    '\n'
+
+/*
+ * Go
+ */
+
+       jmp     start_kernel
+
+/*
+ * Local functions
+ */
+#ifdef CRT_DEBUG
+putc:
+       moveb   %d7, 0xfffff907
+1:
+       movew   0xfffff906, %d7
+       andw    #0x2000, %d7
+       beq     1b
+       rts
+#endif
diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S
new file mode 100644 (file)
index 0000000..a5c639a
--- /dev/null
@@ -0,0 +1,408 @@
+/* arch/m68knommu/platform/68360/head-ram.S
+ *
+ * Startup code for Motorola 68360
+ *
+ * Copyright 2001 (C) SED Systems, a Division of Calian Ltd.
+ * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
+ * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
+ *           uClinux Kernel
+ * Copyright (C) Michael Leslie <mleslie@lineo.com>
+ * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
+ *
+ */
+#define ASSEMBLY
+#include <linux/config.h>
+
+.global _stext
+.global _start
+
+.global _rambase
+.global __ramvec
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+.global _quicc_base
+.global _periph_base
+
+#define REGB                        0x1000
+#define PEPAR                       (_dprbase + REGB + 0x0016)
+#define GMR                         (_dprbase + REGB + 0x0040)
+#define OR0                         (_dprbase + REGB + 0x0054)
+#define BR0                         (_dprbase + REGB + 0x0050)
+#define OR1                         (_dprbase + REGB + 0x0064)
+#define BR1                         (_dprbase + REGB + 0x0060)
+#define OR4                         (_dprbase + REGB + 0x0094)
+#define BR4                         (_dprbase + REGB + 0x0090)
+#define OR6                         (_dprbase + REGB + 0x00b4)
+#define BR6                         (_dprbase + REGB + 0x00b0)
+#define OR7                         (_dprbase + REGB + 0x00c4)
+#define BR7                         (_dprbase + REGB + 0x00c0)
+
+#define MCR                         (_dprbase + REGB + 0x0000)
+#define AVR                         (_dprbase + REGB + 0x0008)
+
+#define SYPCR                       (_dprbase + REGB + 0x0022)
+
+#define PLLCR                       (_dprbase + REGB + 0x0010)
+#define CLKOCR                      (_dprbase + REGB + 0x000C)
+#define CDVCR                       (_dprbase + REGB + 0x0014)
+
+#define BKAR                        (_dprbase + REGB + 0x0030)
+#define BKCR                        (_dprbase + REGB + 0x0034)
+#define SWIV                        (_dprbase + REGB + 0x0023)
+#define PICR                        (_dprbase + REGB + 0x0026)
+#define PITR                        (_dprbase + REGB + 0x002A)
+
+/* Define for all memory configuration */
+#define MCU_SIM_GMR                 0x00000000
+#define SIM_OR_MASK                 0x0fffffff
+
+/* Defines for chip select zero - the flash */
+#define SIM_OR0_MASK                0x20000002
+#define SIM_BR0_MASK                0x00000001
+
+
+/* Defines for chip select one - the RAM */
+#define SIM_OR1_MASK                0x10000000
+#define SIM_BR1_MASK                0x00000001
+
+#define MCU_SIM_MBAR_ADRS           0x0003ff00
+#define MCU_SIM_MBAR_BA_MASK        0xfffff000
+#define MCU_SIM_MBAR_AS_MASK        0x00000001
+
+#define MCU_SIM_PEPAR               0x00B4
+    
+#define MCU_DISABLE_INTRPTS         0x2700
+#define MCU_SIM_AVR                 0x00
+    
+#define MCU_SIM_MCR                 0x00005cff
+
+#define MCU_SIM_CLKOCR              0x00
+#define MCU_SIM_PLLCR               0x8000
+#define MCU_SIM_CDVCR               0x0000
+
+#define MCU_SIM_SYPCR               0x0000
+#define MCU_SIM_SWIV                0x00
+#define MCU_SIM_PICR                0x0000
+#define MCU_SIM_PITR                0x0000
+
+
+#include <asm/m68360_regs.h>
+
+       
+/*
+ * By the time this RAM specific code begins to execute, DPRAM
+ * and DRAM should already be mapped and accessible.
+ */
+
+       .text
+_start:
+_stext:
+       nop
+       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
+       /* We should not need to setup the boot stack the reset should do it. */
+       movea.l #__ramend, %sp                  /*set up stack at the end of DRAM:*/
+
+set_mbar_register:
+       moveq.l #0x07, %d1                      /* Setup MBAR */
+       movec   %d1, %dfc
+
+       lea.l   MCU_SIM_MBAR_ADRS, %a0
+       move.l  #_dprbase, %d0
+       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
+       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
+       moves.l %d0, %a0@
+
+       moveq.l #0x05, %d1
+       movec.l %d1, %dfc
+
+       /* Now we can begin to access registers in DPRAM */
+
+set_sim_mcr:
+       /* Set Module Configuration Register */
+       move.l  #MCU_SIM_MCR, MCR
+
+       /* to do:       Determine cause of reset */
+
+       /*
+        *       configure system clock MC68360 p. 6-40
+        *       (value +1)*osc/128 = system clock
+        */
+set_sim_clock:
+       move.w  #MCU_SIM_PLLCR, PLLCR
+       move.b  #MCU_SIM_CLKOCR, CLKOCR
+       move.w  #MCU_SIM_CDVCR, CDVCR
+
+       /* Wait for the PLL to settle */
+       move.w  #16384, %d0
+pll_settle_wait:
+       subi.w  #1, %d0
+       bne     pll_settle_wait
+
+       /* Setup the system protection register, and watchdog timer register */
+       move.b  #MCU_SIM_SWIV, SWIV
+       move.w  #MCU_SIM_PICR, PICR
+       move.w  #MCU_SIM_PITR, PITR
+       move.w  #MCU_SIM_SYPCR, SYPCR
+
+       /* Clear DPRAM - system + parameter */
+       movea.l #_dprbase, %a0
+       movea.l #_dprbase+0x2000, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+clear_dpram:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     clear_dpram
+
+configure_memory_controller:    
+       /* Set up Global Memory Register (GMR) */
+       move.l  #MCU_SIM_GMR, %d0
+       move.l  %d0, GMR
+
+configure_chip_select_0:
+       move.l  #__ramend, %d0
+       subi.l  #__ramstart, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR0_MASK, %d0
+       move.l  %d0, OR0
+
+       move.l  #__ramstart, %d0
+       ori.l   #SIM_BR0_MASK, %d0
+       move.l  %d0, BR0
+
+configure_chip_select_1:
+       move.l  #__rom_end, %d0
+       subi.l  #__rom_start, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR1_MASK, %d0
+       move.l  %d0, OR1
+
+       move.l  #__rom_start, %d0
+       ori.l   #SIM_BR1_MASK, %d0
+       move.l  %d0, BR1
+
+       move.w  #MCU_SIM_PEPAR, PEPAR 
+
+       /* point to vector table: */
+       move.l  #_romvec, %a0
+       move.l  #_ramvec, %a1
+copy_vectors:
+       move.l  %a0@, %d0
+       move.l  %d0, %a1@
+       move.l  %a0@, %a1@
+       addq.l  #0x04, %a0
+       addq.l  #0x04, %a1
+       cmp.l   #_start, %a0
+       blt     copy_vectors
+
+       move.l  #_ramvec, %a1
+       movec   %a1, %vbr
+
+
+       /* Copy data segment from ROM to RAM */
+       moveal  #_stext, %a0
+       moveal  #_sdata, %a1
+       moveal  #_edata, %a2
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+       move.l  %a0@, %d0
+       addq.l  #0x04, %a0
+       move.l  %d0, %a1@
+       addq.l  #0x04, %a1
+       cmp.l   #_edata, %a1
+       blt     LD1
+
+       moveal  #_sbss, %a0
+       moveal  #_ebss, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+L1:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     L1
+
+load_quicc:
+       move.l  #_dprbase, _quicc_base
+
+store_ram_size:
+       /* Set ram size information */
+       move.l  #_sdata, _rambase
+       move.l  #_ebss, _ramstart
+       move.l  #__ramend, %d0
+       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
+       move.l  %d0, _ramend                    /* Different from __ramend.*/
+
+store_flash_size:
+       /* Set rom size information */
+       move.l  #__rom_end, %d0
+       sub.l   #__rom_start, %d0
+       move.l  %d0, rom_length
+    
+       pea     0
+       pea     env
+       pea     %sp@(4)
+       pea     0
+
+       lea     init_thread_union, %a2
+       lea     0x2000(%a2), %sp
+
+lp:
+       jsr     start_kernel
+
+_exit:
+       jmp     _exit
+
+
+       .data
+       .align 4
+env:
+       .long   0
+_quicc_base:
+       .long   0
+_periph_base:
+       .long   0
+_ramvec:
+       .long   0
+_rambase:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+_dprbase:
+       .long   0xffffe000
+
+       .text
+
+    /*
+     * These are the exception vectors at boot up, they are copied into RAM
+     * and then overwritten as needed.
+     */
+.section ".data.initvect","awx"
+    .long   __ramend   /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   _start      /* Reset: Initial Program Counter               - 1.  */
+    .long   buserr      /* Bus Error                                    - 2.  */
+    .long   trap        /* Address Error                                - 3.  */
+    .long   trap        /* Illegal Instruction                          - 4.  */
+    .long   trap        /* Divide by zero                               - 5.  */
+    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
+    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
+    .long   trap        /* Privilege Violation                          - 8.  */
+    .long   trap        /* Trace                                        - 9.  */
+    .long   trap        /* Line 1010 Emulator                           - 10. */
+    .long   trap        /* Line 1111 Emualtor                           - 11. */
+    .long   trap        /* Harware Breakpoint                           - 12. */
+    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
+    .long   trap        /* Format Error                                 - 14. */
+    .long   trap        /* Uninitialized Interrupt                      - 15. */
+    .long   trap        /* (Unassigned, Reserver)                       - 16. */
+    .long   trap        /* (Unassigned, Reserver)                       - 17. */
+    .long   trap        /* (Unassigned, Reserver)                       - 18. */
+    .long   trap        /* (Unassigned, Reserver)                       - 19. */
+    .long   trap        /* (Unassigned, Reserver)                       - 20. */
+    .long   trap        /* (Unassigned, Reserver)                       - 21. */
+    .long   trap        /* (Unassigned, Reserver)                       - 22. */
+    .long   trap        /* (Unassigned, Reserver)                       - 23. */
+    .long   trap        /* Spurious Interrupt                           - 24. */
+    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
+    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
+    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
+    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
+    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
+    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
+    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
+    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
+    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
+    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
+    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
+    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
+    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
+    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
+    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
+    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
+    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
+    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
+    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
+    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
+    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
+    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
+    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
+    .long   0           /* (Reserved for Coprocessor)                   - 48. */
+    .long   0           /* (Reserved for Coprocessor)                   - 49. */
+    .long   0           /* (Reserved for Coprocessor)                   - 50. */
+    .long   0           /* (Reserved for Coprocessor)                   - 51. */
+    .long   0           /* (Reserved for Coprocessor)                   - 52. */
+    .long   0           /* (Reserved for Coprocessor)                   - 53. */
+    .long   0           /* (Reserved for Coprocessor)                   - 54. */
+    .long   0           /* (Reserved for Coprocessor)                   - 55. */
+    .long   0           /* (Reserved for Coprocessor)                   - 56. */
+    .long   0           /* (Reserved for Coprocessor)                   - 57. */
+    .long   0           /* (Reserved for Coprocessor)                   - 58. */
+    .long   0           /* (Unassigned, Reserved)                       - 59. */
+    .long   0           /* (Unassigned, Reserved)                       - 60. */
+    .long   0           /* (Unassigned, Reserved)                       - 61. */
+    .long   0           /* (Unassigned, Reserved)                       - 62. */
+    .long   0           /* (Unassigned, Reserved)                       - 63. */
+    /*                  The assignment of these vectors to the CPM is         */
+    /*                  dependent on the configuration of the CPM vba         */
+    /*                          fields.                                       */
+    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
+    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
+    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
+    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
+    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
+    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
+    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
+    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
+    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
+    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
+    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
+    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
+    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
+    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
+    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
+    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
+    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
+    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
+    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
+    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
+    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
+    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
+    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
+    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
+    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
+    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
+    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
+    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
+    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
+    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
+    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
+    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
+    /*                  I don't think anything uses the vectors after here.   */
+    .long   0           /* (User-Defined Vectors 34)                    - 96. */
+    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
+    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
+.text
+ignore: rte
diff --git a/arch/m68knommu/platform/68360/head-rom.S b/arch/m68knommu/platform/68360/head-rom.S
new file mode 100644 (file)
index 0000000..0da357a
--- /dev/null
@@ -0,0 +1,420 @@
+/* arch/m68knommu/platform/68360/head-rom.S
+ *
+ * Startup code for Motorola 68360
+ *
+ * Copyright (C) SED Systems, a Division of Calian Ltd.
+ * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
+ * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
+ *           uClinux Kernel
+ * Copyright (C) Michael Leslie <mleslie@lineo.com>
+ * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
+ *
+ */
+#include <linux/config.h>
+
+.global _stext
+.global _sbss
+.global _start
+
+.global _rambase
+.global __ramvec
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+.global _quicc_base
+.global _periph_base
+
+#define REGB                        0x1000
+#define PEPAR                       (_dprbase + REGB + 0x0016)
+#define GMR                         (_dprbase + REGB + 0x0040)
+#define OR0                         (_dprbase + REGB + 0x0054)
+#define BR0                         (_dprbase + REGB + 0x0050)
+
+#define OR1                         (_dprbase + REGB + 0x0064)
+#define BR1                         (_dprbase + REGB + 0x0060)
+
+#define OR2                         (_dprbase + REGB + 0x0074)
+#define BR2                         (_dprbase + REGB + 0x0070)
+
+#define OR3                         (_dprbase + REGB + 0x0084)
+#define BR3                         (_dprbase + REGB + 0x0080)
+
+#define OR4                         (_dprbase + REGB + 0x0094)
+#define BR4                         (_dprbase + REGB + 0x0090)
+
+#define OR5                         (_dprbase + REGB + 0x00A4)
+#define BR5                         (_dprbase + REGB + 0x00A0)
+
+#define OR6                         (_dprbase + REGB + 0x00b4)
+#define BR6                         (_dprbase + REGB + 0x00b0)
+
+#define OR7                         (_dprbase + REGB + 0x00c4)
+#define BR7                         (_dprbase + REGB + 0x00c0)
+
+#define MCR                         (_dprbase + REGB + 0x0000)
+#define AVR                         (_dprbase + REGB + 0x0008)
+
+#define SYPCR                       (_dprbase + REGB + 0x0022)
+
+#define PLLCR                       (_dprbase + REGB + 0x0010)
+#define CLKOCR                      (_dprbase + REGB + 0x000C)
+#define CDVCR                       (_dprbase + REGB + 0x0014)
+
+#define BKAR                        (_dprbase + REGB + 0x0030)
+#define BKCR                        (_dprbase + REGB + 0x0034)
+#define SWIV                        (_dprbase + REGB + 0x0023)
+#define PICR                        (_dprbase + REGB + 0x0026)
+#define PITR                        (_dprbase + REGB + 0x002A)
+
+/* Define for all memory configuration */
+#define MCU_SIM_GMR                 0x00000000
+#define SIM_OR_MASK                 0x0fffffff
+
+/* Defines for chip select zero - the flash */
+#define SIM_OR0_MASK                0x20000000
+#define SIM_BR0_MASK                0x00000001
+
+/* Defines for chip select one - the RAM */
+#define SIM_OR1_MASK                0x10000000
+#define SIM_BR1_MASK                0x00000001
+
+#define MCU_SIM_MBAR_ADRS           0x0003ff00
+#define MCU_SIM_MBAR_BA_MASK        0xfffff000
+#define MCU_SIM_MBAR_AS_MASK        0x00000001
+
+#define MCU_SIM_PEPAR               0x00B4
+    
+#define MCU_DISABLE_INTRPTS         0x2700
+#define MCU_SIM_AVR                 0x00
+    
+#define MCU_SIM_MCR                 0x00005cff
+
+#define MCU_SIM_CLKOCR              0x00
+#define MCU_SIM_PLLCR               0x8000
+#define MCU_SIM_CDVCR               0x0000
+
+#define MCU_SIM_SYPCR               0x0000
+#define MCU_SIM_SWIV                0x00
+#define MCU_SIM_PICR                0x0000
+#define MCU_SIM_PITR                0x0000
+
+
+#include <asm/m68360_regs.h>
+
+       
+/*
+ * By the time this RAM specific code begins to execute, DPRAM
+ * and DRAM should already be mapped and accessible.
+ */
+
+       .text
+_start:
+_stext:
+       nop
+       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
+       /* We should not need to setup the boot stack the reset should do it. */
+       movea.l #__ramend, %sp          /* set up stack at the end of DRAM:*/
+
+
+set_mbar_register:
+       moveq.l #0x07, %d1                      /* Setup MBAR */
+       movec   %d1, %dfc
+
+       lea.l   MCU_SIM_MBAR_ADRS, %a0
+       move.l  #_dprbase, %d0
+       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
+       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
+       moves.l %d0, %a0@
+
+       moveq.l #0x05, %d1
+       movec.l %d1, %dfc
+
+       /* Now we can begin to access registers in DPRAM */
+
+set_sim_mcr:
+       /* Set Module Configuration Register */
+       move.l  #MCU_SIM_MCR, MCR
+
+       /* to do:       Determine cause of reset */
+
+       /*
+        *      configure system clock MC68360 p. 6-40
+        *      (value +1)*osc/128 = system clock
+        *                    or
+        *      (value + 1)*osc = system clock
+        *      You do not need to divide the oscillator by 128 unless you want to.
+        */
+set_sim_clock:
+       move.w  #MCU_SIM_PLLCR, PLLCR
+       move.b  #MCU_SIM_CLKOCR, CLKOCR
+       move.w  #MCU_SIM_CDVCR, CDVCR
+
+       /* Wait for the PLL to settle */
+       move.w  #16384, %d0
+pll_settle_wait:
+       subi.w  #1, %d0
+       bne     pll_settle_wait
+
+       /* Setup the system protection register, and watchdog timer register */
+       move.b  #MCU_SIM_SWIV, SWIV
+       move.w  #MCU_SIM_PICR, PICR
+       move.w  #MCU_SIM_PITR, PITR
+       move.w  #MCU_SIM_SYPCR, SYPCR
+
+       /* Clear DPRAM - system + parameter */
+       movea.l #_dprbase, %a0
+       movea.l #_dprbase+0x2000, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+clear_dpram:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     clear_dpram
+
+configure_memory_controller:    
+       /* Set up Global Memory Register (GMR) */
+       move.l  #MCU_SIM_GMR, %d0
+       move.l  %d0, GMR
+
+configure_chip_select_0:
+       move.l  #0x00400000, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR0_MASK, %d0
+       move.l  %d0, OR0
+
+       move.l  #__rom_start, %d0
+       ori.l   #SIM_BR0_MASK, %d0
+       move.l  %d0, BR0
+
+       move.l  #0x0, BR1
+       move.l  #0x0, BR2
+       move.l  #0x0, BR3
+       move.l  #0x0, BR4
+       move.l  #0x0, BR5
+       move.l  #0x0, BR6
+       move.l  #0x0, BR7
+
+       move.w  #MCU_SIM_PEPAR, PEPAR 
+
+       /* point to vector table: */
+       move.l  #_romvec, %a0
+       move.l  #_ramvec, %a1
+copy_vectors:
+       move.l  %a0@, %d0
+       move.l  %d0, %a1@
+       move.l  %a0@, %a1@
+       addq.l  #0x04, %a0
+       addq.l  #0x04, %a1
+       cmp.l   #_start, %a0
+       blt     copy_vectors
+
+       move.l  #_ramvec, %a1
+       movec   %a1, %vbr
+
+
+       /* Copy data segment from ROM to RAM */
+       moveal  #_etext, %a0
+       moveal  #_sdata, %a1
+       moveal  #_edata, %a2
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+       move.l  %a0@, %d0
+       addq.l  #0x04, %a0
+       move.l  %d0, %a1@
+       addq.l  #0x04, %a1
+       cmp.l   #_edata, %a1
+       blt     LD1
+
+       moveal  #_sbss, %a0
+       moveal  #_ebss, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+L1:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     L1
+
+load_quicc:
+       move.l  #_dprbase, _quicc_base
+
+store_ram_size:
+       /* Set ram size information */
+       move.l  #_sdata, _rambase
+       move.l  #_ebss, _ramstart
+       move.l  #__ramend, %d0
+       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
+       move.l  %d0, _ramend                    /* Different from __ramend.*/
+
+store_flash_size:
+       /* Set rom size information */
+       move.l  #__rom_end, %d0
+       sub.l   #__rom_start, %d0
+       move.l  %d0, rom_length
+    
+       pea     0
+       pea     env
+       pea     %sp@(4)
+       pea     0
+
+       lea     init_thread_union, %a2
+       lea     0x2000(%a2), %sp
+
+lp:
+       jsr     start_kernel
+
+_exit:
+       jmp     _exit
+
+
+       .data
+       .align 4
+env:
+       .long   0
+_quicc_base:
+       .long   0
+_periph_base:
+       .long   0
+_ramvec:
+       .long   0
+_rambase:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+_dprbase:
+       .long   0xffffe000
+
+
+       .text
+
+    /*
+     * These are the exception vectors at boot up, they are copied into RAM
+     * and then overwritten as needed.
+     */
+.section ".data.initvect","awx"
+    .long   __ramend   /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   _start      /* Reset: Initial Program Counter               - 1.  */
+    .long   buserr      /* Bus Error                                    - 2.  */
+    .long   trap        /* Address Error                                - 3.  */
+    .long   trap        /* Illegal Instruction                          - 4.  */
+    .long   trap        /* Divide by zero                               - 5.  */
+    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
+    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
+    .long   trap        /* Privilege Violation                          - 8.  */
+    .long   trap        /* Trace                                        - 9.  */
+    .long   trap        /* Line 1010 Emulator                           - 10. */
+    .long   trap        /* Line 1111 Emualtor                           - 11. */
+    .long   trap        /* Harware Breakpoint                           - 12. */
+    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
+    .long   trap        /* Format Error                                 - 14. */
+    .long   trap        /* Uninitialized Interrupt                      - 15. */
+    .long   trap        /* (Unassigned, Reserver)                       - 16. */
+    .long   trap        /* (Unassigned, Reserver)                       - 17. */
+    .long   trap        /* (Unassigned, Reserver)                       - 18. */
+    .long   trap        /* (Unassigned, Reserver)                       - 19. */
+    .long   trap        /* (Unassigned, Reserver)                       - 20. */
+    .long   trap        /* (Unassigned, Reserver)                       - 21. */
+    .long   trap        /* (Unassigned, Reserver)                       - 22. */
+    .long   trap        /* (Unassigned, Reserver)                       - 23. */
+    .long   trap        /* Spurious Interrupt                           - 24. */
+    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
+    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
+    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
+    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
+    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
+    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
+    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
+    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
+    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
+    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
+    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
+    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
+    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
+    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
+    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
+    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
+    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
+    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
+    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
+    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
+    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
+    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
+    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
+    .long   0           /* (Reserved for Coprocessor)                   - 48. */
+    .long   0           /* (Reserved for Coprocessor)                   - 49. */
+    .long   0           /* (Reserved for Coprocessor)                   - 50. */
+    .long   0           /* (Reserved for Coprocessor)                   - 51. */
+    .long   0           /* (Reserved for Coprocessor)                   - 52. */
+    .long   0           /* (Reserved for Coprocessor)                   - 53. */
+    .long   0           /* (Reserved for Coprocessor)                   - 54. */
+    .long   0           /* (Reserved for Coprocessor)                   - 55. */
+    .long   0           /* (Reserved for Coprocessor)                   - 56. */
+    .long   0           /* (Reserved for Coprocessor)                   - 57. */
+    .long   0           /* (Reserved for Coprocessor)                   - 58. */
+    .long   0           /* (Unassigned, Reserved)                       - 59. */
+    .long   0           /* (Unassigned, Reserved)                       - 60. */
+    .long   0           /* (Unassigned, Reserved)                       - 61. */
+    .long   0           /* (Unassigned, Reserved)                       - 62. */
+    .long   0           /* (Unassigned, Reserved)                       - 63. */
+    /*                  The assignment of these vectors to the CPM is         */
+    /*                  dependent on the configuration of the CPM vba         */
+    /*                          fields.                                       */
+    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
+    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
+    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
+    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
+    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
+    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
+    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
+    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
+    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
+    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
+    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
+    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
+    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
+    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
+    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
+    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
+    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
+    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
+    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
+    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
+    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
+    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
+    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
+    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
+    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
+    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
+    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
+    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
+    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
+    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
+    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
+    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
+    /*                  I don't think anything uses the vectors after here.   */
+    .long   0           /* (User-Defined Vectors 34)                    - 96. */
+    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
+    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
+.text
+ignore: rte
index fe8bb634ead0a1e404edfff77c50260c887442a7..26bd8ea35a4e915e10264202cc12a6937f8c4cbf 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/reg.h>
 #include <asm/nvram.h>
index a3c5281a5d2d8c05e328a6fc5c83f10b9981193c..22d7fd1e0aea7e4e86851db796699ffa3c8f9bee 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/init.h>
 #include <linux/profile.h>
 
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/nvram.h>
 #include <asm/cache.h>
index 9353584fb7103c77cc866b417eecb12fa729c968..17d2db7e537df7eef854d6500bfc7b13ee84ed45 100644 (file)
@@ -96,6 +96,9 @@ SECTIONS
        *(.init.text)
        _einittext = .;
   }
+  /* .exit.text is discarded at runtime, not link time,
+     to deal with references from __bug_table */
+  .exit.text : { *(.exit.text) }
   .init.data : {
     *(.init.data);
     __vtop_table_begin = .;
@@ -190,5 +193,6 @@ SECTIONS
   /* Sections to be discarded. */
   /DISCARD/ : {
     *(.exitcall.exit)
+    *(.exit.data)
   }
 }
index 4864a7de3daa9ac1373f9a2cf1fe4c288dcbac4d..6037ce7796f5e2e1864749b40636b6e759746b75 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/init.h>
 #include <linux/bcd.h>
 
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/nvram.h>
 #include <asm/prom.h>
index 2bcf8a16d1c936180acae6965438678ef417a17d..8599850ca772f5d8a7cfef073a98875c5afae220 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/ioport.h>
 
 #include <asm/sections.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/prep_nvram.h>
index 356e4fd9a94fecc763e90a13bb79860ba2880f7b..fbc273c32bcc176556a5949b0fc2c7b78a331bfb 100644 (file)
@@ -252,7 +252,7 @@ unsigned long __init find_and_init_phbs(void)
                        phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), GFP_KERNEL);
                        if (phb == NULL)
                                return -ENOMEM;
-                               pci_setup_pci_controller(phb);
+                       pci_setup_pci_controller(phb);
 
                        phb->pci_mem_offset = phb->local_number = bus;
                        phb->first_busno = bus;
index 5a8b4d8c2dd62042e8b67a237fa51d89b8797884..1d297e0edfc0d272e9676562a08866ee6acbf31d 100644 (file)
@@ -283,7 +283,7 @@ static void __init setup_u3_agp(struct pci_controller* hose)
         * the reg address cell, we shall fix that by killing struct
         * reg_property and using some accessor functions instead
         */
-               hose->first_busno = 0xf0;
+       hose->first_busno = 0xf0;
        hose->last_busno = 0xff;
        hose->ops = &u3_agp_pci_ops;
        hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
@@ -315,24 +315,24 @@ static int __init add_bridge(struct device_node *dev)
        char* disp_name;
        int *bus_range;
        int primary = 1;
-       struct property *of_prop;
+       struct property *of_prop;
 
        DBG("Adding PCI host bridge %s\n", dev->full_name);
 
-               bus_range = (int *) get_property(dev, "bus-range", &len);
-               if (bus_range == NULL || len < 2 * sizeof(int)) {
-                       printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
-                                      dev->full_name);
-               }
+       bus_range = (int *) get_property(dev, "bus-range", &len);
+       if (bus_range == NULL || len < 2 * sizeof(int)) {
+               printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
+               dev->full_name);
+       }
 
        hose = alloc_bootmem(sizeof(struct pci_controller));
        if (hose == NULL)
                return -ENOMEM;
-               pci_setup_pci_controller(hose);
+       pci_setup_pci_controller(hose);
 
-               hose->arch_data = dev;
-               hose->first_busno = bus_range ? bus_range[0] : 0;
-               hose->last_busno = bus_range ? bus_range[1] : 0xff;
+       hose->arch_data = dev;
+       hose->first_busno = bus_range ? bus_range[0] : 0;
+       hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
        of_prop = alloc_bootmem(sizeof(struct property) +
                                sizeof(hose->global_number));
@@ -346,25 +346,25 @@ static int __init add_bridge(struct device_node *dev)
        }
 
        disp_name = NULL;
-               if (device_is_compatible(dev, "u3-agp")) {
-                       setup_u3_agp(hose);
-                       disp_name = "U3-AGP";
-                       primary = 0;
-               } else if (device_is_compatible(dev, "u3-ht")) {
-                       setup_u3_ht(hose);
-                       disp_name = "U3-HT";
-                       primary = 1;
-               }
-               printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
-                       disp_name, hose->first_busno, hose->last_busno);
-
-               /* Interpret the "ranges" property */
-               /* This also maps the I/O region and sets isa_io/mem_base */
-               pci_process_bridge_OF_ranges(hose, dev);
+       if (device_is_compatible(dev, "u3-agp")) {
+               setup_u3_agp(hose);
+               disp_name = "U3-AGP";
+               primary = 0;
+       } else if (device_is_compatible(dev, "u3-ht")) {
+               setup_u3_ht(hose);
+               disp_name = "U3-HT";
+               primary = 1;
+       }
+       printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
+               disp_name, hose->first_busno, hose->last_busno);
+
+       /* Interpret the "ranges" property */
+       /* This also maps the I/O region and sets isa_io/mem_base */
+       pci_process_bridge_OF_ranges(hose, dev);
        pci_setup_phb_io(hose, primary);
 
-               /* Fixup "bus-range" OF property */
-               fixup_bus_range(dev);
+       /* Fixup "bus-range" OF property */
+       fixup_bus_range(dev);
 
        return 0;
 }
index 9490b6c5b1736ae7fa5b42b7cbdf9a02020bd791..3009701eb90d89b7dfe708ee499e97a6f61ab85d 100644 (file)
@@ -238,8 +238,8 @@ static void __init pSeries_setup_arch(void)
 
        /* Find and initialize PCI host bridges */
        init_pci_config_tokens();
-       eeh_init();
        find_and_init_phbs();
+       eeh_init();
 
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
@@ -590,6 +590,13 @@ static int pseries_shared_idle(void)
        return 0;
 }
 
+static int pSeries_pci_probe_mode(struct pci_bus *bus)
+{
+       if (systemcfg->platform & PLATFORM_LPAR)
+               return PCI_PROBE_DEVTREE;
+       return PCI_PROBE_NORMAL;
+}
+
 struct machdep_calls __initdata pSeries_md = {
        .probe                  = pSeries_probe,
        .setup_arch             = pSeries_setup_arch,
@@ -597,6 +604,7 @@ struct machdep_calls __initdata pSeries_md = {
        .get_cpuinfo            = pSeries_get_cpuinfo,
        .log_error              = pSeries_log_error,
        .pcibios_fixup          = pSeries_final_fixup,
+       .pci_probe_mode         = pSeries_pci_probe_mode,
        .irq_bus_setup          = pSeries_irq_bus_setup,
        .restart                = rtas_restart,
        .power_off              = rtas_power_off,
index 79c7f32236658805bab9f783d80cb3d42091893a..d2c7e2c4733b72130cbd90020b0ae61cc7ed4897 100644 (file)
@@ -272,6 +272,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
        unsigned long start_here = __pa((u32)*((unsigned long *)
                                               pSeries_secondary_smp_init));
        unsigned int pcpu;
+       int start_cpu;
 
        if (cpu_isset(lcpu, of_spin_map))
                /* Already started by OF and sitting in spin loop */
@@ -282,12 +283,20 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
        /* Fixup atomic count: it exited inside IRQ handler. */
        paca[lcpu].__current->thread_info->preempt_count        = 0;
 
-       status = rtas_call(rtas_token("start-cpu"), 3, 1, NULL,
-                          pcpu, start_here, lcpu);
+       /* 
+        * If the RTAS start-cpu token does not exist then presume the
+        * cpu is already spinning.
+        */
+       start_cpu = rtas_token("start-cpu");
+       if (start_cpu == RTAS_UNKNOWN_SERVICE)
+               return 1;
+
+       status = rtas_call(start_cpu, 3, 1, NULL, pcpu, start_here, lcpu);
        if (status != 0) {
                printk(KERN_ERR "start-cpu failed: %i\n", status);
                return 0;
        }
+
        return 1;
 }
 
index 8447dcc2c2b3f7db34086a997030c7d92742dd0a..861138ad092c597efcaee48d9d6496e9f41a7057 100644 (file)
@@ -51,6 +51,10 @@ unsigned long io_page_mask;
 
 EXPORT_SYMBOL(io_page_mask);
 
+#ifdef CONFIG_PPC_MULTIPLATFORM
+static void fixup_resource(struct resource *res, struct pci_dev *dev);
+static void do_bus_setup(struct pci_bus *bus);
+#endif
 
 unsigned int pcibios_assign_all_busses(void)
 {
@@ -225,10 +229,287 @@ static void __init pcibios_claim_of_setup(void)
 }
 #endif
 
+#ifdef CONFIG_PPC_MULTIPLATFORM
+static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
+{
+       u32 *prop;
+       int len;
+
+       prop = (u32 *) get_property(np, name, &len);
+       if (prop && len >= 4)
+               return *prop;
+       return def;
+}
+
+static unsigned int pci_parse_of_flags(u32 addr0)
+{
+       unsigned int flags = 0;
+
+       if (addr0 & 0x02000000) {
+               flags |= IORESOURCE_MEM;
+               if (addr0 & 0x40000000)
+                       flags |= IORESOURCE_PREFETCH;
+       } else if (addr0 & 0x01000000)
+               flags |= IORESOURCE_IO;
+       return flags;
+}
+
+#define GET_64BIT(prop, i)     ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1])
+
+static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
+{
+       u64 base, size;
+       unsigned int flags;
+       struct resource *res;
+       u32 *addrs, i;
+       int proplen;
+
+       addrs = (u32 *) get_property(node, "assigned-addresses", &proplen);
+       if (!addrs)
+               return;
+       for (; proplen >= 20; proplen -= 20, addrs += 5) {
+               flags = pci_parse_of_flags(addrs[0]);
+               if (!flags)
+                       continue;
+               base = GET_64BIT(addrs, 1);
+               size = GET_64BIT(addrs, 3);
+               if (!size)
+                       continue;
+               i = addrs[0] & 0xff;
+               if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
+                       res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
+               } else if (i == dev->rom_base_reg) {
+                       res = &dev->resource[PCI_ROM_RESOURCE];
+                       flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+               } else {
+                       printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
+                       continue;
+               }
+               res->start = base;
+               res->end = base + size - 1;
+               res->flags = flags;
+               res->name = pci_name(dev);
+               fixup_resource(res, dev);
+       }
+}
+
+static struct pci_dev *of_create_pci_dev(struct device_node *node,
+                                        struct pci_bus *bus, int devfn)
+{
+       struct pci_dev *dev;
+       const char *type;
+
+       dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+       type = get_property(node, "device_type", NULL);
+       if (type == NULL)
+               type = "";
+
+       memset(dev, 0, sizeof(struct pci_dev));
+       dev->bus = bus;
+       dev->sysdata = node;
+       dev->dev.parent = bus->bridge;
+       dev->dev.bus = &pci_bus_type;
+       dev->devfn = devfn;
+       dev->multifunction = 0;         /* maybe a lie? */
+
+       dev->vendor = get_int_prop(node, "vendor-id", 0xffff);
+       dev->device = get_int_prop(node, "device-id", 0xffff);
+       dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
+       dev->subsystem_device = get_int_prop(node, "subsystem-id", 0);
+
+       dev->cfg_size = 256; /*pci_cfg_space_size(dev);*/
+
+       sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+               dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
+       dev->class = get_int_prop(node, "class-code", 0);
+
+       dev->current_state = 4;         /* unknown power state */
+
+       if (!strcmp(type, "pci")) {
+               /* a PCI-PCI bridge */
+               dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
+               dev->rom_base_reg = PCI_ROM_ADDRESS1;
+       } else if (!strcmp(type, "cardbus")) {
+               dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
+       } else {
+               dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
+               dev->rom_base_reg = PCI_ROM_ADDRESS;
+               dev->irq = NO_IRQ;
+               if (node->n_intrs > 0) {
+                       dev->irq = node->intrs[0].line;
+                       pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
+                                             dev->irq);
+               }
+       }
+
+       pci_parse_of_addrs(node, dev);
+
+       pci_device_add(dev, bus);
+
+       /* XXX pci_scan_msi_device(dev); */
+
+       return dev;
+}
+
+static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev);
+
+static void __devinit of_scan_bus(struct device_node *node,
+                                 struct pci_bus *bus)
+{
+       struct device_node *child = NULL;
+       u32 *reg;
+       int reglen, devfn;
+       struct pci_dev *dev;
+
+       while ((child = of_get_next_child(node, child)) != NULL) {
+               reg = (u32 *) get_property(child, "reg", &reglen);
+               if (reg == NULL || reglen < 20)
+                       continue;
+               devfn = (reg[0] >> 8) & 0xff;
+               /* create a new pci_dev for this device */
+               dev = of_create_pci_dev(child, bus, devfn);
+               if (!dev)
+                       continue;
+               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+                   dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+                       of_scan_pci_bridge(child, dev);
+       }
+
+       do_bus_setup(bus);
+}
+
+static void __devinit of_scan_pci_bridge(struct device_node *node,
+                                        struct pci_dev *dev)
+{
+       struct pci_bus *bus;
+       u32 *busrange, *ranges;
+       int len, i, mode;
+       struct resource *res;
+       unsigned int flags;
+       u64 size;
+
+       /* parse bus-range property */
+       busrange = (u32 *) get_property(node, "bus-range", &len);
+       if (busrange == NULL || len != 8) {
+               printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n",
+                      node->full_name);
+               return;
+       }
+       ranges = (u32 *) get_property(node, "ranges", &len);
+       if (ranges == NULL) {
+               printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n",
+                      node->full_name);
+               return;
+       }
+
+       bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
+       if (!bus) {
+               printk(KERN_ERR "Failed to create pci bus for %s\n",
+                      node->full_name);
+               return;
+       }
+
+       bus->primary = dev->bus->number;
+       bus->subordinate = busrange[1];
+       bus->bridge_ctl = 0;
+       bus->sysdata = node;
+
+       /* parse ranges property */
+       /* PCI #address-cells == 3 and #size-cells == 2 always */
+       res = &dev->resource[PCI_BRIDGE_RESOURCES];
+       for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) {
+               res->flags = 0;
+               bus->resource[i] = res;
+               ++res;
+       }
+       i = 1;
+       for (; len >= 32; len -= 32, ranges += 8) {
+               flags = pci_parse_of_flags(ranges[0]);
+               size = GET_64BIT(ranges, 6);
+               if (flags == 0 || size == 0)
+                       continue;
+               if (flags & IORESOURCE_IO) {
+                       res = bus->resource[0];
+                       if (res->flags) {
+                               printk(KERN_ERR "PCI: ignoring extra I/O range"
+                                      " for bridge %s\n", node->full_name);
+                               continue;
+                       }
+               } else {
+                       if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
+                               printk(KERN_ERR "PCI: too many memory ranges"
+                                      " for bridge %s\n", node->full_name);
+                               continue;
+                       }
+                       res = bus->resource[i];
+                       ++i;
+               }
+               res->start = GET_64BIT(ranges, 1);
+               res->end = res->start + size - 1;
+               res->flags = flags;
+               fixup_resource(res, dev);
+       }
+       sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
+               bus->number);
+
+       mode = PCI_PROBE_NORMAL;
+       if (ppc_md.pci_probe_mode)
+               mode = ppc_md.pci_probe_mode(bus);
+       if (mode == PCI_PROBE_DEVTREE)
+               of_scan_bus(node, bus);
+       else if (mode == PCI_PROBE_NORMAL)
+               pci_scan_child_bus(bus);
+}
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+static void __devinit scan_phb(struct pci_controller *hose)
+{
+       struct pci_bus *bus;
+       struct device_node *node = hose->arch_data;
+       int i, mode;
+       struct resource *res;
+
+       bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node);
+       if (bus == NULL) {
+               printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
+                      hose->global_number);
+               return;
+       }
+       bus->secondary = hose->first_busno;
+       hose->bus = bus;
+
+       bus->resource[0] = res = &hose->io_resource;
+       if (res->flags && request_resource(&ioport_resource, res))
+               printk(KERN_ERR "Failed to request PCI IO region "
+                      "on PCI domain %04x\n", hose->global_number);
+
+       for (i = 0; i < 3; ++i) {
+               res = &hose->mem_resources[i];
+               bus->resource[i+1] = res;
+               if (res->flags && request_resource(&iomem_resource, res))
+                       printk(KERN_ERR "Failed to request PCI memory region "
+                              "on PCI domain %04x\n", hose->global_number);
+       }
+
+       mode = PCI_PROBE_NORMAL;
+#ifdef CONFIG_PPC_MULTIPLATFORM
+       if (ppc_md.pci_probe_mode)
+               mode = ppc_md.pci_probe_mode(bus);
+       if (mode == PCI_PROBE_DEVTREE) {
+               bus->subordinate = hose->last_busno;
+               of_scan_bus(node, bus);
+       }
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+       if (mode == PCI_PROBE_NORMAL)
+               hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+       pci_bus_add_devices(bus);
+}
+
 static int __init pcibios_init(void)
 {
        struct pci_controller *hose, *tmp;
-       struct pci_bus *bus;
 
        /* For now, override phys_mem_access_prot. If we need it,
         * later, we may move that initialization to each ppc_md
@@ -242,13 +523,8 @@ static int __init pcibios_init(void)
        printk("PCI: Probing PCI hardware\n");
 
        /* Scan all of the recorded PCI controllers.  */
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-               hose->last_busno = 0xff;
-               bus = pci_scan_bus(hose->first_busno, hose->ops,
-                                  hose->arch_data);
-               hose->bus = bus;
-               hose->last_busno = bus->subordinate;
-       }
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+               scan_phb(hose);
 
 #ifndef CONFIG_PPC_ISERIES
        if (pci_probe_only)
@@ -820,120 +1096,89 @@ void phbs_remap_io(void)
 /*
  * ppc64 can have multifunction devices that do not respond to function 0.
  * In this case we must scan all functions.
+ * XXX this can go now, we use the OF device tree in all the
+ * cases that caused problems. -- paulus
  */
 int pcibios_scan_all_fns(struct pci_bus *bus, int devfn)
 {
-       struct device_node *busdn, *dn;
-
-       if (bus->self)
-               busdn = pci_device_to_OF_node(bus->self);
-       else
-               busdn = bus->sysdata;   /* must be a phb */
-
-       if (busdn == NULL)
-              return 0;
-
-       /*
-        * Check to see if there is any of the 8 functions are in the
-        * device tree.  If they are then we need to scan all the
-        * functions of this slot.
-        */
-       for (dn = busdn->child; dn; dn = dn->sibling) {
-              struct pci_dn *pdn = dn->data;
-              if (pdn && (pdn->devfn >> 3) == (devfn >> 3))
-                       return 1;
-       }
-
        return 0;
 }
 
+static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
+{
+       struct pci_controller *hose = pci_bus_to_host(dev->bus);
+       unsigned long start, end, mask, offset;
+
+       if (res->flags & IORESOURCE_IO) {
+               offset = (unsigned long)hose->io_base_virt - pci_io_base;
+
+               start = res->start += offset;
+               end = res->end += offset;
+
+               /* Need to allow IO access to pages that are in the
+                  ISA range */
+               if (start < MAX_ISA_PORT) {
+                       if (end > MAX_ISA_PORT)
+                               end = MAX_ISA_PORT;
+
+                       start >>= PAGE_SHIFT;
+                       end >>= PAGE_SHIFT;
+
+                       /* get the range of pages for the map */
+                       mask = ((1 << (end+1)) - 1) ^ ((1 << start) - 1);
+                       io_page_mask |= mask;
+               }
+       } else if (res->flags & IORESOURCE_MEM) {
+               res->start += hose->pci_mem_offset;
+               res->end += hose->pci_mem_offset;
+       }
+}
 
 void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,
-                                          struct pci_bus *bus)
+                                             struct pci_bus *bus)
 {
        /* Update device resources.  */
-       struct pci_controller *hose = pci_bus_to_host(bus);
        int i;
 
-       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-               if (dev->resource[i].flags & IORESOURCE_IO) {
-                       unsigned long offset = (unsigned long)hose->io_base_virt
-                               - pci_io_base;
-                        unsigned long start, end, mask;
-
-                        start = dev->resource[i].start += offset;
-                        end = dev->resource[i].end += offset;
-
-                        /* Need to allow IO access to pages that are in the
-                           ISA range */
-                        if (start < MAX_ISA_PORT) {
-                                if (end > MAX_ISA_PORT)
-                                        end = MAX_ISA_PORT;
-
-                                start >>= PAGE_SHIFT;
-                                end >>= PAGE_SHIFT;
-
-                                /* get the range of pages for the map */
-                                mask = ((1 << (end+1))-1) ^ ((1 << start)-1);
-                                io_page_mask |= mask;
-                        }
-               }
-                else if (dev->resource[i].flags & IORESOURCE_MEM) {
-                       dev->resource[i].start += hose->pci_mem_offset;
-                       dev->resource[i].end += hose->pci_mem_offset;
-               }
-        }
+       for (i = 0; i < PCI_NUM_RESOURCES; i++)
+               if (dev->resource[i].flags)
+                       fixup_resource(&dev->resource[i], dev);
 }
 EXPORT_SYMBOL(pcibios_fixup_device_resources);
 
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+static void __devinit do_bus_setup(struct pci_bus *bus)
 {
-       struct pci_controller *hose = pci_bus_to_host(bus);
-       struct pci_dev *dev = bus->self;
-       struct resource *res;
-       int i;
+       struct pci_dev *dev;
 
-       if (!dev) {
-               /* Root bus. */
+       ppc_md.iommu_bus_setup(bus);
 
-               hose->bus = bus;
-               bus->resource[0] = res = &hose->io_resource;
+       list_for_each_entry(dev, &bus->devices, bus_list)
+               ppc_md.iommu_dev_setup(dev);
 
-               if (res->flags && request_resource(&ioport_resource, res))
-                       printk(KERN_ERR "Failed to request IO on "
-                                       "PCI domain %d\n", pci_domain_nr(bus));
+       if (ppc_md.irq_bus_setup)
+               ppc_md.irq_bus_setup(bus);
+}
 
-               for (i = 0; i < 3; ++i) {
-                       res = &hose->mem_resources[i];
-                       bus->resource[i+1] = res;
-                       if (res->flags && request_resource(&iomem_resource, res))
-                               printk(KERN_ERR "Failed to request MEM on "
-                                               "PCI domain %d\n",
-                                               pci_domain_nr(bus));
-               }
-       } else if (pci_probe_only &&
-                  (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+       struct pci_dev *dev = bus->self;
+
+       if (dev && pci_probe_only &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
                /* This is a subordinate bridge */
 
                pci_read_bridge_bases(bus);
                pcibios_fixup_device_resources(dev, bus);
        }
 
-       ppc_md.iommu_bus_setup(bus);
-
-       list_for_each_entry(dev, &bus->devices, bus_list)
-               ppc_md.iommu_dev_setup(dev);
-
-       if (ppc_md.irq_bus_setup)
-               ppc_md.irq_bus_setup(bus);
+       do_bus_setup(bus);
 
        if (!pci_probe_only)
                return;
 
-       list_for_each_entry(dev, &bus->devices, bus_list) {
+       list_for_each_entry(dev, &bus->devices, bus_list)
                if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
                        pcibios_fixup_device_resources(dev, bus);
-       }
 }
 EXPORT_SYMBOL(pcibios_fixup_bus);
 
index d37bff2d7d40c3ae9af84e8b9d047fa53766bdb2..dc40a0cad0b47e387e2b207e43f0d70eebdf80ac 100644 (file)
@@ -388,7 +388,7 @@ static void __init setup_u3_agp(struct pci_controller* hose)
         * the reg address cell, we shall fix that by killing struct
         * reg_property and using some accessor functions instead
         */
-               hose->first_busno = 0xf0;
+       hose->first_busno = 0xf0;
        hose->last_busno = 0xff;
        has_uninorth = 1;
        hose->ops = &macrisc_pci_ops;
@@ -473,7 +473,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
                        continue;
                }               
                cur++;
-                       DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
+               DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
                    cur-1, res->start - 1, cur, res->end + 1);
                hose->mem_resources[cur].name = np->full_name;
                hose->mem_resources[cur].flags = IORESOURCE_MEM;
@@ -603,24 +603,24 @@ static int __init add_bridge(struct device_node *dev)
        char* disp_name;
        int *bus_range;
        int primary = 1;
-       struct property *of_prop;
+       struct property *of_prop;
 
        DBG("Adding PCI host bridge %s\n", dev->full_name);
 
-               bus_range = (int *) get_property(dev, "bus-range", &len);
-               if (bus_range == NULL || len < 2 * sizeof(int)) {
-                       printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
-                                      dev->full_name);
-               }
+       bus_range = (int *) get_property(dev, "bus-range", &len);
+       if (bus_range == NULL || len < 2 * sizeof(int)) {
+               printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
+                       dev->full_name);
+       }
 
        hose = alloc_bootmem(sizeof(struct pci_controller));
        if (hose == NULL)
                return -ENOMEM;
-               pci_setup_pci_controller(hose);
+       pci_setup_pci_controller(hose);
 
-               hose->arch_data = dev;
-               hose->first_busno = bus_range ? bus_range[0] : 0;
-               hose->last_busno = bus_range ? bus_range[1] : 0xff;
+       hose->arch_data = dev;
+       hose->first_busno = bus_range ? bus_range[0] : 0;
+       hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
        of_prop = alloc_bootmem(sizeof(struct property) +
                                sizeof(hose->global_number));
@@ -634,24 +634,24 @@ static int __init add_bridge(struct device_node *dev)
        }
 
        disp_name = NULL;
-               if (device_is_compatible(dev, "u3-agp")) {
-                       setup_u3_agp(hose);
-                       disp_name = "U3-AGP";
-                       primary = 0;
-               } else if (device_is_compatible(dev, "u3-ht")) {
-                       setup_u3_ht(hose);
-                       disp_name = "U3-HT";
-                       primary = 1;
-               }
-               printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
-                       disp_name, hose->first_busno, hose->last_busno);
-
-               /* Interpret the "ranges" property */
-               /* This also maps the I/O region and sets isa_io/mem_base */
-               pmac_process_bridge_OF_ranges(hose, dev, primary);
-
-               /* Fixup "bus-range" OF property */
-               fixup_bus_range(dev);
+       if (device_is_compatible(dev, "u3-agp")) {
+               setup_u3_agp(hose);
+               disp_name = "U3-AGP";
+               primary = 0;
+       } else if (device_is_compatible(dev, "u3-ht")) {
+               setup_u3_ht(hose);
+               disp_name = "U3-HT";
+               primary = 1;
+       }
+       printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
+               disp_name, hose->first_busno, hose->last_busno);
+
+       /* Interpret the "ranges" property */
+       /* This also maps the I/O region and sets isa_io/mem_base */
+       pmac_process_bridge_OF_ranges(hose, dev, primary);
+
+       /* Fixup "bus-range" OF property */
+       fixup_bus_range(dev);
 
        return 0;
 }
index e7f695dcd8c8dd4dae28d7626e421f93397eca19..325426c7bed00f5348ac0fc2dcdb64949a3ff716 100644 (file)
@@ -477,6 +477,18 @@ static int __init pmac_probe(int platform)
        return 1;
 }
 
+static int pmac_probe_mode(struct pci_bus *bus)
+{
+       struct device_node *node = bus->sysdata;
+
+       /* We need to use normal PCI probing for the AGP bus,
+          since the device for the AGP bridge isn't in the tree. */
+       if (bus->self == NULL && device_is_compatible(node, "u3-agp"))
+               return PCI_PROBE_NORMAL;
+
+       return PCI_PROBE_DEVTREE;
+}
+
 struct machdep_calls __initdata pmac_md = {
 #ifdef CONFIG_HOTPLUG_CPU
        .cpu_die                = generic_mach_cpu_die,
@@ -488,6 +500,7 @@ struct machdep_calls __initdata pmac_md = {
        .init_IRQ               = pmac_init_IRQ,
        .get_irq                = mpic_get_irq,
        .pcibios_fixup          = pmac_pcibios_fixup,
+       .pci_probe_mode         = pmac_probe_mode,
        .restart                = pmac_restart,
        .power_off              = pmac_power_off,
        .halt                   = pmac_halt,
index 7a7e027653ad922dac160da11e545401696148ed..887005358eb1faa40bdba25f77d75650f21d851a 100644 (file)
@@ -54,6 +54,7 @@
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/time.h>
+#include <asm/plpar_wrappers.h>
 
 #ifndef CONFIG_SMP
 struct task_struct *last_task_used_math = NULL;
@@ -163,7 +164,30 @@ int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs)
 
 #endif /* CONFIG_ALTIVEC */
 
+static void set_dabr_spr(unsigned long val)
+{
+       mtspr(SPRN_DABR, val);
+}
+
+int set_dabr(unsigned long dabr)
+{
+       int ret = 0;
+
+       if (firmware_has_feature(FW_FEATURE_XDABR)) {
+               /* We want to catch accesses from kernel and userspace */
+               unsigned long flags = H_DABRX_KERNEL|H_DABRX_USER;
+               ret = plpar_set_xdabr(dabr, flags);
+       } else if (firmware_has_feature(FW_FEATURE_DABR)) {
+               ret = plpar_set_dabr(dabr);
+       } else {
+               set_dabr_spr(dabr);
+       }
+
+       return ret;
+}
+
 DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
+static DEFINE_PER_CPU(unsigned long, current_dabr);
 
 struct task_struct *__switch_to(struct task_struct *prev,
                                struct task_struct *new)
@@ -198,6 +222,11 @@ struct task_struct *__switch_to(struct task_struct *prev,
                new->thread.regs->msr |= MSR_VEC;
 #endif /* CONFIG_ALTIVEC */
 
+       if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) {
+               set_dabr(new->thread.dabr);
+               __get_cpu_var(current_dabr) = new->thread.dabr;
+       }
+
        flush_tlb_pending();
 
        new_thread = &new->thread;
@@ -334,6 +363,11 @@ void flush_thread(void)
                last_task_used_altivec = NULL;
 #endif /* CONFIG_ALTIVEC */
 #endif /* CONFIG_SMP */
+
+       if (current->thread.dabr) {
+               current->thread.dabr = 0;
+               set_dabr(0);
+       }
 }
 
 void
index 2993f108d96d309f6f333bb47b38c86373551239..85ed3188a91d0a7ef7c3799c8cf9a7992f411ac1 100644 (file)
@@ -17,6 +17,7 @@
  * this archive for more details.
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -206,6 +207,19 @@ int sys_ptrace(long request, long pid, long addr, long data)
                break;
        }
 
+       case PTRACE_GET_DEBUGREG: {
+               ret = -EINVAL;
+               /* We only support one DABR and no IABRS at the moment */
+               if (addr > 0)
+                       break;
+               ret = put_user(child->thread.dabr,
+                              (unsigned long __user *)data);
+               break;
+       }
+
+       case PTRACE_SET_DEBUGREG:
+               ret = ptrace_set_debugreg(child, addr, data);
+
        case PTRACE_DETACH:
                ret = ptrace_detach(child, data);
                break;
@@ -274,6 +288,20 @@ int sys_ptrace(long request, long pid, long addr, long data)
                break;
        }
 
+#ifdef CONFIG_ALTIVEC
+       case PTRACE_GETVRREGS:
+               /* Get the child altivec register state. */
+               flush_altivec_to_thread(child);
+               ret = get_vrregs((unsigned long __user *)data, child);
+               break;
+
+       case PTRACE_SETVRREGS:
+               /* Set the child altivec register state. */
+               flush_altivec_to_thread(child);
+               ret = set_vrregs(child, (unsigned long __user *)data);
+               break;
+#endif
+
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
index 16436426c7e240db5e6599436d149e32d3412aa6..fb8c22d6084a7c280a0c74d9f9d3f1ebb523471d 100644 (file)
@@ -17,6 +17,7 @@
  * this archive for more details.
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -337,6 +338,19 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
                break;
        }
 
+       case PTRACE_GET_DEBUGREG: {
+               ret = -EINVAL;
+               /* We only support one DABR and no IABRS at the moment */
+               if (addr > 0)
+                       break;
+               ret = put_user(child->thread.dabr, (u32 __user *)data);
+               break;
+       }
+
+       case PTRACE_SET_DEBUGREG:
+               ret = ptrace_set_debugreg(child, addr, data);
+               break;
+
        case PTRACE_DETACH:
                ret = ptrace_detach(child, data);
                break;
@@ -405,9 +419,23 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
                break;
        }
 
-       case PTRACE_GETEVENTMSG:
-                ret = put_user(child->ptrace_message, (unsigned int __user *) data);
-                break;
+       case PTRACE_GETEVENTMSG:
+               ret = put_user(child->ptrace_message, (unsigned int __user *) data);
+               break;
+
+#ifdef CONFIG_ALTIVEC
+       case PTRACE_GETVRREGS:
+               /* Get the child altivec register state. */
+               flush_altivec_to_thread(child);
+               ret = get_vrregs((unsigned long __user *)data, child);
+               break;
+
+       case PTRACE_SETVRREGS:
+               /* Set the child altivec register state. */
+               flush_altivec_to_thread(child);
+               ret = set_vrregs(child, (unsigned long __user *)data);
+               break;
+#endif
 
        default:
                ret = ptrace_request(child, request, addr, data);
index 3c00f7bfc1b5736d43ab2011e3ac37aafe6da9cf..41b97dc9cc0a0a9735675bdee038bf7b7008007e 100644 (file)
@@ -59,8 +59,6 @@ char mce_data_buf[RTAS_ERROR_LOG_MAX]
 /* This is true if we are using the firmware NMI handler (typically LPAR) */
 extern int fwnmi_active;
 
-extern void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr);
-
 static int ras_get_sensor_state_token;
 static int ras_check_exception_token;
 
index bfa8791c9807f865bb89085f0054759bbd452eaa..5ac48bd64891f98e0846ef8f0959ccba01da682b 100644 (file)
@@ -1064,8 +1064,6 @@ void __init setup_arch(char **cmdline_p)
 #define PPC64_LINUX_FUNCTION 0x0f000000
 #define PPC64_IPL_MESSAGE 0xc0000000
 #define PPC64_TERM_MESSAGE 0xb0000000
-#define PPC64_ATTN_MESSAGE 0xa0000000
-#define PPC64_DUMP_MESSAGE 0xd0000000
 
 static void ppc64_do_msg(unsigned int src, const char *msg)
 {
@@ -1093,20 +1091,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg)
        printk("[terminate]%04x %s\n", src, msg);
 }
 
-/* Print something that needs attention (device error, etc) */
-void ppc64_attention_msg(unsigned int src, const char *msg)
-{
-       ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg);
-       printk("[attention]%04x %s\n", src, msg);
-}
-
-/* Print a dump progress message. */
-void ppc64_dump_msg(unsigned int src, const char *msg)
-{
-       ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg);
-       printk("[dump]%04x %s\n", src, msg);
-}
-
 /* This should only be called on processor 0 during calibrate decr */
 void __init setup_default_decr(void)
 {
index 49a79a55c32de7d5ab73191dbe78047a6dcf848e..347112cca3c096ac660a3eed66d7aa4b9c0e0b26 100644 (file)
@@ -550,6 +550,15 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
                /* Whee!  Actually deliver the signal.  */
                if (TRAP(regs) == 0x0C00)
                        syscall_restart(regs, &ka);
+
+               /*
+                * Reenable the DABR before delivering the signal to
+                * user space. The DABR will have been cleared if it
+                * triggered inside the kernel.
+                */
+               if (current->thread.dabr)
+                       set_dabr(current->thread.dabr);
+
                return handle_signal(signr, &ka, &info, oldset, regs);
        }
 
index 46f4d6cc7fc9591ce7240887a05edadcd711c6f6..a8b7a5a56bb445b90f7116c3f418fd14b41a657b 100644 (file)
@@ -970,6 +970,14 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
                newsp = regs->gpr[1];
        newsp &= ~0xfUL;
 
+       /*
+        * Reenable the DABR before delivering the signal to
+        * user space. The DABR will have been cleared if it
+        * triggered inside the kernel.
+        */
+       if (current->thread.dabr)
+               set_dabr(current->thread.dabr);
+
        /* Whee!  Actually deliver the signal.  */
        if (ka.sa.sa_flags & SA_SIGINFO)
                ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp);
index d9dc6f28d050050281ccc99e19e2d940de850abd..daf93885dcfab007cc73ddc7e446632d253b0055 100644 (file)
@@ -38,7 +38,7 @@ static void xics_mask_and_ack_irq(unsigned int irq);
 static void xics_end_irq(unsigned int irq);
 static void xics_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
 
-struct hw_interrupt_type xics_pic = {
+static struct hw_interrupt_type xics_pic = {
        .typename = " XICS     ",
        .startup = xics_startup,
        .enable = xics_enable_irq,
@@ -48,7 +48,7 @@ struct hw_interrupt_type xics_pic = {
        .set_affinity = xics_set_affinity
 };
 
-struct hw_interrupt_type xics_8259_pic = {
+static struct hw_interrupt_type xics_8259_pic = {
        .typename = " XICS/8259",
        .ack = xics_mask_and_ack_irq,
 };
@@ -89,9 +89,8 @@ static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS];
 static int xics_irq_8259_cascade = 0;
 static int xics_irq_8259_cascade_real = 0;
 static unsigned int default_server = 0xFF;
-/* also referenced in smp.c... */
-unsigned int default_distrib_server = 0;
-unsigned int interrupt_server_size = 8;
+static unsigned int default_distrib_server = 0;
+static unsigned int interrupt_server_size = 8;
 
 /*
  * XICS only has a single IPI, so encode the messages per CPU
@@ -99,10 +98,10 @@ unsigned int interrupt_server_size = 8;
 struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
 /* RTAS service tokens */
-int ibm_get_xive;
-int ibm_set_xive;
-int ibm_int_on;
-int ibm_int_off;
+static int ibm_get_xive;
+static int ibm_set_xive;
+static int ibm_int_on;
+static int ibm_int_off;
 
 typedef struct {
        int (*xirr_info_get)(int cpu);
@@ -284,16 +283,17 @@ static void xics_enable_irq(unsigned int virq)
        call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
                                DEFAULT_PRIORITY);
        if (call_status != 0) {
-               printk(KERN_ERR "xics_enable_irq: irq=%d: ibm_set_xive "
-                      "returned %x\n", irq, call_status);
+               printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive "
+                      "returned %d\n", irq, call_status);
+               printk("set_xive %x, server %x\n", ibm_set_xive, server);
                return;
        }
 
        /* Now unmask the interrupt (often a no-op) */
        call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq);
        if (call_status != 0) {
-               printk(KERN_ERR "xics_enable_irq: irq=%d: ibm_int_on "
-                      "returned %x\n", irq, call_status);
+               printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on "
+                      "returned %d\n", irq, call_status);
                return;
        }
 }
@@ -308,8 +308,8 @@ static void xics_disable_real_irq(unsigned int irq)
 
        call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq);
        if (call_status != 0) {
-               printk(KERN_ERR "xics_disable_real_irq: irq=%d: "
-                      "ibm_int_off returned %x\n", irq, call_status);
+               printk(KERN_ERR "xics_disable_real_irq: irq=%u: "
+                      "ibm_int_off returned %d\n", irq, call_status);
                return;
        }
 
@@ -317,8 +317,8 @@ static void xics_disable_real_irq(unsigned int irq)
        /* Have to set XIVE to 0xff to be able to remove a slot */
        call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, 0xff);
        if (call_status != 0) {
-               printk(KERN_ERR "xics_disable_irq: irq=%d: ibm_set_xive(0xff)"
-                      " returned %x\n", irq, call_status);
+               printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)"
+                      " returned %d\n", irq, call_status);
                return;
        }
 }
@@ -380,7 +380,7 @@ int xics_get_irq(struct pt_regs *regs)
                if (irq == NO_IRQ)
                        irq = real_irq_to_virt_slowpath(vec);
                if (irq == NO_IRQ) {
-                       printk(KERN_ERR "Interrupt %d (real) is invalid,"
+                       printk(KERN_ERR "Interrupt %u (real) is invalid,"
                               " disabling it.\n", vec);
                        xics_disable_real_irq(vec);
                } else
@@ -622,7 +622,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
        status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
 
        if (status) {
-               printk(KERN_ERR "xics_set_affinity: irq=%d ibm,get-xive "
+               printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive "
                       "returns %d\n", irq, status);
                return;
        }
@@ -641,7 +641,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
                                irq, newmask, xics_status[1]);
 
        if (status) {
-               printk(KERN_ERR "xics_set_affinity: irq=%d ibm,set-xive "
+               printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
                       "returns %d\n", irq, status);
                return;
        }
@@ -720,7 +720,7 @@ void xics_migrate_irqs_away(void)
 
                status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
                if (status) {
-                       printk(KERN_ERR "migrate_irqs_away: irq=%d "
+                       printk(KERN_ERR "migrate_irqs_away: irq=%u "
                                        "ibm,get-xive returns %d\n",
                                        virq, status);
                        goto unlock;
@@ -734,7 +734,7 @@ void xics_migrate_irqs_away(void)
                if (xics_status[0] != get_hard_smp_processor_id(cpu))
                        goto unlock;
 
-               printk(KERN_WARNING "IRQ %d affinity broken off cpu %u\n",
+               printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n",
                       virq, cpu);
 
                /* Reset affinity to all cpus */
index 772f0714a5b7d4be9231b362650c920c1c70cb9c..7fbc68bbb7391cef88ee614d2ec54f291f54c7dc 100644 (file)
@@ -77,6 +77,28 @@ static int store_updates_sp(struct pt_regs *regs)
        return 0;
 }
 
+static void do_dabr(struct pt_regs *regs, unsigned long error_code)
+{
+       siginfo_t info;
+
+       if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
+                       11, SIGSEGV) == NOTIFY_STOP)
+               return;
+
+       if (debugger_dabr_match(regs))
+               return;
+
+       /* Clear the DABR */
+       set_dabr(0);
+
+       /* Deliver the signal to userspace */
+       info.si_signo = SIGTRAP;
+       info.si_errno = 0;
+       info.si_code = TRAP_HWBKPT;
+       info.si_addr = (void __user *)regs->nip;
+       force_sig_info(SIGTRAP, &info, current);
+}
+
 /*
  * The error_code parameter is
  *  - DSISR for a non-SLB data access fault,
@@ -111,12 +133,9 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
        if (!user_mode(regs) && (address >= TASK_SIZE))
                return SIGSEGV;
 
-       if (error_code & DSISR_DABRMATCH) {
-               if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
-                                       11, SIGSEGV) == NOTIFY_STOP)
-                       return 0;
-               if (debugger_dabr_match(regs))
-                       return 0;
+       if (error_code & DSISR_DABRMATCH) {
+               do_dabr(regs, error_code);
+               return 0;
        }
 
        if (in_atomic() || mm == NULL) {
index 183c3e40025881daab3b80ec360a47f2d380af1e..02eb40dac0b304fbcab0b3cf0d136bc312a9eb79 100644 (file)
@@ -46,7 +46,6 @@ GSETSPR(287, pvr)
 GSETSPR(1008, hid0)
 GSETSPR(1009, hid1)
 GSETSPR(1010, iabr)
-GSETSPR(1013, dabr)
 GSETSPR(1023, pir)
 
 static inline void store_inst(void *p)
index 45908b10acd345970da83c6d5369fc850e6b072a..74e63a886a69ae4b9769cacd3b6f2df44bcec48d 100644 (file)
@@ -586,6 +586,8 @@ int xmon_dabr_match(struct pt_regs *regs)
 {
        if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
                return 0;
+       if (dabr.enabled == 0)
+               return 0;
        xmon_core(regs, 0);
        return 1;
 }
@@ -628,20 +630,6 @@ int xmon_fault_handler(struct pt_regs *regs)
        return 0;
 }
 
-/* On systems with a hypervisor, we can't set the DABR
-   (data address breakpoint register) directly. */
-static void set_controlled_dabr(unsigned long val)
-{
-#ifdef CONFIG_PPC_PSERIES
-       if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
-               int rc = plpar_hcall_norets(H_SET_DABR, val);
-               if (rc != H_Success)
-                       xmon_printf("Warning: setting DABR failed (%d)\n", rc);
-       } else
-#endif
-               set_dabr(val);
-}
-
 static struct bpt *at_breakpoint(unsigned long pc)
 {
        int i;
@@ -728,7 +716,7 @@ static void insert_bpts(void)
 static void insert_cpu_bpts(void)
 {
        if (dabr.enabled)
-               set_controlled_dabr(dabr.address | (dabr.enabled & 7));
+               set_dabr(dabr.address | (dabr.enabled & 7));
        if (iabr && cpu_has_feature(CPU_FTR_IABR))
                set_iabr(iabr->address
                         | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
@@ -756,7 +744,7 @@ static void remove_bpts(void)
 
 static void remove_cpu_bpts(void)
 {
-       set_controlled_dabr(0);
+       set_dabr(0);
        if (cpu_has_feature(CPU_FTR_IABR))
                set_iabr(0);
 }
index 18610cea03a21d6d59bfb23224ecf1672678c7bc..ed877d0f27e6e038b12c24489ac1e3914d7ba478 100644 (file)
@@ -678,7 +678,7 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, size
        ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
        set_fs(old_fs);
        
-       if (!ret && offset && put_user(of, offset))
+       if (offset && put_user(of, offset))
                return -EFAULT;
                
        return ret;
index 7931d6f92819eb768c78792e336af88219b11892..787d5f1347ec48de6538bc46e44d712acbddab40 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 
 void *module_alloc(unsigned long size)
 {
@@ -37,7 +38,7 @@ void module_free(struct module *mod, void *module_region)
 }
 
 /* Make generic code ignore STT_REGISTER dummy undefined symbols,
- * and replace references to .func with func as in ppc64's dedotify.
+ * and replace references to .func with _Func
  */
 int module_frob_arch_sections(Elf_Ehdr *hdr,
                              Elf_Shdr *sechdrs,
@@ -64,8 +65,10 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
                                sym[i].st_shndx = SHN_ABS;
                        else {
                                char *name = strtab + sym[i].st_name;
-                               if (name[0] == '.')
-                                       memmove(name, name+1, strlen(name));
+                               if (name[0] == '.') {
+                                       name[0] = '_';
+                                       name[1] = toupper(name[1]);
+                               }
                        }
                }
        }
index f84809333624aae07d323e3b1577bc0ce5ddfb74..1c8fd0fd930590ce218d915cbcc4cf128fc4b66d 100644 (file)
@@ -97,19 +97,12 @@ extern void ___rw_write_enter(void);
 /* Alias functions whose names begin with "." and export the aliases.
  * The module references will be fixed up by module_frob_arch_sections.
  */
-#define DOT_ALIAS2(__ret, __x, __arg1, __arg2) \
-       extern __ret __x(__arg1, __arg2); \
-       asm(".weak " #__x);\
-       asm(#__x "=." #__x);
-
-DOT_ALIAS2(int, div, int, int)
-DOT_ALIAS2(int, mul, int, int)
-DOT_ALIAS2(int, rem, int, int)
-DOT_ALIAS2(unsigned, udiv, unsigned, unsigned)
-DOT_ALIAS2(unsigned, umul, unsigned, unsigned)
-DOT_ALIAS2(unsigned, urem, unsigned, unsigned)
-
-#undef DOT_ALIAS2
+extern int _Div(int, int);
+extern int _Mul(int, int);
+extern int _Rem(int, int);
+extern unsigned _Udiv(unsigned, unsigned);
+extern unsigned _Umul(unsigned, unsigned);
+extern unsigned _Urem(unsigned, unsigned);
 
 /* used by various drivers */
 EXPORT_SYMBOL(sparc_cpu_model);
@@ -320,12 +313,12 @@ EXPORT_SYMBOL(__lshrdi3);
 EXPORT_SYMBOL(__muldi3);
 EXPORT_SYMBOL(__divdi3);
 
-EXPORT_SYMBOL(rem);
-EXPORT_SYMBOL(urem);
-EXPORT_SYMBOL(mul);
-EXPORT_SYMBOL(umul);
-EXPORT_SYMBOL(div);
-EXPORT_SYMBOL(udiv);
+EXPORT_SYMBOL(_Rem);
+EXPORT_SYMBOL(_Urem);
+EXPORT_SYMBOL(_Mul);
+EXPORT_SYMBOL(_Umul);
+EXPORT_SYMBOL(_Div);
+EXPORT_SYMBOL(_Udiv);
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 EXPORT_SYMBOL(do_BUG);
index 83dffbc2f62f05e1d7977931a623a2d830a0279b..da693560d8788a4c9169a5b16534c6a8c20640a3 100644 (file)
@@ -16,7 +16,9 @@
  */
 
        .globl .mul
+       .globl _Mul
 .mul:
+_Mul:  /* needed for export */
        mov     %o0, %y         ! multiplier -> Y
        andncc  %o0, 0xfff, %g0 ! test bits 12..31
        be      Lmul_shortway   ! if zero, can do it the short way
index 44508148d055718d3f8c6f56b693ae1c1d10ffd7..bf015a90d07e985535729bd0540b6bf0014d7a7f 100644 (file)
@@ -43,7 +43,9 @@
 
 
        .globl .rem
+       .globl _Rem
 .rem:
+_Rem:  /* needed for export */
        ! compute sign of result; if neither is negative, no problem
        orcc    %o1, %o0, %g0   ! either negative?
        bge     2f                      ! no, go do the divide
index e0ad80b6f63d8053d84df24e75ff7e5b0c95175c..af9451629d0bdda24ca2a41706f244d1c0a14e53 100644 (file)
@@ -43,7 +43,9 @@
 
 
        .globl .div
+       .globl _Div
 .div:
+_Div:  /* needed for export */
        ! compute sign of result; if neither is negative, no problem
        orcc    %o1, %o0, %g0   ! either negative?
        bge     2f                      ! no, go do the divide
index 2abfc6b0f3e91e8cb6244533f87f47afefce0b89..169e01da671574a38d58b98a5f82317a9fee9a56 100644 (file)
@@ -43,7 +43,9 @@
 
 
        .globl .udiv
+       .globl _Udiv
 .udiv:
+_Udiv: /* needed for export */
 
        ! Ready to divide.  Compute size of quotient; scale comparand.
        orcc    %o1, %g0, %o5
index a784720a8a220b4624365673bd810171e087d8ef..f0e5b20a2536fdbaeb88842f83a1d6ed58d90262 100644 (file)
@@ -21,7 +21,9 @@
  */
 
        .globl .umul
+       .globl _Umul
 .umul:
+_Umul: /* needed for export */
        or      %o0, %o1, %o4
        mov     %o0, %y         ! multiplier -> Y
 
index ec7f0c502c569b7024c34b698e1b1205b5df3587..6b92bdc8b04cc12c5ab994aa962aa6e38938e41d 100644 (file)
@@ -41,7 +41,9 @@
  */
 
        .globl .urem
+       .globl _Urem
 .urem:
+_Urem: /* needed for export */
 
        ! Ready to divide.  Compute size of quotient; scale comparand.
        orcc    %o1, %g0, %o5
index f4399c701b77957d01d93fa7ada889bd6d47e443..18c6e915d69b84260a43b979b28e5058c60a193a 100644 (file)
@@ -46,7 +46,7 @@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
 $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
                              $(obj)/vmlinux.bin $(obj)/tools/build FORCE
        $(call if_changed,image)
-       @echo 'Kernel: $@ is ready'
+       @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
        $(call if_changed,objcopy)
index b38d5b8b5fb844ebf92ed2221faa1bcf2d274e6a..0e10fd84c7cc79e2ee31832e6104c915f3c50597 100644 (file)
@@ -83,7 +83,7 @@ static unsigned char *real_mode; /* Pointer to real-mode data */
 #endif
 #define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
 
-extern char input_data[];
+extern unsigned char input_data[];
 extern int input_len;
 
 static long bytes_out = 0;
@@ -288,7 +288,7 @@ void setup_normal_output_buffer(void)
 #else
        if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory");
 #endif
-       output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */
+       output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */
        free_mem_end_ptr = (long)real_mode;
 }
 
@@ -305,7 +305,7 @@ void setup_output_buffer_if_we_run_high(struct moveparams *mv)
 #else
        if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
 #endif 
-       mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
+       mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START;
        low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
          ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
        low_buffer_size = low_buffer_end - LOW_BUFFER_START;
index bf57e2362bf4cbd79bc9f5e02d7f11b8b18abc0b..f8db7e500fbfdd727e16ac7a9c71f1cab078f243 100644 (file)
@@ -1,11 +1,12 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13-rc6-git3
-# Fri Aug 12 16:40:34 2005
+# Linux kernel version: 2.6.13-git11
+# Mon Sep 12 16:16:16 2005
 #
 CONFIG_X86_64=y
 CONFIG_64BIT=y
 CONFIG_X86=y
+CONFIG_SEMAPHORE_SLEEPERS=y
 CONFIG_MMU=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -13,6 +14,7 @@ CONFIG_X86_CMPXCHG=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_GENERIC_IOMAP=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 
 #
 # Code maturity level options
@@ -26,6 +28,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
 # General setup
 #
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -37,6 +40,7 @@ CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
+CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
@@ -102,6 +106,7 @@ CONFIG_DISCONTIGMEM_MANUAL=y
 CONFIG_DISCONTIGMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_NEED_MULTIPLE_NODES=y
+# CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_NR_CPUS=32
@@ -122,6 +127,7 @@ CONFIG_HZ=250
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_ISA_DMA_API=y
+CONFIG_GENERIC_PENDING_IRQ=y
 
 #
 # Power management options
@@ -194,7 +200,6 @@ CONFIG_UNORDERED_IO=y
 # CONFIG_PCIEPORTBUS is not set
 CONFIG_PCI_MSI=y
 # CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES is not set
 # CONFIG_PCI_DEBUG is not set
 
 #
@@ -234,7 +239,10 @@ CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
@@ -244,8 +252,8 @@ CONFIG_IP_FIB_HASH=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-CONFIG_IP_TCPDIAG_IPV6=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_BIC=y
 CONFIG_IPV6=y
@@ -257,6 +265,11 @@ CONFIG_IPV6=y
 # CONFIG_IPV6_TUNNEL is not set
 # CONFIG_NETFILTER is not set
 
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
@@ -280,9 +293,11 @@ CONFIG_IPV6=y
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
 
 #
 # Device Drivers
@@ -329,7 +344,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
 CONFIG_LBD=y
 # CONFIG_CDROM_PKTCDVD is not set
 
@@ -409,6 +423,7 @@ CONFIG_IDEDMA_AUTO=y
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
 # CONFIG_SCSI_PROC_FS is not set
 
@@ -432,7 +447,7 @@ CONFIG_BLK_DEV_SD=y
 #
 # SCSI Transport Attributes
 #
-# CONFIG_SCSI_SPI_ATTRS is not set
+CONFIG_SCSI_SPI_ATTRS=y
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 
@@ -458,6 +473,7 @@ CONFIG_SCSI_SATA=y
 # CONFIG_SCSI_SATA_AHCI is not set
 # CONFIG_SCSI_SATA_SVW is not set
 CONFIG_SCSI_ATA_PIIX=y
+# CONFIG_SCSI_SATA_MV is not set
 # CONFIG_SCSI_SATA_NV is not set
 # CONFIG_SCSI_SATA_PROMISE is not set
 # CONFIG_SCSI_SATA_QSTOR is not set
@@ -536,6 +552,11 @@ CONFIG_TUN=y
 #
 # CONFIG_ARCNET is not set
 
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
 #
 # Ethernet (10 or 100Mbit)
 #
@@ -586,6 +607,7 @@ CONFIG_E1000=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
@@ -595,6 +617,7 @@ CONFIG_TIGON3=y
 #
 # Ethernet (10000 Mbit)
 #
+# CONFIG_CHELSIO_T1 is not set
 # CONFIG_IXGB is not set
 CONFIG_S2IO=m
 # CONFIG_S2IO_NAPI is not set
@@ -749,7 +772,6 @@ CONFIG_MAX_RAW_DEVS=256
 # I2C support
 #
 # CONFIG_I2C is not set
-# CONFIG_I2C_SENSOR is not set
 
 #
 # Dallas's 1-wire bus
@@ -760,6 +782,7 @@ CONFIG_MAX_RAW_DEVS=256
 # Hardware Monitoring support
 #
 CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -767,6 +790,10 @@ CONFIG_HWMON=y
 #
 # CONFIG_IBM_ASM is not set
 
+#
+# Multimedia Capabilities Port drivers
+#
+
 #
 # Multimedia devices
 #
@@ -858,9 +885,8 @@ CONFIG_USB_UHCI_HCD=y
 #
 # USB Device Class drivers
 #
-# CONFIG_USB_AUDIO is not set
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 # CONFIG_USB_BLUETOOTH_TTY is not set
-# CONFIG_USB_MIDI is not set
 # CONFIG_USB_ACM is not set
 CONFIG_USB_PRINTER=y
 
@@ -877,6 +903,7 @@ CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
 
 #
 # USB Input Devices
@@ -893,6 +920,7 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_MTOUCH is not set
 # CONFIG_USB_ITMTOUCH is not set
 # CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
@@ -976,6 +1004,8 @@ CONFIG_USB_MON=y
 # Firmware Drivers
 #
 # CONFIG_EDD is not set
+# CONFIG_DELL_RBU is not set
+CONFIG_DCDBAS=m
 
 #
 # File systems
@@ -1000,10 +1030,6 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
 # CONFIG_REISERFS_FS_SECURITY is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
-
-#
-# XFS support
-#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -1012,6 +1038,7 @@ CONFIG_INOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=y
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -1037,12 +1064,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1074,6 +1100,7 @@ CONFIG_NFSD_V3=y
 # CONFIG_NFSD_V3_ACL is not set
 # CONFIG_NFSD_V4 is not set
 CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
@@ -1086,6 +1113,7 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1150,6 +1178,7 @@ CONFIG_OPROFILE=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_LOG_BUF_SHIFT=18
+CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -1157,6 +1186,7 @@ CONFIG_LOG_BUF_SHIFT=18
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 CONFIG_DEBUG_FS=y
+# CONFIG_FRAME_POINTER is not set
 CONFIG_INIT_DEBUG=y
 # CONFIG_IOMMU_DEBUG is not set
 CONFIG_KPROBES=y
@@ -1180,5 +1210,6 @@ CONFIG_KPROBES=y
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
index 5244f803203d652d13ec08917eac18633865b774..e0eb0c712fe91fbddfc74beb9048eace392e1566 100644 (file)
  * with the int 0x80 path.
  */    
 ENTRY(ia32_sysenter_target)
-       CFI_STARTPROC
+       CFI_STARTPROC   simple
+       CFI_DEF_CFA     rsp,0
+       CFI_REGISTER    rsp,rbp
        swapgs
        movq    %gs:pda_kernelstack, %rsp
        addq    $(PDA_STACKOFFSET),%rsp 
        sti     
        movl    %ebp,%ebp               /* zero extension */
        pushq   $__USER32_DS
+       CFI_ADJUST_CFA_OFFSET 8
+       /*CFI_REL_OFFSET ss,0*/
        pushq   %rbp
+       CFI_ADJUST_CFA_OFFSET 8
+       CFI_REL_OFFSET rsp,0
        pushfq
+       CFI_ADJUST_CFA_OFFSET 8
+       /*CFI_REL_OFFSET rflags,0*/
        movl    $VSYSCALL32_SYSEXIT, %r10d
+       CFI_REGISTER rip,r10
        pushq   $__USER32_CS
+       CFI_ADJUST_CFA_OFFSET 8
+       /*CFI_REL_OFFSET cs,0*/
        movl    %eax, %eax
        pushq   %r10
+       CFI_ADJUST_CFA_OFFSET 8
+       CFI_REL_OFFSET rip,0
        pushq   %rax
+       CFI_ADJUST_CFA_OFFSET 8
        cld
        SAVE_ARGS 0,0,1
        /* no need to do an access_ok check here because rbp has been
@@ -79,6 +93,7 @@ ENTRY(ia32_sysenter_target)
        .previous       
        GET_THREAD_INFO(%r10)
        testl  $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
+       CFI_REMEMBER_STATE
        jnz  sysenter_tracesys
 sysenter_do_call:      
        cmpl    $(IA32_NR_syscalls),%eax
@@ -94,14 +109,20 @@ sysenter_do_call:
        andl  $~0x200,EFLAGS-R11(%rsp) 
        RESTORE_ARGS 1,24,1,1,1,1
        popfq
+       CFI_ADJUST_CFA_OFFSET -8
+       /*CFI_RESTORE rflags*/
        popq    %rcx                            /* User %esp */
+       CFI_ADJUST_CFA_OFFSET -8
+       CFI_REGISTER rsp,rcx
        movl    $VSYSCALL32_SYSEXIT,%edx        /* User %eip */
+       CFI_REGISTER rip,rdx
        swapgs
        sti             /* sti only takes effect after the next instruction */
        /* sysexit */
        .byte   0xf, 0x35
 
 sysenter_tracesys:
+       CFI_RESTORE_STATE
        SAVE_REST
        CLEAR_RREGS
        movq    $-ENOSYS,RAX(%rsp)      /* really needed? */
@@ -140,21 +161,28 @@ sysenter_tracesys:
  * with the int 0x80 path.     
  */    
 ENTRY(ia32_cstar_target)
-       CFI_STARTPROC
+       CFI_STARTPROC   simple
+       CFI_DEF_CFA     rsp,0
+       CFI_REGISTER    rip,rcx
+       /*CFI_REGISTER  rflags,r11*/
        swapgs
        movl    %esp,%r8d
+       CFI_REGISTER    rsp,r8
        movq    %gs:pda_kernelstack,%rsp
        sti
        SAVE_ARGS 8,1,1
        movl    %eax,%eax       /* zero extension */
        movq    %rax,ORIG_RAX-ARGOFFSET(%rsp)
        movq    %rcx,RIP-ARGOFFSET(%rsp)
+       CFI_REL_OFFSET rip,RIP-ARGOFFSET
        movq    %rbp,RCX-ARGOFFSET(%rsp) /* this lies slightly to ptrace */
        movl    %ebp,%ecx
        movq    $__USER32_CS,CS-ARGOFFSET(%rsp)
        movq    $__USER32_DS,SS-ARGOFFSET(%rsp)
        movq    %r11,EFLAGS-ARGOFFSET(%rsp)
+       /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/
        movq    %r8,RSP-ARGOFFSET(%rsp) 
+       CFI_REL_OFFSET rsp,RSP-ARGOFFSET
        /* no need to do an access_ok check here because r8 has been
           32bit zero extended */ 
        /* hardware stack frame is complete now */      
@@ -164,6 +192,7 @@ ENTRY(ia32_cstar_target)
        .previous       
        GET_THREAD_INFO(%r10)
        testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
+       CFI_REMEMBER_STATE
        jnz   cstar_tracesys
 cstar_do_call: 
        cmpl $IA32_NR_syscalls,%eax
@@ -177,12 +206,16 @@ cstar_do_call:
        jnz  int_ret_from_sys_call
        RESTORE_ARGS 1,-ARG_SKIP,1,1,1
        movl RIP-ARGOFFSET(%rsp),%ecx
+       CFI_REGISTER rip,rcx
        movl EFLAGS-ARGOFFSET(%rsp),%r11d       
+       /*CFI_REGISTER rflags,r11*/
        movl RSP-ARGOFFSET(%rsp),%esp
+       CFI_RESTORE rsp
        swapgs
        sysretl
        
 cstar_tracesys:        
+       CFI_RESTORE_STATE
        SAVE_REST
        CLEAR_RREGS
        movq $-ENOSYS,RAX(%rsp) /* really needed? */
@@ -226,11 +259,18 @@ ia32_badarg:
  */                            
 
 ENTRY(ia32_syscall)
-       CFI_STARTPROC
+       CFI_STARTPROC   simple
+       CFI_DEF_CFA     rsp,SS+8-RIP
+       /*CFI_REL_OFFSET        ss,SS-RIP*/
+       CFI_REL_OFFSET  rsp,RSP-RIP
+       /*CFI_REL_OFFSET        rflags,EFLAGS-RIP*/
+       /*CFI_REL_OFFSET        cs,CS-RIP*/
+       CFI_REL_OFFSET  rip,RIP-RIP
        swapgs  
        sti
        movl %eax,%eax
        pushq %rax
+       CFI_ADJUST_CFA_OFFSET 8
        cld
        /* note the registers are not zero extended to the sf.
           this could be a problem. */
@@ -278,6 +318,8 @@ quiet_ni_syscall:
        jmp  ia32_ptregs_common 
        .endm
 
+       CFI_STARTPROC
+
        PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
        PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
        PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
@@ -290,8 +332,9 @@ quiet_ni_syscall:
        PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx
 
 ENTRY(ia32_ptregs_common)
-       CFI_STARTPROC
        popq %r11
+       CFI_ADJUST_CFA_OFFSET -8
+       CFI_REGISTER rip, r11
        SAVE_REST
        call *%rax
        RESTORE_REST
index 04d80406ce4fed4c1a6ce646253675c65b074269..5389df610e78277d0a6329f98a16d3f1f52c27d0 100644 (file)
@@ -751,7 +751,7 @@ sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
        ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
        set_fs(old_fs);
        
-       if (!ret && offset && put_user(of, offset))
+       if (offset && put_user(of, offset))
                return -EFAULT;
                
        return ret;
index 1579bdd0adcde450ad0a4991e1b6986895800822..bcdd0a805fe70c7357b0aab2adefa59ab081d31e 100644 (file)
@@ -46,3 +46,4 @@ microcode-$(subst m,y,$(CONFIG_MICROCODE))  += ../../i386/kernel/microcode.o
 intel_cacheinfo-y              += ../../i386/kernel/cpu/intel_cacheinfo.o
 quirks-y                       += ../../i386/kernel/quirks.o
 i8237-y                                += ../../i386/kernel/i8237.o
+msr-$(subst m,y,$(CONFIG_X86_MSR))  += ../../i386/kernel/msr.o
index 148f6f7ea315889f1bf0d0d64d92b6b44db7bad2..867a0ebee1773c2a1a678245a665abc8dfbe1df8 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/bootmem.h>
-#include <linux/irq.h>
 #include <linux/acpi.h>
 #include <asm/mpspec.h>
 #include <asm/io.h>
index c9a6b812e926cf3f5c79493433cda35b5c9c7e3b..962ad4823b6a567d4f340bca8d101a2e958dfbd2 100644 (file)
@@ -245,6 +245,8 @@ void __init iommu_hole_init(void)
                
        if (aper_alloc) { 
                /* Got the aperture from the AGP bridge */
+       } else if (swiotlb && !valid_agp) {
+               /* Do nothing */
        } else if ((!no_iommu && end_pfn >= 0xffffffff>>PAGE_SHIFT) ||
                   force_iommu ||
                   valid_agp ||
index 375d369570ca3dbbb365b363585d5b6ecff1ef57..b6e7715d877f38a0d191616c22dc7f9fe98e4509 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/init.h>
 
 #include <linux/mm.h>
-#include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/bootmem.h>
 #include <linux/smp_lock.h>
@@ -109,11 +108,8 @@ void clear_local_APIC(void)
        if (maxlvt >= 4)
                apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
        v = GET_APIC_VERSION(apic_read(APIC_LVR));
-       if (APIC_INTEGRATED(v)) {       /* !82489DX */
-               if (maxlvt > 3)         /* Due to Pentium errata 3AP and 11AP. */
-                       apic_write(APIC_ESR, 0);
-               apic_read(APIC_ESR);
-       }
+       apic_write(APIC_ESR, 0);
+       apic_read(APIC_ESR);
 }
 
 void __init connect_bsp_APIC(void)
@@ -316,8 +312,6 @@ void __init init_bsp_APIC(void)
         */
        apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
        value = APIC_DM_NMI;
-       if (!APIC_INTEGRATED(ver))              /* 82489DX */
-               value |= APIC_LVT_LEVEL_TRIGGER;
        apic_write_around(APIC_LVT1, value);
 }
 
@@ -325,14 +319,6 @@ void __cpuinit setup_local_APIC (void)
 {
        unsigned int value, ver, maxlvt;
 
-       /* Pound the ESR really hard over the head with a big hammer - mbligh */
-       if (esr_disable) {
-               apic_write(APIC_ESR, 0);
-               apic_write(APIC_ESR, 0);
-               apic_write(APIC_ESR, 0);
-               apic_write(APIC_ESR, 0);
-       }
-
        value = apic_read(APIC_LVR);
        ver = GET_APIC_VERSION(value);
 
@@ -430,15 +416,11 @@ void __cpuinit setup_local_APIC (void)
                value = APIC_DM_NMI;
        else
                value = APIC_DM_NMI | APIC_LVT_MASKED;
-       if (!APIC_INTEGRATED(ver))              /* 82489DX */
-               value |= APIC_LVT_LEVEL_TRIGGER;
        apic_write_around(APIC_LVT1, value);
 
-       if (APIC_INTEGRATED(ver) && !esr_disable) {             /* !82489DX */
+       {
                unsigned oldvalue;
                maxlvt = get_maxlvt();
-               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
-                       apic_write(APIC_ESR, 0);
                oldvalue = apic_read(APIC_ESR);
                value = ERROR_APIC_VECTOR;      // enables sending errors
                apic_write_around(APIC_LVTERR, value);
@@ -452,17 +434,6 @@ void __cpuinit setup_local_APIC (void)
                        apic_printk(APIC_VERBOSE,
                        "ESR value after enabling vector: %08x, after %08x\n",
                        oldvalue, value);
-       } else {
-               if (esr_disable)        
-                       /* 
-                        * Something untraceble is creating bad interrupts on 
-                        * secondary quads ... for the moment, just leave the
-                        * ESR disabled - we can't do anything useful with the
-                        * errors anyway - mbligh
-                        */
-                       apic_printk(APIC_DEBUG, "Leaving ESR disabled.\n");
-               else 
-                       apic_printk(APIC_DEBUG, "No ESR for 82489DX.\n");
        }
 
        nmi_watchdog_default();
@@ -650,8 +621,7 @@ void __init init_apic_mappings(void)
         * Fetch the APIC ID of the BSP in case we have a
         * default configuration (or the MP table is broken).
         */
-       if (boot_cpu_id == -1U)
-               boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+       boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
 
 #ifdef CONFIG_X86_IO_APIC
        {
@@ -693,8 +663,6 @@ static void __setup_APIC_LVTT(unsigned int clocks)
 
        ver = GET_APIC_VERSION(apic_read(APIC_LVR));
        lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
-       if (!APIC_INTEGRATED(ver))
-               lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);
        apic_write_around(APIC_LVTT, lvtt_value);
 
        /*
@@ -1081,7 +1049,7 @@ int __init APIC_init_uniprocessor (void)
 
        connect_bsp_APIC();
 
-       phys_cpu_present_map = physid_mask_of_physid(0);
+       phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id);
        apic_write_around(APIC_ID, boot_cpu_id);
 
        setup_local_APIC();
index 35b4c3fcbb37ff95dbd556b87da576db49cfe3ba..aaa6d383351798dca10eb8f7402a5c90a0ac1f95 100644 (file)
@@ -39,7 +39,6 @@ int main(void)
        ENTRY(kernelstack); 
        ENTRY(oldrsp); 
        ENTRY(pcurrent); 
-       ENTRY(irqrsp);
        ENTRY(irqcount);
        ENTRY(cpunumber);
        ENTRY(irqstackptr);
index d7fa4248501cc300ad4470fc38820b16a6a57c8c..535e04466079857a09d3f9b0c6649f15f36301e6 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
-#include <linux/irq.h>
 #include <linux/reboot.h>
 #include <linux/kexec.h>
 
index bb0ae18ec02b90efd04cbf7cce43f0490095fa88..eb7929eea7b33c4743b533a0d39bf8c22c42707c 100644 (file)
@@ -131,7 +131,7 @@ void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned lon
 
                if (ei->type != E820_RAM || 
                    ei->addr+ei->size <= start || 
-                   ei->addr > end)
+                   ei->addr >= end)
                        continue;
 
                addr = round_up(ei->addr, PAGE_SIZE);
index 9631c747c5e3750580cf06dea4b0e8e1324a757f..9cd968dd0f5a4bd3b9d4b83525f94ee5386fec14 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/tty.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#include <asm/fcntl.h>
 
 /* Simple VGA output */
 
@@ -158,6 +159,47 @@ static struct console early_serial_console = {
        .index =        -1,
 };
 
+/* Console interface to a host file on AMD's SimNow! */
+
+static int simnow_fd;
+
+enum {
+       MAGIC1 = 0xBACCD00A,
+       MAGIC2 = 0xCA110000,
+       XOPEN = 5,
+       XWRITE = 4,
+};
+
+static noinline long simnow(long cmd, long a, long b, long c)
+{
+       long ret;
+       asm volatile("cpuid" :
+                    "=a" (ret) :
+                    "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2));
+       return ret;
+}
+
+void __init simnow_init(char *str)
+{
+       char *fn = "klog";
+       if (*str == '=')
+               fn = ++str;
+       /* error ignored */
+       simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644);
+}
+
+static void simnow_write(struct console *con, const char *s, unsigned n)
+{
+       simnow(XWRITE, simnow_fd, (unsigned long)s, n);
+}
+
+static struct console simnow_console = {
+       .name =         "simnow",
+       .write =        simnow_write,
+       .flags =        CON_PRINTBUFFER,
+       .index =        -1,
+};
+
 /* Direct interface for emergencies */
 struct console *early_console = &early_vga_console;
 static int early_console_initialized = 0;
@@ -205,6 +247,10 @@ int __init setup_early_printk(char *opt)
                max_xpos = SCREEN_INFO.orig_video_cols;
                max_ypos = SCREEN_INFO.orig_video_lines;
                early_console = &early_vga_console; 
+       } else if (!strncmp(buf, "simnow", 6)) {
+               simnow_init(buf + 6);
+               early_console = &simnow_console;
+               keep_early = 1;
        }
        early_console_initialized = 1;
        register_console(early_console);       
index 3620508c8bd9b29e26bcf73892f8c4f88f8800bf..7937971d1853bd5187cfe615e24c4a5cf35689be 100644 (file)
        xorl %eax, %eax
        pushq %rax /* ss */
        CFI_ADJUST_CFA_OFFSET   8
+       /*CFI_REL_OFFSET        ss,0*/
        pushq %rax /* rsp */
        CFI_ADJUST_CFA_OFFSET   8
-       CFI_OFFSET      rip,0
+       CFI_REL_OFFSET  rsp,0
        pushq $(1<<9) /* eflags - interrupts on */
        CFI_ADJUST_CFA_OFFSET   8
+       /*CFI_REL_OFFSET        rflags,0*/
        pushq $__KERNEL_CS /* cs */
        CFI_ADJUST_CFA_OFFSET   8
+       /*CFI_REL_OFFSET        cs,0*/
        pushq \child_rip /* rip */
        CFI_ADJUST_CFA_OFFSET   8
-       CFI_OFFSET      rip,0
+       CFI_REL_OFFSET  rip,0
        pushq   %rax /* orig rax */
        CFI_ADJUST_CFA_OFFSET   8
        .endm
        CFI_ADJUST_CFA_OFFSET   -(6*8)
        .endm
 
-       .macro  CFI_DEFAULT_STACK
-       CFI_ADJUST_CFA_OFFSET  (SS)
-       CFI_OFFSET      r15,R15-SS
-       CFI_OFFSET      r14,R14-SS
-       CFI_OFFSET      r13,R13-SS
-       CFI_OFFSET      r12,R12-SS
-       CFI_OFFSET      rbp,RBP-SS
-       CFI_OFFSET      rbx,RBX-SS
-       CFI_OFFSET      r11,R11-SS
-       CFI_OFFSET      r10,R10-SS
-       CFI_OFFSET      r9,R9-SS
-       CFI_OFFSET      r8,R8-SS
-       CFI_OFFSET      rax,RAX-SS
-       CFI_OFFSET      rcx,RCX-SS
-       CFI_OFFSET      rdx,RDX-SS
-       CFI_OFFSET      rsi,RSI-SS
-       CFI_OFFSET      rdi,RDI-SS
-       CFI_OFFSET      rsp,RSP-SS
-       CFI_OFFSET      rip,RIP-SS
+       .macro  CFI_DEFAULT_STACK start=1
+       .if \start
+       CFI_STARTPROC   simple
+       CFI_DEF_CFA     rsp,SS+8
+       .else
+       CFI_DEF_CFA_OFFSET SS+8
+       .endif
+       CFI_REL_OFFSET  r15,R15
+       CFI_REL_OFFSET  r14,R14
+       CFI_REL_OFFSET  r13,R13
+       CFI_REL_OFFSET  r12,R12
+       CFI_REL_OFFSET  rbp,RBP
+       CFI_REL_OFFSET  rbx,RBX
+       CFI_REL_OFFSET  r11,R11
+       CFI_REL_OFFSET  r10,R10
+       CFI_REL_OFFSET  r9,R9
+       CFI_REL_OFFSET  r8,R8
+       CFI_REL_OFFSET  rax,RAX
+       CFI_REL_OFFSET  rcx,RCX
+       CFI_REL_OFFSET  rdx,RDX
+       CFI_REL_OFFSET  rsi,RSI
+       CFI_REL_OFFSET  rdi,RDI
+       CFI_REL_OFFSET  rip,RIP
+       /*CFI_REL_OFFSET        cs,CS*/
+       /*CFI_REL_OFFSET        rflags,EFLAGS*/
+       CFI_REL_OFFSET  rsp,RSP
+       /*CFI_REL_OFFSET        ss,SS*/
        .endm
 /*
  * A newly forked process directly context switches into this.
  */    
 /* rdi:        prev */ 
 ENTRY(ret_from_fork)
-       CFI_STARTPROC
        CFI_DEFAULT_STACK
        call schedule_tail
        GET_THREAD_INFO(%rcx)
@@ -172,16 +182,21 @@ rff_trace:
  */                                    
 
 ENTRY(system_call)
-       CFI_STARTPROC
+       CFI_STARTPROC   simple
+       CFI_DEF_CFA     rsp,0
+       CFI_REGISTER    rip,rcx
+       /*CFI_REGISTER  rflags,r11*/
        swapgs
        movq    %rsp,%gs:pda_oldrsp 
        movq    %gs:pda_kernelstack,%rsp
        sti                                     
        SAVE_ARGS 8,1
        movq  %rax,ORIG_RAX-ARGOFFSET(%rsp) 
-       movq  %rcx,RIP-ARGOFFSET(%rsp)  
+       movq  %rcx,RIP-ARGOFFSET(%rsp)
+       CFI_REL_OFFSET rip,RIP-ARGOFFSET
        GET_THREAD_INFO(%rcx)
        testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
+       CFI_REMEMBER_STATE
        jnz tracesys
        cmpq $__NR_syscall_max,%rax
        ja badsys
@@ -201,9 +216,12 @@ sysret_check:
        cli
        movl threadinfo_flags(%rcx),%edx
        andl %edi,%edx
+       CFI_REMEMBER_STATE
        jnz  sysret_careful 
        movq RIP-ARGOFFSET(%rsp),%rcx
+       CFI_REGISTER    rip,rcx
        RESTORE_ARGS 0,-ARG_SKIP,1
+       /*CFI_REGISTER  rflags,r11*/
        movq    %gs:pda_oldrsp,%rsp
        swapgs
        sysretq
@@ -211,12 +229,15 @@ sysret_check:
        /* Handle reschedules */
        /* edx: work, edi: workmask */  
 sysret_careful:
+       CFI_RESTORE_STATE
        bt $TIF_NEED_RESCHED,%edx
        jnc sysret_signal
        sti
        pushq %rdi
+       CFI_ADJUST_CFA_OFFSET 8
        call schedule
        popq  %rdi
+       CFI_ADJUST_CFA_OFFSET -8
        jmp sysret_check
 
        /* Handle a signal */ 
@@ -234,8 +255,13 @@ sysret_signal:
 1:     movl $_TIF_NEED_RESCHED,%edi
        jmp sysret_check
        
+badsys:
+       movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
+       jmp ret_from_sys_call
+
        /* Do syscall tracing */
 tracesys:                       
+       CFI_RESTORE_STATE
        SAVE_REST
        movq $-ENOSYS,RAX(%rsp)
        FIXUP_TOP_OF_STACK %rdi
@@ -254,16 +280,29 @@ tracesys:
        RESTORE_TOP_OF_STACK %rbx
        RESTORE_REST
        jmp ret_from_sys_call
+       CFI_ENDPROC
                
-badsys:
-       movq $-ENOSYS,RAX-ARGOFFSET(%rsp)       
-       jmp ret_from_sys_call
-
 /* 
  * Syscall return path ending with IRET.
  * Has correct top of stack, but partial stack frame.
  */    
-ENTRY(int_ret_from_sys_call)   
+ENTRY(int_ret_from_sys_call)
+       CFI_STARTPROC   simple
+       CFI_DEF_CFA     rsp,SS+8-ARGOFFSET
+       /*CFI_REL_OFFSET        ss,SS-ARGOFFSET*/
+       CFI_REL_OFFSET  rsp,RSP-ARGOFFSET
+       /*CFI_REL_OFFSET        rflags,EFLAGS-ARGOFFSET*/
+       /*CFI_REL_OFFSET        cs,CS-ARGOFFSET*/
+       CFI_REL_OFFSET  rip,RIP-ARGOFFSET
+       CFI_REL_OFFSET  rdx,RDX-ARGOFFSET
+       CFI_REL_OFFSET  rcx,RCX-ARGOFFSET
+       CFI_REL_OFFSET  rax,RAX-ARGOFFSET
+       CFI_REL_OFFSET  rdi,RDI-ARGOFFSET
+       CFI_REL_OFFSET  rsi,RSI-ARGOFFSET
+       CFI_REL_OFFSET  r8,R8-ARGOFFSET
+       CFI_REL_OFFSET  r9,R9-ARGOFFSET
+       CFI_REL_OFFSET  r10,R10-ARGOFFSET
+       CFI_REL_OFFSET  r11,R11-ARGOFFSET
        cli
        testl $3,CS-ARGOFFSET(%rsp)
        je retint_restore_args
@@ -284,8 +323,10 @@ int_careful:
        jnc  int_very_careful
        sti
        pushq %rdi
+       CFI_ADJUST_CFA_OFFSET 8
        call schedule
        popq %rdi
+       CFI_ADJUST_CFA_OFFSET -8
        cli
        jmp int_with_check
 
@@ -297,9 +338,11 @@ int_very_careful:
        testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
        jz int_signal
        pushq %rdi
+       CFI_ADJUST_CFA_OFFSET 8
        leaq 8(%rsp),%rdi       # &ptregs -> arg1       
        call syscall_trace_leave
        popq %rdi
+       CFI_ADJUST_CFA_OFFSET -8
        andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi
        cli
        jmp int_restore_rest
@@ -329,6 +372,8 @@ int_restore_rest:
        jmp     ptregscall_common
        .endm
 
+       CFI_STARTPROC
+
        PTREGSCALL stub_clone, sys_clone, %r8
        PTREGSCALL stub_fork, sys_fork, %rdi
        PTREGSCALL stub_vfork, sys_vfork, %rdi
@@ -337,40 +382,49 @@ int_restore_rest:
        PTREGSCALL stub_iopl, sys_iopl, %rsi
 
 ENTRY(ptregscall_common)
-       CFI_STARTPROC
        popq %r11
-       CFI_ADJUST_CFA_OFFSET   -8
+       CFI_ADJUST_CFA_OFFSET -8
+       CFI_REGISTER rip, r11
        SAVE_REST
        movq %r11, %r15
+       CFI_REGISTER rip, r15
        FIXUP_TOP_OF_STACK %r11
        call *%rax
        RESTORE_TOP_OF_STACK %r11
        movq %r15, %r11
+       CFI_REGISTER rip, r11
        RESTORE_REST
        pushq %r11
-       CFI_ADJUST_CFA_OFFSET   8
+       CFI_ADJUST_CFA_OFFSET 8
+       CFI_REL_OFFSET rip, 0
        ret
        CFI_ENDPROC
        
 ENTRY(stub_execve)
        CFI_STARTPROC
        popq %r11
-       CFI_ADJUST_CFA_OFFSET   -8
+       CFI_ADJUST_CFA_OFFSET -8
+       CFI_REGISTER rip, r11
        SAVE_REST
        movq %r11, %r15
+       CFI_REGISTER rip, r15
        FIXUP_TOP_OF_STACK %r11
        call sys_execve
        GET_THREAD_INFO(%rcx)
        bt $TIF_IA32,threadinfo_flags(%rcx)
+       CFI_REMEMBER_STATE
        jc exec_32bit
        RESTORE_TOP_OF_STACK %r11
        movq %r15, %r11
+       CFI_REGISTER rip, r11
        RESTORE_REST
-       push %r11
+       pushq %r11
+       CFI_ADJUST_CFA_OFFSET 8
+       CFI_REL_OFFSET rip, 0
        ret
 
 exec_32bit:
-       CFI_ADJUST_CFA_OFFSET   REST_SKIP
+       CFI_RESTORE_STATE
        movq %rax,RAX(%rsp)
        RESTORE_REST
        jmp int_ret_from_sys_call
@@ -382,7 +436,8 @@ exec_32bit:
  */                
 ENTRY(stub_rt_sigreturn)
        CFI_STARTPROC
-       addq $8, %rsp           
+       addq $8, %rsp
+       CFI_ADJUST_CFA_OFFSET   -8
        SAVE_REST
        movq %rsp,%rdi
        FIXUP_TOP_OF_STACK %r11
@@ -392,6 +447,25 @@ ENTRY(stub_rt_sigreturn)
        jmp int_ret_from_sys_call
        CFI_ENDPROC
 
+/*
+ * initial frame state for interrupts and exceptions
+ */
+       .macro _frame ref
+       CFI_STARTPROC simple
+       CFI_DEF_CFA rsp,SS+8-\ref
+       /*CFI_REL_OFFSET ss,SS-\ref*/
+       CFI_REL_OFFSET rsp,RSP-\ref
+       /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/
+       /*CFI_REL_OFFSET cs,CS-\ref*/
+       CFI_REL_OFFSET rip,RIP-\ref
+       .endm
+
+/* initial frame state for interrupts (and exceptions without error code) */
+#define INTR_FRAME _frame RIP
+/* initial frame state for exceptions with error code (and interrupts with
+   vector already pushed) */
+#define XCPT_FRAME _frame ORIG_RAX
+
 /* 
  * Interrupt entry/exit.
  *
@@ -402,10 +476,6 @@ ENTRY(stub_rt_sigreturn)
 
 /* 0(%rsp): interrupt number */ 
        .macro interrupt func
-       CFI_STARTPROC   simple
-       CFI_DEF_CFA     rsp,(SS-RDI)
-       CFI_REL_OFFSET  rsp,(RSP-ORIG_RAX)
-       CFI_REL_OFFSET  rip,(RIP-ORIG_RAX)
        cld
 #ifdef CONFIG_DEBUG_INFO
        SAVE_ALL        
@@ -425,23 +495,27 @@ ENTRY(stub_rt_sigreturn)
        swapgs  
 1:     incl    %gs:pda_irqcount        # RED-PEN should check preempt count
        movq %gs:pda_irqstackptr,%rax
-       cmoveq %rax,%rsp                                                        
+       cmoveq %rax,%rsp /*todo This needs CFI annotation! */
        pushq %rdi                      # save old stack        
+       CFI_ADJUST_CFA_OFFSET   8
        call \func
        .endm
 
 ENTRY(common_interrupt)
+       XCPT_FRAME
        interrupt do_IRQ
        /* 0(%rsp): oldrsp-ARGOFFSET */
-ret_from_intr:         
+ret_from_intr:
        popq  %rdi
+       CFI_ADJUST_CFA_OFFSET   -8
        cli     
        decl %gs:pda_irqcount
 #ifdef CONFIG_DEBUG_INFO
        movq RBP(%rdi),%rbp
+       CFI_DEF_CFA_REGISTER    rsp
 #endif
-       leaq ARGOFFSET(%rdi),%rsp
-exit_intr:             
+       leaq ARGOFFSET(%rdi),%rsp /*todo This needs CFI annotation! */
+exit_intr:
        GET_THREAD_INFO(%rcx)
        testl $3,CS-ARGOFFSET(%rsp)
        je retint_kernel
@@ -453,9 +527,10 @@ exit_intr:
         */             
 retint_with_reschedule:
        movl $_TIF_WORK_MASK,%edi
-retint_check:                  
+retint_check:
        movl threadinfo_flags(%rcx),%edx
        andl %edi,%edx
+       CFI_REMEMBER_STATE
        jnz  retint_careful
 retint_swapgs:         
        swapgs 
@@ -476,14 +551,17 @@ bad_iret:
        jmp do_exit                     
        .previous       
        
-       /* edi: workmask, edx: work */  
+       /* edi: workmask, edx: work */
 retint_careful:
+       CFI_RESTORE_STATE
        bt    $TIF_NEED_RESCHED,%edx
        jnc   retint_signal
        sti
        pushq %rdi
+       CFI_ADJUST_CFA_OFFSET   8
        call  schedule
        popq %rdi               
+       CFI_ADJUST_CFA_OFFSET   -8
        GET_THREAD_INFO(%rcx)
        cli
        jmp retint_check
@@ -523,7 +601,9 @@ retint_kernel:
  * APIC interrupts.
  */            
        .macro apicinterrupt num,func
+       INTR_FRAME
        pushq $\num-256
+       CFI_ADJUST_CFA_OFFSET 8
        interrupt \func
        jmp ret_from_intr
        CFI_ENDPROC
@@ -536,8 +616,19 @@ ENTRY(thermal_interrupt)
 ENTRY(reschedule_interrupt)
        apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
 
-ENTRY(invalidate_interrupt)
-       apicinterrupt INVALIDATE_TLB_VECTOR,smp_invalidate_interrupt
+       .macro INVALIDATE_ENTRY num
+ENTRY(invalidate_interrupt\num)
+       apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt 
+       .endm
+
+       INVALIDATE_ENTRY 0
+       INVALIDATE_ENTRY 1
+       INVALIDATE_ENTRY 2
+       INVALIDATE_ENTRY 3
+       INVALIDATE_ENTRY 4
+       INVALIDATE_ENTRY 5
+       INVALIDATE_ENTRY 6
+       INVALIDATE_ENTRY 7
 
 ENTRY(call_function_interrupt)
        apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
@@ -558,16 +649,23 @@ ENTRY(spurious_interrupt)
  * Exception entry points.
  */            
        .macro zeroentry sym
+       INTR_FRAME
        pushq $0        /* push error code/oldrax */ 
+       CFI_ADJUST_CFA_OFFSET 8
        pushq %rax      /* push real oldrax to the rdi slot */ 
+       CFI_ADJUST_CFA_OFFSET 8
        leaq  \sym(%rip),%rax
        jmp error_entry
+       CFI_ENDPROC
        .endm   
 
        .macro errorentry sym
+       XCPT_FRAME
        pushq %rax
+       CFI_ADJUST_CFA_OFFSET 8
        leaq  \sym(%rip),%rax
        jmp error_entry
+       CFI_ENDPROC
        .endm
 
        /* error code is on the stack already */
@@ -594,10 +692,7 @@ ENTRY(spurious_interrupt)
  * and the exception handler in %rax.  
  */                                            
 ENTRY(error_entry)
-       CFI_STARTPROC   simple
-       CFI_DEF_CFA     rsp,(SS-RDI)
-       CFI_REL_OFFSET  rsp,(RSP-RDI)
-       CFI_REL_OFFSET  rip,(RIP-RDI)
+       _frame RDI
        /* rdi slot contains rax, oldrax contains error code */
        cld     
        subq  $14*8,%rsp
@@ -679,7 +774,9 @@ error_kernelspace:
        /* Reload gs selector with exception handling */
        /* edi:  new selector */ 
 ENTRY(load_gs_index)
+       CFI_STARTPROC
        pushf
+       CFI_ADJUST_CFA_OFFSET 8
        cli
         swapgs
 gs_change:     
@@ -687,7 +784,9 @@ gs_change:
 2:     mfence          /* workaround */
        swapgs
         popf
+       CFI_ADJUST_CFA_OFFSET -8
         ret
+       CFI_ENDPROC
        
         .section __ex_table,"a"
         .align 8
@@ -799,7 +898,7 @@ ENTRY(device_not_available)
 
        /* runs on exception stack */
 KPROBE_ENTRY(debug)
-       CFI_STARTPROC
+       INTR_FRAME
        pushq $0
        CFI_ADJUST_CFA_OFFSET 8         
        paranoidentry do_debug
@@ -809,9 +908,9 @@ KPROBE_ENTRY(debug)
 
        /* runs on exception stack */   
 ENTRY(nmi)
-       CFI_STARTPROC
+       INTR_FRAME
        pushq $-1
-       CFI_ADJUST_CFA_OFFSET 8         
+       CFI_ADJUST_CFA_OFFSET 8
        paranoidentry do_nmi
        /*
         * "Paranoid" exit path from exception stack.
@@ -877,7 +976,7 @@ ENTRY(reserved)
 
        /* runs on exception stack */
 ENTRY(double_fault)
-       CFI_STARTPROC
+       XCPT_FRAME
        paranoidentry do_double_fault
        jmp paranoid_exit
        CFI_ENDPROC
@@ -890,7 +989,7 @@ ENTRY(segment_not_present)
 
        /* runs on exception stack */
 ENTRY(stack_segment)
-       CFI_STARTPROC
+       XCPT_FRAME
        paranoidentry do_stack_segment
        jmp paranoid_exit
        CFI_ENDPROC
@@ -911,7 +1010,7 @@ ENTRY(spurious_interrupt_bug)
 #ifdef CONFIG_X86_MCE
        /* runs on exception stack */
 ENTRY(machine_check)
-       CFI_STARTPROC
+       INTR_FRAME
        pushq $0
        CFI_ADJUST_CFA_OFFSET 8 
        paranoidentry do_machine_check
@@ -923,14 +1022,19 @@ ENTRY(call_debug)
        zeroentry do_call_debug
 
 ENTRY(call_softirq)
+       CFI_STARTPROC
        movq %gs:pda_irqstackptr,%rax
        pushq %r15
+       CFI_ADJUST_CFA_OFFSET 8
        movq %rsp,%r15
+       CFI_DEF_CFA_REGISTER    r15
        incl %gs:pda_irqcount
        cmove %rax,%rsp
        call __do_softirq
        movq %r15,%rsp
+       CFI_DEF_CFA_REGISTER    rsp
        decl %gs:pda_irqcount
        popq %r15
+       CFI_ADJUST_CFA_OFFSET -8
        ret
-
+       CFI_ENDPROC
index b1c144f73149854da5e9bb277e4309e281b60ba3..7a64ea181788c62e3c6a8e9e07a378ffa0a23ac0 100644 (file)
@@ -45,7 +45,7 @@ void __init clustered_apic_check(void)
        u8 clusters, max_cluster;
        u8 id;
        u8 cluster_cnt[NUM_APIC_CLUSTERS];
-       int num_cpus = 0;
+       int max_apic = 0;
 
 #if defined(CONFIG_ACPI)
        /*
@@ -64,14 +64,15 @@ void __init clustered_apic_check(void)
                id = bios_cpu_apicid[i];
                if (id == BAD_APICID)
                        continue;
-               num_cpus++;
+               if (id > max_apic)
+                       max_apic = id;
                cluster_cnt[APIC_CLUSTERID(id)]++;
        }
 
        /* Don't use clustered mode on AMD platforms. */
        if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
                genapic = &apic_physflat;
-#ifndef CONFIG_CPU_HOTPLUG
+#ifndef CONFIG_HOTPLUG_CPU
                /* In the CPU hotplug case we cannot use broadcast mode
                   because that opens a race when a CPU is removed.
                   Stay at physflat mode in this case.
@@ -79,7 +80,7 @@ void __init clustered_apic_check(void)
                   we have ACPI platform support for CPU hotplug
                   we should detect hotplug capablity from ACPI tables and
                   only do this when really needed. -AK */
-               if (num_cpus <= 8)
+               if (max_apic <= 8)
                        genapic = &apic_flat;
 #endif
                goto print;
@@ -103,9 +104,14 @@ void __init clustered_apic_check(void)
         * (We don't use lowest priority delivery + HW APIC IRQ steering, so
         * can ignore the clustered logical case and go straight to physical.)
         */
-       if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster)
+       if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) {
+#ifdef CONFIG_HOTPLUG_CPU
+               /* Don't use APIC shortcuts in CPU hotplug to avoid races */
+               genapic = &apic_physflat;
+#else
                genapic = &apic_flat;
-       else
+#endif
+       } else
                genapic = &apic_cluster;
 
 print:
index f6523dd1bc0938fb6f21ff811af0b8292d77ca46..a472d62f899a87a8037a737663c09c3f507bbd77 100644 (file)
@@ -51,10 +51,10 @@ static void cluster_init_apic_ldr(void)
                count = 3;
        id = my_cluster | (1UL << count);
        x86_cpu_to_log_apicid[smp_processor_id()] = id;
-       apic_write_around(APIC_DFR, APIC_DFR_CLUSTER);
+       apic_write(APIC_DFR, APIC_DFR_CLUSTER);
        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
        val |= SET_APIC_LOGICAL_ID(id);
-       apic_write_around(APIC_LDR, val);
+       apic_write(APIC_LDR, val);
 }
 
 /* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */
index 6d57da96bf8c7e6ad655ffb78fd635727e65bb67..9da3edb799ea543042776664db789a59b7418163 100644 (file)
@@ -38,10 +38,10 @@ static void flat_init_apic_ldr(void)
        num = smp_processor_id();
        id = 1UL << num;
        x86_cpu_to_log_apicid[num] = id;
-       apic_write_around(APIC_DFR, APIC_DFR_FLAT);
+       apic_write(APIC_DFR, APIC_DFR_FLAT);
        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
        val |= SET_APIC_LOGICAL_ID(id);
-       apic_write_around(APIC_LDR, val);
+       apic_write(APIC_LDR, val);
 }
 
 static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
@@ -62,7 +62,7 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
         * prepare target chip field
         */
        cfg = __prepare_ICR2(mask);
-       apic_write_around(APIC_ICR2, cfg);
+       apic_write(APIC_ICR2, cfg);
 
        /*
         * program the ICR
@@ -72,7 +72,7 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
        /*
         * Send the IPI. The write to APIC_ICR fires this off.
         */
-       apic_write_around(APIC_ICR, cfg);
+       apic_write(APIC_ICR, cfg);
        local_irq_restore(flags);
 }
 
@@ -177,9 +177,9 @@ static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask)
 
 struct genapic apic_physflat =  {
        .name = "physical flat",
-       .int_delivery_mode = dest_LowestPrio,
+       .int_delivery_mode = dest_Fixed,
        .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
-       .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_LOWEST,
+       .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_FIXED,
        .target_cpus = physflat_target_cpus,
        .apic_id_registered = flat_apic_id_registered,
        .init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/
index 98ff5eb32b9af5db22035c0da04cfe2bf9764367..4592bf21fcafa32e34d580a113255e6f61d1b754 100644 (file)
@@ -270,7 +270,7 @@ ENTRY(level3_kernel_pgt)
 .org 0x4000
 ENTRY(level2_ident_pgt)
        /* 40MB for bootup.     */
-       .quad   0x0000000000000283
+       .quad   0x0000000000000183
        .quad   0x0000000000200183
        .quad   0x0000000000400183
        .quad   0x0000000000600183
index a891690951299912495b8da4915210e73b524988..b2a238b5a17ed36cc7a071be01f62231d80cc5c0 100644 (file)
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/irq.h>
 #include <asm/hw_irq.h>
 #include <asm/pgtable.h>
 #include <asm/delay.h>
 #include <asm/desc.h>
 #include <asm/apic.h>
 
-#include <linux/irq.h>
-
 /*
  * Common place to define all x86 IRQ vectors
  *
@@ -486,7 +483,14 @@ void spurious_interrupt(void);
 void error_interrupt(void);
 void reschedule_interrupt(void);
 void call_function_interrupt(void);
-void invalidate_interrupt(void);
+void invalidate_interrupt0(void);
+void invalidate_interrupt1(void);
+void invalidate_interrupt2(void);
+void invalidate_interrupt3(void);
+void invalidate_interrupt4(void);
+void invalidate_interrupt5(void);
+void invalidate_interrupt6(void);
+void invalidate_interrupt7(void);
 void thermal_interrupt(void);
 void i8254_timer_resume(void);
 
@@ -562,8 +566,15 @@ void __init init_IRQ(void)
         */
        set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
 
-       /* IPI for invalidation */
-       set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
+       /* IPIs for invalidation */
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6);
+       set_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7);
 
        /* IPI for generic function call */
        set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
index c4dc9149115741cf4b48c385adf8a49ec91979a8..e0ba5c1043fd23f71e48e236aebcb18b41d3934a 100644 (file)
@@ -44,6 +44,6 @@ EXPORT_SYMBOL(init_task);
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */ 
-DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp;
+DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS;
 
 #define ALIGN_TO_4K __attribute__((section(".data.init_task")))
index 5f1529be1237495ba9a81757ec91c89c684dc1ef..522944a000ad9c8755ad529ba0c74bff3353c897 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #include <linux/mm.h>
-#include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -45,6 +44,8 @@ int sis_apic_bug; /* not actually supported, dummy for compile */
 
 static int no_timer_check;
 
+int disable_timer_pin_1 __initdata;
+
 static DEFINE_SPINLOCK(ioapic_lock);
 
 /*
@@ -298,6 +299,15 @@ void __init check_ioapic(void)
 #endif
                                        /* RED-PEN skip them on mptables too? */
                                        return;
+                               case PCI_VENDOR_ID_ATI:
+                                       /* All timer interrupts on atiixp
+                                          are doubled. Disable one. */
+                                       if (disable_timer_pin_1 == 0) {
+                                               disable_timer_pin_1 = 1;
+                                               printk(KERN_INFO
+               "ATI board detected. Disabling timer pin 1.\n");
+                                       }
+                                       return;
                                } 
 
                                /* No multi-function device? */
@@ -1022,13 +1032,11 @@ void __apicdebuginit print_local_APIC(void * dummy)
        v = apic_read(APIC_TASKPRI);
        printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
 
-       if (APIC_INTEGRATED(ver)) {                     /* !82489DX */
-               v = apic_read(APIC_ARBPRI);
-               printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
-                       v & APIC_ARBPRI_MASK);
-               v = apic_read(APIC_PROCPRI);
-               printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
-       }
+       v = apic_read(APIC_ARBPRI);
+       printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
+               v & APIC_ARBPRI_MASK);
+       v = apic_read(APIC_PROCPRI);
+       printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
 
        v = apic_read(APIC_EOI);
        printk(KERN_DEBUG "... APIC EOI: %08x\n", v);
@@ -1048,12 +1056,8 @@ void __apicdebuginit print_local_APIC(void * dummy)
        printk(KERN_DEBUG "... APIC IRR field:\n");
        print_APIC_bitfield(APIC_IRR);
 
-       if (APIC_INTEGRATED(ver)) {             /* !82489DX */
-               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
-                       apic_write(APIC_ESR, 0);
-               v = apic_read(APIC_ESR);
-               printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
-       }
+       v = apic_read(APIC_ESR);
+       printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
 
        v = apic_read(APIC_ICR);
        printk(KERN_DEBUG "... APIC ICR: %08x\n", v);
@@ -1665,6 +1669,8 @@ static inline void check_timer(void)
                                setup_nmi();
                                enable_8259A_irq(0);
                        }
+                       if (disable_timer_pin_1 > 0)
+                               clear_IO_APIC_pin(0, pin1);
                        return;
                }
                clear_IO_APIC_pin(0, pin1);
index 849a20aec7ca05e4cb5067f44010e2ca830f34e6..d6a04a8320a38d475a3780488b856ecba23fe66b 100644 (file)
@@ -99,7 +99,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
        unsigned irq = regs->orig_rax & 0xff;
 
        irq_enter();
-       BUG_ON(irq > 256);
 
        __do_IRQ(irq, regs);
        irq_exit();
index 8aa56736cde3805fe8b38b84733e176914ae14be..08203b07f4bd6d6c5aa26ddc9cedda58a29fda7f 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/ctype.h>
 #include <asm/processor.h> 
 #include <asm/msr.h>
 #include <asm/mce.h>
@@ -56,15 +57,19 @@ void mce_log(struct mce *mce)
        smp_wmb();
        for (;;) {
                entry = rcu_dereference(mcelog.next);
-               /* When the buffer fills up discard new entries. Assume 
-                  that the earlier errors are the more interesting. */
-               if (entry >= MCE_LOG_LEN) {
-                       set_bit(MCE_OVERFLOW, &mcelog.flags);
-                       return;
+               for (;;) {
+                       /* When the buffer fills up discard new entries. Assume
+                          that the earlier errors are the more interesting. */
+                       if (entry >= MCE_LOG_LEN) {
+                               set_bit(MCE_OVERFLOW, &mcelog.flags);
+                               return;
+                       }
+                       /* Old left over entry. Skip. */
+                       if (mcelog.entry[entry].finished) {
+                               entry++;
+                               continue;
+                       }
                }
-               /* Old left over entry. Skip. */
-               if (mcelog.entry[entry].finished)
-                       continue;
                smp_rmb();
                next = entry + 1;
                if (cmpxchg(&mcelog.next, entry, next) == entry)
@@ -212,7 +217,7 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                        panicm_found = 1;
                }
 
-               tainted |= TAINT_MACHINE_CHECK;
+               add_taint(TAINT_MACHINE_CHECK);
        }
 
        /* Never do anything final in the polling timer */
@@ -404,9 +409,15 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff
        }
 
        err = 0;
-       for (i = 0; i < next; i++) {
-               if (!mcelog.entry[i].finished)
-                       continue;
+       for (i = 0; i < next; i++) {            
+               unsigned long start = jiffies;
+               while (!mcelog.entry[i].finished) {
+                       if (!time_before(jiffies, start + 2)) {
+                               memset(mcelog.entry + i,0, sizeof(struct mce));
+                               continue;
+                       }
+                       cpu_relax();
+               }
                smp_rmb();
                err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce));
                buf += sizeof(struct mce); 
@@ -479,6 +490,7 @@ static int __init mcheck_disable(char *str)
 
 /* mce=off disables machine check. Note you can reenable it later
    using sysfs.
+   mce=TOLERANCELEVEL (number, see above)
    mce=bootlog Log MCEs from before booting. Disabled by default to work
    around buggy BIOS that leave bogus MCEs.  */
 static int __init mcheck_enable(char *str)
@@ -489,6 +501,8 @@ static int __init mcheck_enable(char *str)
                mce_dont_init = 1;
        else if (!strcmp(str, "bootlog"))
                mce_bootlog = 1;
+       else if (isdigit(str[0]))
+               get_option(&str, &tolerant);
        else
                printk("mce= argument %s ignored. Please use /sys", str); 
        return 0;
@@ -501,10 +515,12 @@ __setup("mce", mcheck_enable);
  * Sysfs support
  */ 
 
-/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */
+/* On resume clear all MCE state. Don't want to see leftovers from the BIOS.
+   Only one CPU is active at this time, the others get readded later using
+   CPU hotplug. */
 static int mce_resume(struct sys_device *dev)
 {
-       on_each_cpu(mce_init, NULL, 1, 1);
+       mce_init(NULL);
        return 0;
 }
 
index 8d8ed6ae1d0c8d880f96558b7a8f865a80ea2ac5..f16d38d09dafeadcafc6d1e6413617c96eeeb8d4 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/mm.h>
-#include <linux/irq.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/config.h>
@@ -46,8 +45,6 @@ int acpi_found_madt;
 int apic_version [MAX_APICS];
 unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
-unsigned char pci_bus_to_node [256];
-EXPORT_SYMBOL(pci_bus_to_node);
 
 static int mp_current_pci_id = 0;
 /* I/O APIC entries */
@@ -705,7 +702,7 @@ void __init mp_register_lapic (
 
        processor.mpc_type = MP_PROCESSOR;
        processor.mpc_apicid = id;
-       processor.mpc_apicver = 0x10; /* TBD: lapic version */
+       processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR));
        processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0);
        processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0);
        processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | 
diff --git a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c
deleted file mode 100644 (file)
index 598953a..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *   
- *   Copyright 2000 H. Peter Anvin - 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, Inc., 675 Mass Ave, Cambridge MA 02139,
- *   USA; either version 2 of the License, or (at your option) any later
- *   version; incorporated herein by reference.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * msr.c
- *
- * x86 MSR access device
- *
- * This device is accessed by lseek() to the appropriate register number
- * and then read/write in chunks of 8 bytes.  A larger size means multiple
- * reads or writes of the same register.
- *
- * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
- * an SMP box will direct the access to CPU %d.
- */
-
-#include <linux/module.h>
-#include <linux/config.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-
-#include <asm/processor.h>
-#include <asm/msr.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-/* Note: "err" is handled in a funny way below.  Otherwise one version
-   of gcc or another breaks. */
-
-static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
-{
-       int err;
-
-       asm volatile ("1:       wrmsr\n"
-                     "2:\n"
-                     ".section .fixup,\"ax\"\n"
-                     "3:       movl %4,%0\n"
-                     " jmp 2b\n"
-                     ".previous\n"
-                     ".section __ex_table,\"a\"\n"
-                     " .align 8\n" "   .quad 1b,3b\n" ".previous":"=&bDS" (err)
-                     :"a"(eax), "d"(edx), "c"(reg), "i"(-EIO), "0"(0));
-
-       return err;
-}
-
-static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
-{
-       int err;
-
-       asm volatile ("1:       rdmsr\n"
-                     "2:\n"
-                     ".section .fixup,\"ax\"\n"
-                     "3:       movl %4,%0\n"
-                     " jmp 2b\n"
-                     ".previous\n"
-                     ".section __ex_table,\"a\"\n"
-                     " .align 8\n"
-                     " .quad 1b,3b\n"
-                     ".previous":"=&bDS" (err), "=a"(*eax), "=d"(*edx)
-                     :"c"(reg), "i"(-EIO), "0"(0));
-
-       return err;
-}
-
-#ifdef CONFIG_SMP
-
-struct msr_command {
-       int cpu;
-       int err;
-       u32 reg;
-       u32 data[2];
-};
-
-static void msr_smp_wrmsr(void *cmd_block)
-{
-       struct msr_command *cmd = (struct msr_command *)cmd_block;
-
-       if (cmd->cpu == smp_processor_id())
-               cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]);
-}
-
-static void msr_smp_rdmsr(void *cmd_block)
-{
-       struct msr_command *cmd = (struct msr_command *)cmd_block;
-
-       if (cmd->cpu == smp_processor_id())
-               cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
-}
-
-static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
-{
-       struct msr_command cmd;
-       int ret;
-
-       preempt_disable();
-       if (cpu == smp_processor_id()) {
-               ret = wrmsr_eio(reg, eax, edx);
-       } else {
-               cmd.cpu = cpu;
-               cmd.reg = reg;
-               cmd.data[0] = eax;
-               cmd.data[1] = edx;
-
-               smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
-               ret = cmd.err;
-       }
-       preempt_enable();
-       return ret;
-}
-
-static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx)
-{
-       struct msr_command cmd;
-       int ret;
-
-       preempt_disable();
-       if (cpu == smp_processor_id()) {
-               ret = rdmsr_eio(reg, eax, edx);
-       } else {
-               cmd.cpu = cpu;
-               cmd.reg = reg;
-
-               smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
-
-               *eax = cmd.data[0];
-               *edx = cmd.data[1];
-
-               ret = cmd.err;
-       }
-       preempt_enable();
-       return ret;
-}
-
-#else                          /* ! CONFIG_SMP */
-
-static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
-{
-       return wrmsr_eio(reg, eax, edx);
-}
-
-static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
-{
-       return rdmsr_eio(reg, eax, edx);
-}
-
-#endif                         /* ! CONFIG_SMP */
-
-static loff_t msr_seek(struct file *file, loff_t offset, int orig)
-{
-       loff_t ret = -EINVAL;
-
-       lock_kernel();
-       switch (orig) {
-       case 0:
-               file->f_pos = offset;
-               ret = file->f_pos;
-               break;
-       case 1:
-               file->f_pos += offset;
-               ret = file->f_pos;
-       }
-       unlock_kernel();
-       return ret;
-}
-
-static ssize_t msr_read(struct file *file, char __user * buf,
-                       size_t count, loff_t * ppos)
-{
-       u32 __user *tmp = (u32 __user *) buf;
-       u32 data[2];
-       size_t rv;
-       u32 reg = *ppos;
-       int cpu = iminor(file->f_dentry->d_inode);
-       int err;
-
-       if (count % 8)
-               return -EINVAL; /* Invalid chunk size */
-
-       for (rv = 0; count; count -= 8) {
-               err = do_rdmsr(cpu, reg, &data[0], &data[1]);
-               if (err)
-                       return err;
-               if (copy_to_user(tmp, &data, 8))
-                       return -EFAULT;
-               tmp += 2;
-       }
-
-       return ((char __user *)tmp) - buf;
-}
-
-static ssize_t msr_write(struct file *file, const char __user *buf,
-                        size_t count, loff_t *ppos)
-{
-       const u32 __user *tmp = (const u32 __user *)buf;
-       u32 data[2];
-       size_t rv;
-       u32 reg = *ppos;
-       int cpu = iminor(file->f_dentry->d_inode);
-       int err;
-
-       if (count % 8)
-               return -EINVAL; /* Invalid chunk size */
-
-       for (rv = 0; count; count -= 8) {
-               if (copy_from_user(&data, tmp, 8))
-                       return -EFAULT;
-               err = do_wrmsr(cpu, reg, data[0], data[1]);
-               if (err)
-                       return err;
-               tmp += 2;
-       }
-
-       return ((char __user *)tmp) - buf;
-}
-
-static int msr_open(struct inode *inode, struct file *file)
-{
-       unsigned int cpu = iminor(file->f_dentry->d_inode);
-       struct cpuinfo_x86 *c = &(cpu_data)[cpu];
-
-       if (cpu >= NR_CPUS || !cpu_online(cpu))
-               return -ENXIO;  /* No such CPU */
-       if (!cpu_has(c, X86_FEATURE_MSR))
-               return -EIO;    /* MSR not supported */
-
-       return 0;
-}
-
-/*
- * File operations we support
- */
-static struct file_operations msr_fops = {
-       .owner = THIS_MODULE,
-       .llseek = msr_seek,
-       .read = msr_read,
-       .write = msr_write,
-       .open = msr_open,
-};
-
-static int __init msr_init(void)
-{
-       if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) {
-               printk(KERN_ERR "msr: unable to get major %d for msr\n",
-                      MSR_MAJOR);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static void __exit msr_exit(void)
-{
-       unregister_chrdev(MSR_MAJOR, "cpu/msr");
-}
-
-module_init(msr_init);
-module_exit(msr_exit)
-
-MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
-MODULE_DESCRIPTION("x86 generic MSR driver");
-MODULE_LICENSE("GPL");
index caf164959e197d25f100b54c1195ef19257e9c72..39d445e16f2254441b29dcfb6a5a37de5439ca8a 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/config.h>
 #include <linux/mm.h>
-#include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/bootmem.h>
 #include <linux/smp_lock.h>
@@ -367,7 +366,7 @@ static void setup_k7_watchdog(void)
                | K7_NMI_EVENT;
 
        wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
-       wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
+       wrmsrl(MSR_K7_PERFCTR0, -((u64)cpu_khz * 1000 / nmi_hz));
        apic_write(APIC_LVTPC, APIC_DM_NMI);
        evntsel |= K7_EVNTSEL_ENABLE;
        wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
@@ -408,8 +407,8 @@ static int setup_p4_watchdog(void)
 
        wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
        wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
-       Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
-       wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
+       Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz * 1000UL / nmi_hz));
+       wrmsrl(MSR_P4_IQ_COUNTER0, -((u64)cpu_khz * 1000 / nmi_hz));
        apic_write(APIC_LVTPC, APIC_DM_NMI);
        wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
        return 1;
@@ -488,8 +487,8 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
                                                        == NOTIFY_STOP) {
                                local_set(&__get_cpu_var(alert_counter), 0);
                                return;
-                       } 
-                       die_nmi("NMI Watchdog detected LOCKUP on CPU%d", regs);
+                       }
+                       die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs);
                }
        } else {
                __get_cpu_var(last_irq_sum) = sum;
@@ -507,7 +506,7 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
                        wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
                        apic_write(APIC_LVTPC, APIC_DM_NMI);
                }
-               wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+               wrmsrl(nmi_perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
        }
 }
 
index 57f35c68aa34d0eb4255a919e9bca929622feed1..cf0a0315d586a15bc17dcd2de072956a00dc0d2e 100644 (file)
@@ -191,11 +191,9 @@ static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order)
 {
        struct page *page;
        int node;
-       if (dev->bus == &pci_bus_type) {
-               cpumask_t mask;
-               mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
-               node = cpu_to_node(first_cpu(mask));
-       } else
+       if (dev->bus == &pci_bus_type)
+               node = pcibus_to_node(to_pci_dev(dev)->bus);
+       else
                node = numa_node_id();
        page = alloc_pages_node(node, gfp, order);
        return page ? page_address(page) : NULL;
index 8661f82ac70b409d96a70b31b84ad87c485fbd30..b5a89c0bdf5914851fe32710b0b808587dfb6c32 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/irq.h>
 #include <linux/ptrace.h>
 #include <linux/utsname.h>
 #include <linux/random.h>
@@ -123,6 +122,7 @@ static void poll_idle (void)
                        : :
                        "i" (_TIF_NEED_RESCHED), 
                        "m" (current_thread_info()->flags));
+               clear_thread_flag(TIF_POLLING_NRFLAG);
        } else {
                set_need_resched();
        }
@@ -271,8 +271,11 @@ void __show_regs(struct pt_regs * regs)
 
        printk("\n");
        print_modules();
-       printk("Pid: %d, comm: %.20s %s %s\n", 
-              current->pid, current->comm, print_tainted(), system_utsname.release);
+       printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+               current->pid, current->comm, print_tainted(),
+               system_utsname.release,
+               (int)strcspn(system_utsname.version, " "),
+               system_utsname.version);
        printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
        printk_address(regs->rip); 
        printk("\nRSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
@@ -482,33 +485,6 @@ out:
        return err;
 }
 
-/*
- * This function selects if the context switch from prev to next
- * has to tweak the TSC disable bit in the cr4.
- */
-static inline void disable_tsc(struct task_struct *prev_p,
-                              struct task_struct *next_p)
-{
-       struct thread_info *prev, *next;
-
-       /*
-        * gcc should eliminate the ->thread_info dereference if
-        * has_secure_computing returns 0 at compile time (SECCOMP=n).
-        */
-       prev = prev_p->thread_info;
-       next = next_p->thread_info;
-
-       if (has_secure_computing(prev) || has_secure_computing(next)) {
-               /* slow path here */
-               if (has_secure_computing(prev) &&
-                   !has_secure_computing(next)) {
-                       write_cr4(read_cr4() & ~X86_CR4_TSD);
-               } else if (!has_secure_computing(prev) &&
-                          has_secure_computing(next))
-                       write_cr4(read_cr4() | X86_CR4_TSD);
-       }
-}
-
 /*
  * This special macro can be used to load a debugging register
  */
@@ -627,8 +603,6 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *
                }
        }
 
-       disable_tsc(prev_p, next_p);
-
        return prev_p;
 }
 
index 9aec524be3ebbbb653bcd32b42e44ea51324f442..351d8d64c2fbf45cff433c18fe38cba1156f2b7f 100644 (file)
@@ -336,6 +336,11 @@ static __init void parse_cmdline_early (char ** cmdline_p)
 #endif
 #endif
 
+               if (!memcmp(from, "disable_timer_pin_1", 19))
+                       disable_timer_pin_1 = 1;
+               if (!memcmp(from, "enable_timer_pin_1", 18))
+                       disable_timer_pin_1 = -1;
+
                if (!memcmp(from, "nolapic", 7) ||
                    !memcmp(from, "disableapic", 11))
                        disable_apic = 1;
@@ -755,6 +760,24 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
        }
 }
 
+#ifdef CONFIG_NUMA
+static int nearby_node(int apicid)
+{
+       int i;
+       for (i = apicid - 1; i >= 0; i--) {
+               int node = apicid_to_node[i];
+               if (node != NUMA_NO_NODE && node_online(node))
+                       return node;
+       }
+       for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
+               int node = apicid_to_node[i];
+               if (node != NUMA_NO_NODE && node_online(node))
+                       return node;
+       }
+       return first_node(node_online_map); /* Shouldn't happen */
+}
+#endif
+
 /*
  * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
  * Assumes number of cores is a power of two.
@@ -763,8 +786,11 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
        int cpu = smp_processor_id();
-       int node = 0;
        unsigned bits;
+#ifdef CONFIG_NUMA
+       int node = 0;
+       unsigned apicid = phys_proc_id[cpu];
+#endif
 
        bits = 0;
        while ((1 << bits) < c->x86_num_cores)
@@ -776,20 +802,32 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
        phys_proc_id[cpu] >>= bits;
 
 #ifdef CONFIG_NUMA
-       /* When an ACPI SRAT table is available use the mappings from SRAT
-          instead. */
-       if (acpi_numa <= 0) {
-               node = phys_proc_id[cpu];
-               if (!node_online(node))
-                       node = first_node(node_online_map);
-               cpu_to_node[cpu] = node;
-       } else {
-               node = cpu_to_node[cpu];
-       }
+       node = phys_proc_id[cpu];
+       if (apicid_to_node[apicid] != NUMA_NO_NODE)
+               node = apicid_to_node[apicid];
+       if (!node_online(node)) {
+               /* Two possibilities here:
+                  - The CPU is missing memory and no node was created.
+                  In that case try picking one from a nearby CPU
+                  - The APIC IDs differ from the HyperTransport node IDs
+                  which the K8 northbridge parsing fills in.
+                  Assume they are all increased by a constant offset,
+                  but in the same order as the HT nodeids.
+                  If that doesn't result in a usable node fall back to the
+                  path for the previous case.  */
+               int ht_nodeid = apicid - (phys_proc_id[0] << bits);
+               if (ht_nodeid >= 0 &&
+                   apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
+                       node = apicid_to_node[ht_nodeid];
+               /* Pick a nearby node */
+               if (!node_online(node))
+                       node = nearby_node(apicid);
+       }
+       cpu_to_node[cpu] = node;
+
+       printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n",
+                       cpu, c->x86_num_cores, node, cpu_core_id[cpu]);
 #endif
-
-       printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n",
-                       cpu, c->x86_num_cores, node, cpu_core_id[cpu]);
 #endif
 }
 
@@ -909,6 +947,25 @@ static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
                return 1;
 }
 
+static void srat_detect_node(void)
+{
+#ifdef CONFIG_NUMA
+       unsigned apicid, node;
+       int cpu = smp_processor_id();
+
+       /* Don't do the funky fallback heuristics the AMD version employs
+          for now. */
+       apicid = phys_proc_id[cpu];
+       node = apicid_to_node[apicid];
+       if (node == NUMA_NO_NODE)
+               node = 0;
+       cpu_to_node[cpu] = node;
+
+       if (acpi_numa > 0)
+               printk(KERN_INFO "CPU %d -> Node %d\n", cpu, node);
+#endif
+}
+
 static void __cpuinit init_intel(struct cpuinfo_x86 *c)
 {
        /* Cache sizes */
@@ -927,6 +984,8 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
        if (c->x86 >= 15)
                set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
        c->x86_num_cores = intel_num_cpu_cores(c);
+
+       srat_detect_node();
 }
 
 static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
index e3ffcacc8c90bf40d17a778c684401a9d66b17d3..bd33be24a386717d3c402059ce49ba0dad3ab838 100644 (file)
@@ -94,7 +94,7 @@ void __init setup_per_cpu_areas(void)
                size = PERCPU_ENOUGH_ROOM;
 #endif
 
-       for (i = 0; i < NR_CPUS; i++) { 
+       for_each_cpu_mask (i, cpu_possible_map) {
                char *ptr;
 
                if (!NODE_DATA(cpu_to_node(i))) {
@@ -119,7 +119,6 @@ void pda_init(int cpu)
        asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); 
        wrmsrl(MSR_GS_BASE, cpu_pda + cpu);
 
-       pda->me = pda;
        pda->cpunumber = cpu; 
        pda->irqcount = -1;
        pda->kernelstack = 
index e5958220d6b8b8eaaca2f70d956efc249c3faa40..9db9dda161b40fe59df298406518bb4a867b0b61 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 
 #include <linux/mm.h>
-#include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
@@ -29,6 +28,8 @@
 #include <asm/proto.h>
 #include <asm/apicdef.h>
 
+#define __cpuinit __init
+
 /*
  *     Smarter SMP flushing macros. 
  *             c/o Linus Torvalds.
  *     writing to user space from interrupts. (Its not allowed anyway).
  *
  *     Optimizations Manfred Spraul <manfred@colorfullife.com>
+ *
+ *     More scalable flush, from Andi Kleen
+ *
+ *     To avoid global state use 8 different call vectors.
+ *     Each CPU uses a specific vector to trigger flushes on other
+ *     CPUs. Depending on the received vector the target CPUs look into
+ *     the right per cpu variable for the flush data.
+ *
+ *     With more than 8 CPUs they are hashed to the 8 available
+ *     vectors. The limited global vector space forces us to this right now.
+ *     In future when interrupts are split into per CPU domains this could be
+ *     fixed, at the cost of triggering multiple IPIs in some cases.
  */
 
-static cpumask_t flush_cpumask;
-static struct mm_struct * flush_mm;
-static unsigned long flush_va;
-static DEFINE_SPINLOCK(tlbstate_lock);
+union smp_flush_state {
+       struct {
+               cpumask_t flush_cpumask;
+               struct mm_struct *flush_mm;
+               unsigned long flush_va;
 #define FLUSH_ALL      -1ULL
+               spinlock_t tlbstate_lock;
+       };
+       char pad[SMP_CACHE_BYTES];
+} ____cacheline_aligned;
+
+/* State is put into the per CPU data section, but padded
+   to a full cache line because other CPUs can access it and we don't
+   want false sharing in the per cpu data segment. */
+static DEFINE_PER_CPU(union smp_flush_state, flush_state);
 
 /*
  * We cannot call mmdrop() because we are in interrupt context, 
  * instead update mm->cpu_vm_mask.
  */
-static inline void leave_mm (unsigned long cpu)
+static inline void leave_mm(int cpu)
 {
        if (read_pda(mmu_state) == TLBSTATE_OK)
                BUG();
@@ -101,15 +124,25 @@ static inline void leave_mm (unsigned long cpu)
  *
  * 1) Flush the tlb entries if the cpu uses the mm that's being flushed.
  * 2) Leave the mm if we are in the lazy tlb mode.
+ *
+ * Interrupts are disabled.
  */
 
-asmlinkage void smp_invalidate_interrupt (void)
+asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs)
 {
-       unsigned long cpu;
+       int cpu;
+       int sender;
+       union smp_flush_state *f;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
+       /*
+        * orig_rax contains the interrupt vector - 256.
+        * Use that to determine where the sender put the data.
+        */
+       sender = regs->orig_rax + 256 - INVALIDATE_TLB_VECTOR_START;
+       f = &per_cpu(flush_state, sender);
 
-       if (!cpu_isset(cpu, flush_cpumask))
+       if (!cpu_isset(cpu, f->flush_cpumask))
                goto out;
                /* 
                 * This was a BUG() but until someone can quote me the
@@ -120,64 +153,63 @@ asmlinkage void smp_invalidate_interrupt (void)
                 * BUG();
                 */
                 
-       if (flush_mm == read_pda(active_mm)) {
+       if (f->flush_mm == read_pda(active_mm)) {
                if (read_pda(mmu_state) == TLBSTATE_OK) {
-                       if (flush_va == FLUSH_ALL)
+                       if (f->flush_va == FLUSH_ALL)
                                local_flush_tlb();
                        else
-                               __flush_tlb_one(flush_va);
+                               __flush_tlb_one(f->flush_va);
                } else
                        leave_mm(cpu);
        }
 out:
        ack_APIC_irq();
-       cpu_clear(cpu, flush_cpumask);
-       put_cpu_no_resched();
+       cpu_clear(cpu, f->flush_cpumask);
 }
 
 static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
                                                unsigned long va)
 {
-       cpumask_t tmp;
-       /*
-        * A couple of (to be removed) sanity checks:
-        *
-        * - we do not send IPIs to not-yet booted CPUs.
-        * - current CPU must not be in mask
-        * - mask must exist :)
-        */
-       BUG_ON(cpus_empty(cpumask));
-       cpus_and(tmp, cpumask, cpu_online_map);
-       BUG_ON(!cpus_equal(tmp, cpumask));
-       BUG_ON(cpu_isset(smp_processor_id(), cpumask));
-       if (!mm)
-               BUG();
+       int sender;
+       union smp_flush_state *f;
 
-       /*
-        * I'm not happy about this global shared spinlock in the
-        * MM hot path, but we'll see how contended it is.
-        * Temporarily this turns IRQs off, so that lockups are
-        * detected by the NMI watchdog.
-        */
-       spin_lock(&tlbstate_lock);
-       
-       flush_mm = mm;
-       flush_va = va;
-       cpus_or(flush_cpumask, cpumask, flush_cpumask);
+       /* Caller has disabled preemption */
+       sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS;
+       f = &per_cpu(flush_state, sender);
+
+       /* Could avoid this lock when
+          num_online_cpus() <= NUM_INVALIDATE_TLB_VECTORS, but it is
+          probably not worth checking this for a cache-hot lock. */
+       spin_lock(&f->tlbstate_lock);
+
+       f->flush_mm = mm;
+       f->flush_va = va;
+       cpus_or(f->flush_cpumask, cpumask, f->flush_cpumask);
 
        /*
         * We have to send the IPI only to
         * CPUs affected.
         */
-       send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR);
+       send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR_START + sender);
+
+       while (!cpus_empty(f->flush_cpumask))
+               cpu_relax();
 
-       while (!cpus_empty(flush_cpumask))
-               mb();   /* nothing. lockup detection does not belong here */;
+       f->flush_mm = NULL;
+       f->flush_va = 0;
+       spin_unlock(&f->tlbstate_lock);
+}
 
-       flush_mm = NULL;
-       flush_va = 0;
-       spin_unlock(&tlbstate_lock);
+int __cpuinit init_smp_flush(void)
+{
+       int i;
+       for_each_cpu_mask(i, cpu_possible_map) {
+               spin_lock_init(&per_cpu(flush_state.tlbstate_lock, i));
+       }
+       return 0;
 }
+
+core_initcall(init_smp_flush);
        
 void flush_tlb_current_task(void)
 {
@@ -295,8 +327,11 @@ void unlock_ipi_call_lock(void)
 /*
  * this function sends a 'generic call function' IPI to one other CPU
  * in the system.
+ *
+ * cpu is a standard Linux logical CPU number.
  */
-static void __smp_call_function_single (int cpu, void (*func) (void *info), void *info,
+static void
+__smp_call_function_single(int cpu, void (*func) (void *info), void *info,
                                int nonatomic, int wait)
 {
        struct call_data_struct data;
index 4fb34b5cb1f964e8093bc73bfd5219649a952efa..e12d7baeb33ec47ca0dc935f267dcc874693d5f6 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/mm.h>
 #include <linux/kernel_stat.h>
 #include <linux/smp_lock.h>
-#include <linux/irq.h>
 #include <linux/bootmem.h>
 #include <linux/thread_info.h>
 #include <linux/module.h>
@@ -58,6 +57,8 @@
 #include <asm/tlbflush.h>
 #include <asm/proto.h>
 #include <asm/nmi.h>
+#include <asm/irq.h>
+#include <asm/hw_irq.h>
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
@@ -413,8 +414,13 @@ void __cpuinit smp_callin(void)
 
        /*
         * Get our bogomips.
+        *
+        * Need to enable IRQs because it can take longer and then
+        * the NMI watchdog might kill us.
         */
+       local_irq_enable();
        calibrate_delay();
+       local_irq_disable();
        Dprintk("Stack at about %p\n",&cpuid);
 
        disable_APIC_timer();
@@ -540,8 +546,8 @@ static void inquire_remote_apic(int apicid)
                 */
                apic_wait_icr_idle();
 
-               apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
-               apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
+               apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+               apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]);
 
                timeout = 0;
                do {
@@ -574,12 +580,12 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
        /*
         * Turn INIT on target chip
         */
-       apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
 
        /*
         * Send IPI
         */
-       apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
+       apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
                                | APIC_DM_INIT);
 
        Dprintk("Waiting for send to finish...\n");
@@ -595,10 +601,10 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
        Dprintk("Deasserting INIT.\n");
 
        /* Target chip */
-       apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+       apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
 
        /* Send IPI */
-       apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+       apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
 
        Dprintk("Waiting for send to finish...\n");
        timeout = 0;
@@ -610,16 +616,7 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
 
        atomic_set(&init_deasserted, 1);
 
-       /*
-        * Should we send STARTUP IPIs ?
-        *
-        * Determine this based on the APIC version.
-        * If we don't have an integrated APIC, don't send the STARTUP IPIs.
-        */
-       if (APIC_INTEGRATED(apic_version[phys_apicid]))
-               num_starts = 2;
-       else
-               num_starts = 0;
+       num_starts = 2;
 
        /*
         * Run STARTUP IPI loop.
@@ -640,12 +637,11 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
                 */
 
                /* Target chip */
-               apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+               apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
 
                /* Boot on the stack */
                /* Kick the second */
-               apic_write_around(APIC_ICR, APIC_DM_STARTUP
-                                       | (start_rip >> 12));
+               apic_write(APIC_ICR, APIC_DM_STARTUP | (start_rip >> 12));
 
                /*
                 * Give the other CPU some time to accept the IPI.
@@ -864,17 +860,6 @@ static __cpuinit void smp_cleanup_boot(void)
         * Reset trampoline flag
         */
        *((volatile int *) phys_to_virt(0x467)) = 0;
-
-#ifndef CONFIG_HOTPLUG_CPU
-       /*
-        * Free pages reserved for SMP bootup.
-        * When you add hotplug CPU support later remove this
-        * Note there is more work to be done for later CPU bootup.
-        */
-
-       free_page((unsigned long) __va(PAGE_SIZE));
-       free_page((unsigned long) __va(SMP_TRAMPOLINE_BASE));
-#endif
 }
 
 /*
index 0612640d91b1c31262d3022edd6ffac685190514..ebb9abf3ce6dae3269711f583b0ef2f827d148cb 100644 (file)
@@ -8,23 +8,8 @@
  */
 
 #include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/poll.h>
-#include <linux/delay.h>
-#include <linux/sysrq.h>
-#include <linux/proc_fs.h>
-#include <linux/irq.h>
-#include <linux/pm.h>
-#include <linux/device.h>
+#include <linux/smp.h>
 #include <linux/suspend.h>
-#include <asm/uaccess.h>
-#include <asm/acpi.h>
-#include <asm/tlbflush.h>
-#include <asm/io.h>
 #include <asm/proto.h>
 
 struct saved_context saved_context;
index 7b6abe0582536f54f5c5aea12587d22d3ab92f1d..2373cb8b86250744018a1ecdd48fc7b6da21248a 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/mc146818rtc.h>
-#include <linux/irq.h>
 #include <linux/time.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
@@ -937,7 +936,6 @@ void __init time_init(void)
        vxtime.mode = VXTIME_TSC;
        vxtime.quot = (1000000L << 32) / vxtime_hz;
        vxtime.tsc_quot = (1000L << 32) / cpu_khz;
-       vxtime.hz = vxtime_hz;
        rdtscll_sync(&vxtime.last_tsc);
        setup_irq(0, &irq0);
 
index f238d6078a5a921fcf94c935903b9aaa3aac5bf0..b5e09e6b55368fbd58572ac8c775bd1fc77ab4a7 100644 (file)
@@ -47,9 +47,6 @@
 #include <asm/proto.h>
 #include <asm/nmi.h>
 
-#include <linux/irq.h>
-
-
 extern struct gate_struct idt_table[256]; 
 
 asmlinkage void divide_error(void);
@@ -324,13 +321,13 @@ void handle_BUG(struct pt_regs *regs)
        if (__copy_from_user(&f, (struct bug_frame *) regs->rip, 
                             sizeof(struct bug_frame)))
                return; 
-       if ((unsigned long)f.filename < __PAGE_OFFSET || 
+       if (f.filename >= 0 ||
            f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) 
                return;
-       if (__get_user(tmp, f.filename))
-               f.filename = "unmapped filename"; 
+       if (__get_user(tmp, (char *)(long)f.filename))
+               f.filename = (int)(long)"unmapped filename";
        printk("----------- [cut here ] --------- [please bite here ] ---------\n");
-       printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line);
+       printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", (char *)(long)f.filename, f.line);
 } 
 
 #ifdef CONFIG_BUG
@@ -343,30 +340,33 @@ void out_of_line_bug(void)
 static DEFINE_SPINLOCK(die_lock);
 static int die_owner = -1;
 
-void oops_begin(void)
+unsigned long oops_begin(void)
 {
-       int cpu = safe_smp_processor_id(); 
-       /* racy, but better than risking deadlock. */ 
-       local_irq_disable();
+       int cpu = safe_smp_processor_id();
+       unsigned long flags;
+
+       /* racy, but better than risking deadlock. */
+       local_irq_save(flags);
        if (!spin_trylock(&die_lock)) { 
                if (cpu == die_owner) 
                        /* nested oops. should stop eventually */;
                else
-                       spin_lock(&die_lock); 
+                       spin_lock(&die_lock);
        }
-       die_owner = cpu; 
+       die_owner = cpu;
        console_verbose();
-       bust_spinlocks(1); 
+       bust_spinlocks(1);
+       return flags;
 }
 
-void oops_end(void)
+void oops_end(unsigned long flags)
 { 
        die_owner = -1;
-       bust_spinlocks(0); 
-       spin_unlock(&die_lock); 
+       bust_spinlocks(0);
+       spin_unlock_irqrestore(&die_lock, flags);
        if (panic_on_oops)
-               panic("Oops"); 
-} 
+               panic("Oops");
+}
 
 void __die(const char * str, struct pt_regs * regs, long err)
 {
@@ -392,10 +392,11 @@ void __die(const char * str, struct pt_regs * regs, long err)
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
-       oops_begin();
+       unsigned long flags = oops_begin();
+
        handle_BUG(regs);
        __die(str, regs, err);
-       oops_end();
+       oops_end(flags);
        do_exit(SIGSEGV); 
 }
 static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
@@ -406,7 +407,8 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
 
 void die_nmi(char *str, struct pt_regs *regs)
 {
-       oops_begin();
+       unsigned long flags = oops_begin();
+
        /*
         * We are in trouble anyway, lets at least try
         * to get a message out.
@@ -416,7 +418,7 @@ void die_nmi(char *str, struct pt_regs *regs)
        if (panic_on_timeout || panic_on_oops)
                panic("nmi watchdog");
        printk("console shuts up ...\n");
-       oops_end();
+       oops_end(flags);
        do_exit(SIGSEGV);
 }
 
@@ -790,13 +792,16 @@ asmlinkage void do_coprocessor_error(struct pt_regs *regs)
         */
        cwd = get_fpu_cwd(task);
        swd = get_fpu_swd(task);
-       switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
+       switch (swd & ~cwd & 0x3f) {
                case 0x000:
                default:
                        break;
                case 0x001: /* Invalid Op */
-               case 0x041: /* Stack Fault */
-               case 0x241: /* Stack Fault | Direction */
+                       /*
+                        * swd & 0x240 == 0x040: Stack Underflow
+                        * swd & 0x240 == 0x240: Stack Overflow
+                        * User must clear the SF bit (0x40) if set
+                        */
                        info.si_code = FPE_FLTINV;
                        break;
                case 0x002: /* Denormalize */
index 2e5734425949648ea92bd8d7fd9e65e6f99a8ed5..70a0bd16085fbd3a4fe9bf6c7719e5b33cb54965 100644 (file)
@@ -107,7 +107,7 @@ static force_inline long time_syscall(long *t)
        return secs;
 }
 
-static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
+int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
 {
        if (unlikely(!__sysctl_vsyscall))
                return gettimeofday(tv,tz);
@@ -120,7 +120,7 @@ static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz
 
 /* This will break when the xtime seconds get inaccurate, but that is
  * unlikely */
-static time_t __vsyscall(1) vtime(time_t *t)
+time_t __vsyscall(1) vtime(time_t *t)
 {
        if (unlikely(!__sysctl_vsyscall))
                return time_syscall(t);
@@ -129,12 +129,12 @@ static time_t __vsyscall(1) vtime(time_t *t)
        return __xtime.tv_sec;
 }
 
-static long __vsyscall(2) venosys_0(void)
+long __vsyscall(2) venosys_0(void)
 {
        return -ENOSYS;
 }
 
-static long __vsyscall(3) venosys_1(void)
+long __vsyscall(3) venosys_1(void)
 {
        return -ENOSYS;
 }
index 816732d8858c3195c7b6d78419b2b0b537de3f10..b75b872ec154f8e004fc04a29375eb97f7f468bb 100644 (file)
@@ -221,12 +221,13 @@ int unhandled_signal(struct task_struct *tsk, int sig)
 static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
                                 unsigned long error_code)
 {
-       oops_begin();
+       unsigned long flags = oops_begin();
+
        printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
               current->comm, address);
        dump_pagetable(address);
        __die("Bad pagetable", regs, error_code);
-       oops_end();
+       oops_end(flags);
        do_exit(SIGKILL);
 }
 
@@ -304,6 +305,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
        unsigned long address;
        const struct exception_table_entry *fixup;
        int write;
+       unsigned long flags;
        siginfo_t info;
 
 #ifdef CONFIG_CHECKING
@@ -521,7 +523,7 @@ no_context:
  * terminate things with extreme prejudice.
  */
 
-       oops_begin(); 
+       flags = oops_begin();
 
        if (address < PAGE_SIZE)
                printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
@@ -534,7 +536,7 @@ no_context:
        __die("Oops", regs, error_code);
        /* Executive summary in case the body of the oops scrolled away */
        printk(KERN_EMERG "CR2: %016lx\n", address);
-       oops_end(); 
+       oops_end(flags);
        do_exit(SIGKILL);
 
 /*
index aa4a5189ecee2640503d053bf6c79b233aa99f99..e60a1a848de8f622ce87bd7616b7c32b0dea6e0e 100644 (file)
@@ -57,31 +57,31 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 void show_mem(void)
 {
-       int i, total = 0, reserved = 0;
-       int shared = 0, cached = 0;
+       long i, total = 0, reserved = 0;
+       long shared = 0, cached = 0;
        pg_data_t *pgdat;
        struct page *page;
 
-       printk("Mem-info:\n");
+       printk(KERN_INFO "Mem-info:\n");
        show_free_areas();
-       printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+       printk(KERN_INFO "Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
 
        for_each_pgdat(pgdat) {
                for (i = 0; i < pgdat->node_spanned_pages; ++i) {
                        page = pfn_to_page(pgdat->node_start_pfn + i);
                        total++;
-                       if (PageReserved(page))
-                       reserved++;
-                       else if (PageSwapCache(page))
-                       cached++;
-                       else if (page_count(page))
-                               shared += page_count(page) - 1;
+                       if (PageReserved(page))
+                               reserved++;
+                       else if (PageSwapCache(page))
+                               cached++;
+                       else if (page_count(page))
+                               shared += page_count(page) - 1;
                }
        }
-       printk("%d pages of RAM\n", total);
-       printk("%d reserved pages\n",reserved);
-       printk("%d pages shared\n",shared);
-       printk("%d pages swap cached\n",cached);
+       printk(KERN_INFO "%lu pages of RAM\n", total);
+       printk(KERN_INFO "%lu reserved pages\n",reserved);
+       printk(KERN_INFO "%lu pages shared\n",shared);
+       printk(KERN_INFO "%lu pages swap cached\n",cached);
 }
 
 /* References to section boundaries */
@@ -381,41 +381,14 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size)
        __flush_tlb_all();
 } 
 
-static inline int page_is_ram (unsigned long pagenr)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               unsigned long addr, end;
-
-               if (e820.map[i].type != E820_RAM)       /* not usable memory */
-                       continue;
-               /*
-                *      !!!FIXME!!! Some BIOSen report areas as RAM that
-                *      are not. Notably the 640->1Mb area. We need a sanity
-                *      check here.
-                */
-               addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
-               end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
-               if  ((pagenr >= addr) && (pagenr < end))
-                       return 1;
-       }
-       return 0;
-}
-
-extern int swiotlb_force;
-
 static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
                         kcore_vsyscall;
 
 void __init mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-       int tmp;
+       long codesize, reservedpages, datasize, initsize;
 
 #ifdef CONFIG_SWIOTLB
-       if (swiotlb_force)
-               swiotlb = 1;
        if (!iommu_aperture &&
            (end_pfn >= 0xffffffff>>PAGE_SHIFT || force_iommu))
               swiotlb = 1;
@@ -436,25 +409,11 @@ void __init mem_init(void)
 
        /* this will put all low memory onto the freelists */
 #ifdef CONFIG_NUMA
-       totalram_pages += numa_free_all_bootmem();
-       tmp = 0;
-       /* should count reserved pages here for all nodes */ 
+       totalram_pages = numa_free_all_bootmem();
 #else
-
-#ifdef CONFIG_FLATMEM
-       max_mapnr = end_pfn;
-       if (!mem_map) BUG();
-#endif
-
-       totalram_pages += free_all_bootmem();
-
-       for (tmp = 0; tmp < end_pfn; tmp++)
-               /*
-                * Only count reserved RAM pages
-                */
-               if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
-                       reservedpages++;
+       totalram_pages = free_all_bootmem();
 #endif
+       reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn);
 
        after_bootmem = 1;
 
@@ -471,7 +430,7 @@ void __init mem_init(void)
        kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, 
                                 VSYSCALL_END - VSYSCALL_START);
 
-       printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+       printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
                (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
                end_pfn << (PAGE_SHIFT-10),
                codesize >> 10,
index ec35747aacd764b0aedf1824e604b704e5a164e9..65417b040c1bffd171f0ce46d590a57e174c742b 100644 (file)
@@ -45,10 +45,12 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
        unsigned long prevbase;
        struct node nodes[8];
        int nodeid, i, nb; 
+       unsigned char nodeids[8];
        int found = 0;
        u32 reg;
        unsigned numnodes;
        nodemask_t nodes_parsed;
+       unsigned dualcore = 0;
 
        nodes_clear(nodes_parsed);
 
@@ -67,11 +69,15 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
        prevbase = 0;
        for (i = 0; i < 8; i++) { 
                unsigned long base,limit; 
-
+               u32 nodeid;
+               
+               /* Undefined before E stepping, but hopefully 0 */
+               dualcore |= ((read_pci_config(0, nb, 3, 0xe8) >> 12) & 3) == 1;
                base = read_pci_config(0, nb, 1, 0x40 + i*8);
                limit = read_pci_config(0, nb, 1, 0x44 + i*8);
 
                nodeid = limit & 7; 
+               nodeids[i] = nodeid;
                if ((base & 3) == 0) { 
                        if (i < numnodes)
                                printk("Skipping disabled node %d\n", i); 
@@ -157,8 +163,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
 
        for (i = 0; i < 8; i++) {
                if (nodes[i].start != nodes[i].end) { 
-                       /* assume 1:1 NODE:CPU */
-                       cpu_to_node[i] = i; 
+                       nodeid = nodeids[i];
+                       apicid_to_node[nodeid << dualcore] = i;
+                       apicid_to_node[(nodeid << dualcore) + dualcore] = i;
                        setup_node_bootmem(i, nodes[i].start, nodes[i].end); 
                } 
        }
index 04f7a33e144c4bbbd05befd65d6c396184e6e75d..80a49d9bd8a77941a89794b32eba75e0cc2490aa 100644 (file)
@@ -28,8 +28,13 @@ bootmem_data_t plat_node_bdata[MAX_NUMNODES];
 int memnode_shift;
 u8  memnodemap[NODEMAPSIZE];
 
-unsigned char cpu_to_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = NUMA_NO_NODE };
-cpumask_t     node_to_cpumask[MAX_NUMNODES] __read_mostly;
+unsigned char cpu_to_node[NR_CPUS] __read_mostly = {
+       [0 ... NR_CPUS-1] = NUMA_NO_NODE
+};
+unsigned char apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
+       [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
+};
+cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly;
 
 int numa_off __initdata;
 
index 8e3d097a9ddddc5ef1c179cd24ae28a6d7902163..4b2e844c15a75707de27bccac2dcccd750db480c 100644 (file)
 
 static struct acpi_table_slit *acpi_slit;
 
-/* Internal processor count */
-static unsigned int __initdata num_processors = 0;
-
 static nodemask_t nodes_parsed __initdata;
 static nodemask_t nodes_found __initdata;
 static struct node nodes[MAX_NUMNODES] __initdata;
 static __u8  pxm2node[256] = { [0 ... 255] = 0xff };
 
+static int node_to_pxm(int n);
+
+int pxm_to_node(int pxm)
+{
+       if ((unsigned)pxm >= 256)
+               return 0;
+       return pxm2node[pxm];
+}
+
 static __init int setup_node(int pxm)
 {
        unsigned node = pxm2node[pxm];
@@ -44,14 +50,14 @@ static __init int setup_node(int pxm)
 static __init int conflicting_nodes(unsigned long start, unsigned long end)
 {
        int i;
-       for_each_online_node(i) {
+       for_each_node_mask(i, nodes_parsed) {
                struct node *nd = &nodes[i];
                if (nd->start == nd->end)
                        continue;
                if (nd->end > start && nd->start < end)
-                       return 1;
+                       return i;
                if (nd->end == end && nd->start == start)
-                       return 1;
+                       return i;
        }
        return -1;
 }
@@ -75,8 +81,11 @@ static __init void cutoff_node(int i, unsigned long start, unsigned long end)
 
 static __init void bad_srat(void)
 {
+       int i;
        printk(KERN_ERR "SRAT: SRAT not used.\n");
        acpi_numa = -1;
+       for (i = 0; i < MAX_LOCAL_APIC; i++)
+               apicid_to_node[i] = NUMA_NO_NODE;
 }
 
 static __init inline int srat_disabled(void)
@@ -104,18 +113,10 @@ acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
                bad_srat();
                return;
        }
-       if (num_processors >= NR_CPUS) {
-               printk(KERN_ERR "SRAT: Processor #%d (lapic %u) INVALID. (Max ID: %d).\n",
-                       num_processors, pa->apic_id, NR_CPUS);
-               bad_srat();
-               return;
-       }
-       cpu_to_node[num_processors] = node;
+       apicid_to_node[pa->apic_id] = node;
        acpi_numa = 1;
-       printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> CPU %u -> Node %u\n",
-              pxm, pa->apic_id, num_processors, node);
-
-       num_processors++;
+       printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
+              pxm, pa->apic_id, node);
 }
 
 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
@@ -143,10 +144,15 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
                printk(KERN_INFO "SRAT: hot plug zone found %lx - %lx \n",
                                start, end);
        i = conflicting_nodes(start, end);
-       if (i >= 0) {
+       if (i == node) {
+               printk(KERN_WARNING
+               "SRAT: Warning: PXM %d (%lx-%lx) overlaps with itself (%Lx-%Lx)\n",
+                       pxm, start, end, nodes[i].start, nodes[i].end);
+       } else if (i >= 0) {
                printk(KERN_ERR
-                      "SRAT: pxm %d overlap %lx-%lx with node %d(%Lx-%Lx)\n",
-                      pxm, start, end, i, nodes[i].start, nodes[i].end);
+                      "SRAT: PXM %d (%lx-%lx) overlaps with PXM %d (%Lx-%Lx)\n",
+                      pxm, start, end, node_to_pxm(i),
+                       nodes[i].start, nodes[i].end);
                bad_srat();
                return;
        }
@@ -174,6 +180,14 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
        int i;
        if (acpi_numa <= 0)
                return -1;
+
+       /* First clean up the node list */
+       for_each_node_mask(i, nodes_parsed) {
+               cutoff_node(i, start, end);
+               if (nodes[i].start == nodes[i].end)
+                       node_clear(i, nodes_parsed);
+       }
+
        memnode_shift = compute_hash_shift(nodes, nodes_weight(nodes_parsed));
        if (memnode_shift < 0) {
                printk(KERN_ERR
@@ -181,16 +195,10 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
                bad_srat();
                return -1;
        }
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               if (!node_isset(i, nodes_parsed))
-                       continue;
-               cutoff_node(i, start, end);
-               if (nodes[i].start == nodes[i].end) { 
-                       node_clear(i, nodes_parsed);
-                       continue;
-               }
+
+       /* Finally register nodes */
+       for_each_node_mask(i, nodes_parsed)
                setup_node_bootmem(i, nodes[i].start, nodes[i].end);
-       }
        for (i = 0; i < NR_CPUS; i++) { 
                if (cpu_to_node[i] == NUMA_NO_NODE)
                        continue;
@@ -201,7 +209,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
        return 0;
 }
 
-int node_to_pxm(int n)
+static int node_to_pxm(int n)
 {
        int i;
        if (pxm2node[n] == n)
index d80c323669e0c5e741a33f8c5700b2c8b8784007..3acf60ded2a0b54144a72b5b0faf5f8bc2c00933 100644 (file)
@@ -58,10 +58,16 @@ fill_mp_bus_to_cpumask(void)
                                for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus);
                                     j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
                                     j++) { 
-                                       int node = NODE_ID(nid);
+                                       struct pci_bus *bus;
+                                       long node = NODE_ID(nid);
+                                       /* Algorithm a bit dumb, but
+                                          it shouldn't matter here */
+                                       bus = pci_find_bus(0, j);
+                                       if (!bus)
+                                               continue;
                                        if (!node_online(node))
                                                node = 0;
-                                       pci_bus_to_node[j] = node;
+                                       bus->sysdata = (void *)node;
                                }               
                        }
                }
index 657e88aa09022ba67df0fcc8dca7d20e44ecef53..a0838c4a94e4c032d9d6024fb0eaed96b0d3dab3 100644 (file)
@@ -111,13 +111,6 @@ static int __init pci_mmcfg_init(void)
            (pci_mmcfg_config[0].base_address == 0))
                return 0;
 
-       /* Kludge for now. Don't use mmconfig on AMD systems because
-          those have some busses where mmconfig doesn't work,
-          and we don't parse ACPI MCFG well enough to handle that. 
-          Remove when proper handling is added. */
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-               return 0; 
-
        /* RED-PEN i386 doesn't do _nocache right now */
        pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
        if (pci_mmcfg_virt == NULL) {
index 46d655fab1159c54768d08d226ac3bc36a393b2a..48f446d3c671ade5a5198384c729f83118a35033 100644 (file)
@@ -4,6 +4,8 @@ menu "Device Drivers"
 
 source "drivers/base/Kconfig"
 
+source "drivers/connector/Kconfig"
+
 source "drivers/mtd/Kconfig"
 
 source "drivers/parport/Kconfig"
index 86c8654a0ca940d183adb4f945fa757b358e0d48..1a109a6dd953d90c4bb74146ccdbc6699f02a9e4 100644 (file)
@@ -17,6 +17,8 @@ obj-$(CONFIG_PNP)             += pnp/
 # default.
 obj-y                          += char/
 
+obj-$(CONFIG_CONNECTOR)                += connector/
+
 # i810fb and intelfb depend on char/agp/
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
index 373e7b728fa70746bb13907e07114ee0293fd4f6..6b2eb6f39b4dea6ec809acb715cf1c2ab1fc0b45 100644 (file)
@@ -152,12 +152,13 @@ attribute_container_add_device(struct device *dev,
 
                if (!cont->match(cont, dev))
                        continue;
-               ic = kmalloc(sizeof(struct internal_container), GFP_KERNEL);
+
+               ic = kzalloc(sizeof(*ic), GFP_KERNEL);
                if (!ic) {
                        dev_printk(KERN_ERR, dev, "failed to allocate class container\n");
                        continue;
                }
-               memset(ic, 0, sizeof(struct internal_container));
+
                ic->cont = cont;
                class_device_initialize(&ic->classdev);
                ic->classdev.dev = get_device(dev);
index d164c32a97ad4e90426a4f1e8a244b8d5f7d93d3..3b112e3542f897e81bf881b762f3a317ecaefae4 100644 (file)
@@ -189,12 +189,11 @@ struct class *class_create(struct module *owner, char *name)
        struct class *cls;
        int retval;
 
-       cls = kmalloc(sizeof(struct class), GFP_KERNEL);
+       cls = kzalloc(sizeof(*cls), GFP_KERNEL);
        if (!cls) {
                retval = -ENOMEM;
                goto error;
        }
-       memset(cls, 0x00, sizeof(struct class));
 
        cls->name = name;
        cls->owner = owner;
@@ -500,13 +499,13 @@ int class_device_add(struct class_device *class_dev)
        /* add the needed attributes to this device */
        if (MAJOR(class_dev->devt)) {
                struct class_device_attribute *attr;
-               attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+               attr = kzalloc(sizeof(*attr), GFP_KERNEL);
                if (!attr) {
                        error = -ENOMEM;
                        kobject_del(&class_dev->kobj);
                        goto register_done;
                }
-               memset(attr, sizeof(*attr), 0x00);
+
                attr->attr.name = "dev";
                attr->attr.mode = S_IRUGO;
                attr->attr.owner = parent->owner;
@@ -577,12 +576,11 @@ struct class_device *class_device_create(struct class *cls, dev_t devt,
        if (cls == NULL || IS_ERR(cls))
                goto error;
 
-       class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
+       class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
        if (!class_dev) {
                retval = -ENOMEM;
                goto error;
        }
-       memset(class_dev, 0x00, sizeof(struct class_device));
 
        class_dev->devt = devt;
        class_dev->dev = device;
index 5bfa2e9a7c2678efade79213aa5bd203054613b8..4acb2c5733c3b46710d6321b886d16b8704f1d1c 100644 (file)
@@ -301,9 +301,9 @@ fw_register_class_device(struct class_device **class_dev_p,
                         const char *fw_name, struct device *device)
 {
        int retval;
-       struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
+       struct firmware_priv *fw_priv = kzalloc(sizeof(*fw_priv),
                                                GFP_KERNEL);
-       struct class_device *class_dev = kmalloc(sizeof (struct class_device),
+       struct class_device *class_dev = kzalloc(sizeof(*class_dev),
                                                 GFP_KERNEL);
 
        *class_dev_p = NULL;
@@ -313,8 +313,6 @@ fw_register_class_device(struct class_device **class_dev_p,
                retval = -ENOMEM;
                goto error_kfree;
        }
-       memset(fw_priv, 0, sizeof (*fw_priv));
-       memset(class_dev, 0, sizeof (*class_dev));
 
        init_completion(&fw_priv->completion);
        fw_priv->attr_data = firmware_attr_data_tmpl;
@@ -402,14 +400,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
        if (!firmware_p)
                return -EINVAL;
 
-       *firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL);
+       *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
        if (!firmware) {
                printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
                       __FUNCTION__);
                retval = -ENOMEM;
                goto out;
        }
-       memset(firmware, 0, sizeof (*firmware));
 
        retval = fw_setup_class_device(firmware, &class_dev, name, device,
                hotplug);
index 2f455d86793c8bde34098fae2deb80a17e54238d..b449dae6f0d30fcb8385ce68c1f9bdfd34f6ff64 100644 (file)
@@ -135,7 +135,7 @@ retry:
 struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
 {
        struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
-       struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL);
+       struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
        int i;
 
        if ((p == NULL) || (base == NULL)) {
@@ -144,7 +144,6 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
                return NULL;
        }
 
-       memset(base, 0, sizeof(struct probe));
        base->dev = 1;
        base->range = ~0;
        base->get = base_probe;
index 3a5f4c991797a02eb0de0ecaac726076d88281f9..361e204209ebb3c8324599aecf0716766d1b20c1 100644 (file)
@@ -225,13 +225,12 @@ struct platform_device *platform_device_register_simple(char *name, unsigned int
        struct platform_object *pobj;
        int retval;
 
-       pobj = kmalloc(sizeof(struct platform_object) + sizeof(struct resource) * num, GFP_KERNEL);
+       pobj = kzalloc(sizeof(*pobj) + sizeof(struct resource) * num, GFP_KERNEL);
        if (!pobj) {
                retval = -ENOMEM;
                goto error;
        }
 
-       memset(pobj, 0, sizeof(*pobj));
        pobj->pdev.name = name;
        pobj->pdev.id = id;
        pobj->pdev.dev.release = platform_device_release_simple;
index 721ba8086043bd714c06e5353f60a348e7989f50..0e9e586e9ba362a52bbac71e1bb169451fdbe6c5 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (c) 2004 Coraid, Inc.  See COPYING for GPL terms. */
-#define VERSION "10"
+#define VERSION "12"
 #define AOE_MAJOR 152
 #define DEVICE_NAME "aoe"
 
@@ -7,12 +7,12 @@
  * default is 16, which is 15 partitions plus the whole disk
  */
 #ifndef AOE_PARTITIONS
-#define AOE_PARTITIONS 16
+#define AOE_PARTITIONS (16)
 #endif
 
-#define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * 10 + (aoeminor))
-#define AOEMAJOR(sysminor) ((sysminor) / 10)
-#define AOEMINOR(sysminor) ((sysminor) % 10)
+#define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * NPERSHELF + (aoeminor))
+#define AOEMAJOR(sysminor) ((sysminor) / NPERSHELF)
+#define AOEMINOR(sysminor) ((sysminor) % NPERSHELF)
 #define WHITESPACE " \t\v\f\n"
 
 enum {
@@ -83,7 +83,7 @@ enum {
 
 enum {
        MAXATADATA = 1024,
-       NPERSHELF = 10,
+       NPERSHELF = 16,         /* number of slots per shelf address */
        FREETAG = -1,
        MIN_BUFS = 8,
 };
index 28f2c177a54167a0ce7d3bd9e3f1dbe7ac1d7995..c56f995aadadcee00d8a63982ccf0a16da20c97a 100644 (file)
 #include <linux/completion.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.6.6)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,6)
+#define DRIVER_NAME "HP CISS Driver (v 2.6.8)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
+MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
-                       " SA6i P600 P800 E400 E300");
+                       " SA6i P600 P800 P400 P400i E200 E200i");
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -83,12 +83,22 @@ static const struct pci_device_id cciss_pci_device_id[] = {
                0x0E11, 0x4091, 0, 0, 0},
        { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
                0x103C, 0x3225, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
                0x103c, 0x3223, 0, 0, 0},
        { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-               0x103c, 0x3231, 0, 0, 0},
+               0x103c, 0x3234, 0, 0, 0},
        { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-               0x103c, 0x3233, 0, 0, 0},
+               0x103c, 0x3235, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3211, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3212, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3213, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3214, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3215, 0, 0, 0},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -111,8 +121,13 @@ static struct board_type products[] = {
        { 0x40910E11, "Smart Array 6i", &SA5_access},
        { 0x3225103C, "Smart Array P600", &SA5_access},
        { 0x3223103C, "Smart Array P800", &SA5_access},
-       { 0x3231103C, "Smart Array E400", &SA5_access},
-       { 0x3233103C, "Smart Array E300", &SA5_access},
+       { 0x3234103C, "Smart Array P400", &SA5_access},
+       { 0x3235103C, "Smart Array P400i", &SA5_access},
+       { 0x3211103C, "Smart Array E200i", &SA5_access},
+       { 0x3212103C, "Smart Array E200", &SA5_access},
+       { 0x3213103C, "Smart Array E200i", &SA5_access},
+       { 0x3214103C, "Smart Array E200i", &SA5_access},
+       { 0x3215103C, "Smart Array E200i", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
@@ -140,15 +155,26 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 
 static int revalidate_allvol(ctlr_info_t *host);
 static int cciss_revalidate(struct gendisk *disk);
-static int deregister_disk(struct gendisk *disk);
-static int register_new_disk(ctlr_info_t *h);
+static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all);
 
+static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
+       int withirq, unsigned int *total_size, unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol,
+                       int withirq, unsigned int total_size,
+                       unsigned int block_size, InquiryData_struct *inq_buff,
+                       drive_info_struct *drv);
 static void cciss_getgeometry(int cntl_num);
 
 static void start_io( ctlr_info_t *h);
 static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
        unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
        unsigned char *scsi3addr, int cmd_type);
+static int sendcmd_withirq(__u8        cmd, int ctlr, void *buff, size_t size,
+       unsigned int use_unit_num, unsigned int log_unit, __u8  page_code,
+       int cmd_type);
+
+static void fail_all_cmds(unsigned long ctlr);
 
 #ifdef CONFIG_PROC_FS
 static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
@@ -265,7 +291,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
        for(i=0; i<=h->highest_lun; i++) {
 
                 drv = &h->drv[i];
-               if (drv->block_size == 0)
+               if (drv->heads == 0)
                        continue;
 
                vol_sz = drv->nr_blocks;
@@ -363,6 +389,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
                        return NULL;
                memset(c, 0, sizeof(CommandList_struct));
 
+               c->cmdindex = -1;
+
                c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
                                        h->pdev, sizeof(ErrorInfo_struct), 
                                        &err_dma_handle);
@@ -393,6 +421,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
                err_dma_handle = h->errinfo_pool_dhandle 
                                        + i*sizeof(ErrorInfo_struct);
                 h->nr_allocs++;
+
+               c->cmdindex = i;
         }
 
        c->busaddr = (__u32) cmd_dma_handle;
@@ -453,6 +483,11 @@ static int cciss_open(struct inode *inode, struct file *filep)
        printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
 #endif /* CCISS_DEBUG */ 
 
+       if (host->busy_initializing)
+               return -EBUSY;
+
+       if (host->busy_initializing || drv->busy_configuring)
+               return -EBUSY;
        /*
         * Root is allowed to open raw volume zero even if it's not configured
         * so array config can still work. Root is also allowed to open any
@@ -796,10 +831,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
                return(0);
        }
        case CCISS_DEREGDISK:
-               return deregister_disk(disk);
+               return rebuild_lun_table(host, disk);
 
        case CCISS_REGNEWD:
-               return register_new_disk(host);
+               return rebuild_lun_table(host, NULL);
 
        case CCISS_PASSTHRU:
        {
@@ -1143,48 +1178,323 @@ static int revalidate_allvol(ctlr_info_t *host)
         return 0;
 }
 
-static int deregister_disk(struct gendisk *disk)
+/* This function will check the usage_count of the drive to be updated/added.
+ * If the usage_count is zero then the drive information will be updated and
+ * the disk will be re-registered with the kernel.  If not then it will be
+ * left alone for the next reboot.  The exception to this is disk 0 which
+ * will always be left registered with the kernel since it is also the
+ * controller node.  Any changes to disk 0 will show up on the next
+ * reboot.
+*/
+static void cciss_update_drive_info(int ctlr, int drv_index)
+  {
+       ctlr_info_t *h = hba[ctlr];
+       struct gendisk *disk;
+       ReadCapdata_struct *size_buff = NULL;
+       InquiryData_struct *inq_buff = NULL;
+       unsigned int block_size;
+       unsigned int total_size;
+       unsigned long flags = 0;
+       int ret = 0;
+
+       /* if the disk already exists then deregister it before proceeding*/
+       if (h->drv[drv_index].raid_level != -1){
+               spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+               h->drv[drv_index].busy_configuring = 1;
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               ret = deregister_disk(h->gendisk[drv_index],
+                       &h->drv[drv_index], 0);
+               h->drv[drv_index].busy_configuring = 0;
+       }
+
+       /* If the disk is in use return */
+       if (ret)
+               return;
+
+
+       /* Get information about the disk and modify the driver sturcture */
+       size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+        if (size_buff == NULL)
+               goto mem_msg;
+       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+       if (inq_buff == NULL)
+               goto mem_msg;
+
+       cciss_read_capacity(ctlr, drv_index, size_buff, 1,
+               &total_size, &block_size);
+       cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
+               inq_buff, &h->drv[drv_index]);
+
+       ++h->num_luns;
+       disk = h->gendisk[drv_index];
+       set_capacity(disk, h->drv[drv_index].nr_blocks);
+
+
+       /* if it's the controller it's already added */
+       if (drv_index){
+               disk->queue = blk_init_queue(do_cciss_request, &h->lock);
+
+               /* Set up queue information */
+               disk->queue->backing_dev_info.ra_pages = READ_AHEAD;
+               blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask);
+
+               /* This is a hardware imposed limit. */
+               blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES);
+
+               /* This is a limit in the driver and could be eliminated. */
+               blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES);
+
+               blk_queue_max_sectors(disk->queue, 512);
+
+               disk->queue->queuedata = hba[ctlr];
+
+               blk_queue_hardsect_size(disk->queue,
+                       hba[ctlr]->drv[drv_index].block_size);
+
+               h->drv[drv_index].queue = disk->queue;
+               add_disk(disk);
+       }
+
+freeret:
+       kfree(size_buff);
+       kfree(inq_buff);
+       return;
+mem_msg:
+       printk(KERN_ERR "cciss: out of memory\n");
+       goto freeret;
+}
+
+/* This function will find the first index of the controllers drive array
+ * that has a -1 for the raid_level and will return that index.  This is
+ * where new drives will be added.  If the index to be returned is greater
+ * than the highest_lun index for the controller then highest_lun is set
+ * to this new index.  If there are no available indexes then -1 is returned.
+*/
+static int cciss_find_free_drive_index(int ctlr)
 {
+       int i;
+
+       for (i=0; i < CISS_MAX_LUN; i++){
+               if (hba[ctlr]->drv[i].raid_level == -1){
+                       if (i > hba[ctlr]->highest_lun)
+                               hba[ctlr]->highest_lun = i;
+                       return i;
+               }
+       }
+       return -1;
+}
+
+/* This function will add and remove logical drives from the Logical
+ * drive array of the controller and maintain persistancy of ordering
+ * so that mount points are preserved until the next reboot.  This allows
+ * for the removal of logical drives in the middle of the drive array
+ * without a re-ordering of those drives.
+ * INPUT
+ * h           = The controller to perform the operations on
+ * del_disk    = The disk to remove if specified.  If the value given
+ *               is NULL then no disk is removed.
+*/
+static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
+{
+       int ctlr = h->ctlr;
+       int num_luns;
+       ReportLunData_struct *ld_buff = NULL;
+       drive_info_struct *drv = NULL;
+       int return_code;
+       int listlength = 0;
+       int i;
+       int drv_found;
+       int drv_index = 0;
+       __u32 lunid = 0;
        unsigned long flags;
+
+       /* Set busy_configuring flag for this operation */
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->num_luns >= CISS_MAX_LUN){
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return -EINVAL;
+       }
+
+       if (h->busy_configuring){
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return -EBUSY;
+       }
+       h->busy_configuring = 1;
+
+       /* if del_disk is NULL then we are being called to add a new disk
+        * and update the logical drive table.  If it is not NULL then
+        * we will check if the disk is in use or not.
+        */
+       if (del_disk != NULL){
+               drv = get_drv(del_disk);
+               drv->busy_configuring = 1;
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return_code = deregister_disk(del_disk, drv, 1);
+               drv->busy_configuring = 0;
+               h->busy_configuring = 0;
+               return return_code;
+       } else {
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               if (!capable(CAP_SYS_RAWIO))
+                       return -EPERM;
+
+               ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+               if (ld_buff == NULL)
+                       goto mem_msg;
+
+               return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
+                               sizeof(ReportLunData_struct), 0, 0, 0,
+                               TYPE_CMD);
+
+               if (return_code == IO_OK){
+                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
+                       listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+               } else{ /* reading number of logical volumes failed */
+                       printk(KERN_WARNING "cciss: report logical volume"
+                               " command failed\n");
+                       listlength = 0;
+                       goto freeret;
+               }
+
+               num_luns = listlength / 8;      /* 8 bytes per entry */
+               if (num_luns > CISS_MAX_LUN){
+                       num_luns = CISS_MAX_LUN;
+                       printk(KERN_WARNING "cciss: more luns configured"
+                               " on controller than can be handled by"
+                               " this driver.\n");
+               }
+
+               /* Compare controller drive array to drivers drive array.
+               * Check for updates in the drive information and any new drives
+               * on the controller.
+               */
+               for (i=0; i < num_luns; i++){
+                       int j;
+
+                       drv_found = 0;
+
+                       lunid = (0xff &
+                               (unsigned int)(ld_buff->LUN[i][3])) << 24;
+                       lunid |= (0xff &
+                               (unsigned int)(ld_buff->LUN[i][2])) << 16;
+                       lunid |= (0xff &
+                               (unsigned int)(ld_buff->LUN[i][1])) << 8;
+                       lunid |= 0xff &
+                               (unsigned int)(ld_buff->LUN[i][0]);
+
+                       /* Find if the LUN is already in the drive array
+                        * of the controller.  If so then update its info
+                        * if not is use.  If it does not exist then find
+                        * the first free index and add it.
+                       */
+                       for (j=0; j <= h->highest_lun; j++){
+                               if (h->drv[j].LunID == lunid){
+                                       drv_index = j;
+                                       drv_found = 1;
+                               }
+                       }
+
+                       /* check if the drive was found already in the array */
+                       if (!drv_found){
+                               drv_index = cciss_find_free_drive_index(ctlr);
+                               if (drv_index == -1)
+                                       goto freeret;
+
+                       }
+                       h->drv[drv_index].LunID = lunid;
+                       cciss_update_drive_info(ctlr, drv_index);
+               } /* end for */
+       } /* end else */
+
+freeret:
+       kfree(ld_buff);
+       h->busy_configuring = 0;
+       /* We return -1 here to tell the ACU that we have registered/updated
+        * all of the drives that we can and to keep it from calling us
+        * additional times.
+       */
+       return -1;
+mem_msg:
+       printk(KERN_ERR "cciss: out of memory\n");
+       goto freeret;
+}
+
+/* This function will deregister the disk and it's queue from the
+ * kernel.  It must be called with the controller lock held and the
+ * drv structures busy_configuring flag set.  It's parameters are:
+ *
+ * disk = This is the disk to be deregistered
+ * drv  = This is the drive_info_struct associated with the disk to be
+ *        deregistered.  It contains information about the disk used
+ *        by the driver.
+ * clear_all = This flag determines whether or not the disk information
+ *             is going to be completely cleared out and the highest_lun
+ *             reset.  Sometimes we want to clear out information about
+ *             the disk in preperation for re-adding it.  In this case
+ *             the highest_lun should be left unchanged and the LunID
+ *             should not be cleared.
+*/
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+                          int clear_all)
+{
        ctlr_info_t *h = get_host(disk);
-       drive_info_struct *drv = get_drv(disk);
-       int ctlr = h->ctlr;
 
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
 
-       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
        /* make sure logical volume is NOT is use */
-       if( drv->usage_count > 1) {
-               spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+       if(clear_all || (h->gendisk[0] == disk)) {
+       if (drv->usage_count > 1)
                 return -EBUSY;
        }
-       drv->usage_count++;
-       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+        else
+               if( drv->usage_count > 0 )
+                       return -EBUSY;
 
-       /* invalidate the devices and deregister the disk */ 
-       if (disk->flags & GENHD_FL_UP)
+       /* invalidate the devices and deregister the disk.  If it is disk
+        * zero do not deregister it but just zero out it's values.  This
+        * allows us to delete disk zero but keep the controller registered.
+       */
+       if (h->gendisk[0] != disk){
+               if (disk->flags & GENHD_FL_UP){
+                       blk_cleanup_queue(disk->queue);
                del_gendisk(disk);
+                       drv->queue = NULL;
+               }
+       }
+
+       --h->num_luns;
+       /* zero out the disk size info */
+       drv->nr_blocks = 0;
+       drv->block_size = 0;
+       drv->heads = 0;
+       drv->sectors = 0;
+       drv->cylinders = 0;
+       drv->raid_level = -1;   /* This can be used as a flag variable to
+                                * indicate that this element of the drive
+                                * array is free.
+                               */
+
+       if (clear_all){
        /* check to see if it was the last disk */
        if (drv == h->drv + h->highest_lun) {
                /* if so, find the new hightest lun */
                int i, newhighest =-1;
                for(i=0; i<h->highest_lun; i++) {
                        /* if the disk has size > 0, it is available */
-                       if (h->drv[i].nr_blocks)
+                               if (h->drv[i].heads)
                                newhighest = i;
                }
                h->highest_lun = newhighest;
-                               
        }
-       --h->num_luns;
-       /* zero out the disk size info */ 
-       drv->nr_blocks = 0;
-       drv->block_size = 0;
-       drv->cylinders = 0;
+
        drv->LunID = 0;
+       }
        return(0);
 }
+
 static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
        size_t size,
        unsigned int use_unit_num, /* 0: address the controller,
@@ -1420,8 +1730,10 @@ case CMD_HARDWARE_ERR:
                }
        }       
        /* unlock the buffers from DMA */
+       buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
+       buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
        pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
-                       size, PCI_DMA_BIDIRECTIONAL);
+                       c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
        cmd_free(h, c, 0);
         return(return_status);
 
@@ -1495,164 +1807,6 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
        return;
 }
 
-static int register_new_disk(ctlr_info_t *h)
-{
-        struct gendisk *disk;
-       int ctlr = h->ctlr;
-        int i;
-       int num_luns;
-       int logvol;
-       int new_lun_found = 0;
-       int new_lun_index = 0;
-       int free_index_found = 0;
-       int free_index = 0;
-       ReportLunData_struct *ld_buff = NULL;
-       ReadCapdata_struct *size_buff = NULL;
-       InquiryData_struct *inq_buff = NULL;
-       int return_code;
-       int listlength = 0;
-       __u32 lunid = 0;
-       unsigned int block_size;
-       unsigned int total_size;
-
-        if (!capable(CAP_SYS_RAWIO))
-                return -EPERM;
-       /* if we have no space in our disk array left to add anything */
-       if(  h->num_luns >= CISS_MAX_LUN)
-               return -EINVAL;
-       
-       ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
-       if (ld_buff == NULL)
-               goto mem_msg;
-       memset(ld_buff, 0, sizeof(ReportLunData_struct));
-       size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-               goto mem_msg;
-       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-               goto mem_msg;
-       
-       return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, 
-                       sizeof(ReportLunData_struct), 0, 0, 0, TYPE_CMD);
-
-       if( return_code == IO_OK)
-       {
-               
-               // printk("LUN Data\n--------------------------\n");
-
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;  
-               listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-       } else /* reading number of logical volumes failed */
-       {
-               printk(KERN_WARNING "cciss: report logical volume"
-                       " command failed\n");
-               listlength = 0;
-               goto free_err;
-       }
-       num_luns = listlength / 8; // 8 bytes pre entry
-       if (num_luns > CISS_MAX_LUN)
-       {
-               num_luns = CISS_MAX_LUN;
-       }
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
-               ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
-               ld_buff->LUNListLength[3],  num_luns);
-#endif 
-       for(i=0; i<  num_luns; i++)
-       {
-               int j;
-               int lunID_found = 0;
-
-               lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
-               lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
-               lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
-               lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
-               
-               /* check to see if this is a new lun */ 
-               for(j=0; j <= h->highest_lun; j++)
-               {
-#ifdef CCISS_DEBUG
-                       printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
-                                               lunid);
-#endif /* CCISS_DEBUG */
-                       if (h->drv[j].LunID == lunid)
-                       {
-                               lunID_found = 1;
-                               break;
-                       }
-                       
-               }
-               if( lunID_found == 1)
-                       continue;
-               else
-               {       /* It is the new lun we have been looking for */
-#ifdef CCISS_DEBUG
-                       printk("new lun found at %d\n", i);
-#endif /* CCISS_DEBUG */
-                       new_lun_index = i;
-                       new_lun_found = 1;
-                       break;  
-               }
-        }
-        if (!new_lun_found)
-        {
-               printk(KERN_WARNING "cciss:  New Logical Volume not found\n");
-               goto free_err;
-        }
-        /* Now find the free index     */
-       for(i=0; i <CISS_MAX_LUN; i++)
-       {
-#ifdef CCISS_DEBUG
-               printk("Checking Index %d\n", i);
-#endif /* CCISS_DEBUG */
-               if(h->drv[i].LunID == 0)
-               {
-#ifdef CCISS_DEBUG
-                       printk("free index found at %d\n", i);
-#endif /* CCISS_DEBUG */
-                       free_index_found = 1;
-                       free_index = i;
-                       break;
-               }
-       }
-       if (!free_index_found)
-       {
-               printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
-               goto free_err;
-         }
-
-       logvol = free_index;
-       h->drv[logvol].LunID = lunid;
-               /* there could be gaps in lun numbers, track hightest */
-       if(h->highest_lun < lunid)
-               h->highest_lun = logvol;
-       cciss_read_capacity(ctlr, logvol, size_buff, 1,
-               &total_size, &block_size);
-       cciss_geometry_inquiry(ctlr, logvol, 1, total_size, block_size,
-                       inq_buff, &h->drv[logvol]);
-       h->drv[logvol].usage_count = 0;
-       ++h->num_luns;
-       /* setup partitions per disk */
-        disk = h->gendisk[logvol];
-       set_capacity(disk, h->drv[logvol].nr_blocks);
-       /* if it's the controller it's already added */
-       if(logvol)
-               add_disk(disk);
-freeret:
-       kfree(ld_buff);
-       kfree(size_buff);
-       kfree(inq_buff);
-       return (logvol);
-mem_msg:
-       printk(KERN_ERR "cciss: out of memory\n");
-free_err:
-       logvol = -1;
-       goto freeret;
-}
-
 static int cciss_revalidate(struct gendisk *disk)
 {
        ctlr_info_t *h = get_host(disk);
@@ -1859,8 +2013,10 @@ resend_cmd1:
                
 cleanup1:      
        /* unlock the data buffer from DMA */
+       buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
+       buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
        pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                               size, PCI_DMA_BIDIRECTIONAL);
+                               c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
        cmd_free(info_p, c, 1);
        return (status);
 } 
@@ -2111,7 +2267,11 @@ queue:
        /* fill in the request */ 
        drv = creq->rq_disk->private_data;
        c->Header.ReplyQueue = 0;  // unused in simple mode
-       c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
+       /* got command from pool, so use the command block index instead */
+       /* for direct lookups. */
+       /* The first 2 bits are reserved for controller error reporting. */
+       c->Header.Tag.lower = (c->cmdindex << 3);
+       c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
        c->Header.LUN.LogDev.VolId= drv->LunID;
        c->Header.LUN.LogDev.Mode = 1;
        c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
@@ -2186,7 +2346,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
        ctlr_info_t *h = dev_id;
        CommandList_struct *c;
        unsigned long flags;
-       __u32 a, a1;
+       __u32 a, a1, a2;
        int j;
        int start_queue = h->next_to_run;
 
@@ -2204,10 +2364,21 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
                {
                        a1 = a;
+                       if ((a & 0x04)) {
+                               a2 = (a >> 3);
+                               if (a2 >= NR_CMDS) {
+                                       printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr);
+                                       fail_all_cmds(h->ctlr);
+                                       return IRQ_HANDLED;
+                               }
+
+                               c = h->cmd_pool + a2;
+                               a = c->busaddr;
+
+                       } else {
                        a &= ~3;
-                       if ((c = h->cmpQ) == NULL)
-                       {  
-                               printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1);
+                               if ((c = h->cmpQ) == NULL) {
+                                       printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1);
                                continue;       
                        } 
                        while(c->busaddr != a) {
@@ -2215,6 +2386,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                                if (c == h->cmpQ) 
                                        break;
                        }
+                       }
                        /*
                         * If we've found the command, take it off the
                         * completion Q and free it
@@ -2634,12 +2806,16 @@ static void cciss_getgeometry(int cntl_num)
 #endif /* CCISS_DEBUG */
 
        hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
-       for(i=0; i<  hba[cntl_num]->num_luns; i++)
+//     for(i=0; i<  hba[cntl_num]->num_luns; i++)
+       for(i=0; i < CISS_MAX_LUN; i++)
        {
-
-               lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
-               lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
-               lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+               if (i < hba[cntl_num]->num_luns){
+                       lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
+                                << 24;
+                       lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
+                                << 16;
+                       lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
+                                << 8;
                lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
                
                hba[cntl_num]->drv[i].LunID = lunid;
@@ -2647,13 +2823,18 @@ static void cciss_getgeometry(int cntl_num)
 
 #ifdef CCISS_DEBUG
                printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i, 
-               ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], 
-               ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID);
+                       ld_buff->LUN[i][0], ld_buff->LUN[i][1],
+                       ld_buff->LUN[i][2], ld_buff->LUN[i][3],
+                       hba[cntl_num]->drv[i].LunID);
 #endif /* CCISS_DEBUG */
                cciss_read_capacity(cntl_num, i, size_buff, 0,
                        &total_size, &block_size);
-               cciss_geometry_inquiry(cntl_num, i, 0, total_size, block_size,
-                       inq_buff, &hba[cntl_num]->drv[i]);
+                       cciss_geometry_inquiry(cntl_num, i, 0, total_size,
+                               block_size, inq_buff, &hba[cntl_num]->drv[i]);
+               } else {
+                       /* initialize raid_level to indicate a free space */
+                       hba[cntl_num]->drv[i].raid_level = -1;
+               }
        }
        kfree(ld_buff);
        kfree(size_buff);
@@ -2727,6 +2908,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        i = alloc_cciss_hba();
        if(i < 0)
                return (-1);
+
+       hba[i]->busy_initializing = 1;
+
        if (cciss_pci_init(hba[i], pdev) != 0)
                goto clean1;
 
@@ -2849,6 +3033,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                add_disk(disk);
        }
 
+       hba[i]->busy_initializing = 0;
        return(1);
 
 clean4:
@@ -2869,6 +3054,7 @@ clean2:
 clean1:
        release_io_mem(hba[i]);
        free_hba(i);
+       hba[i]->busy_initializing = 0;
        return(-1);
 }
 
@@ -2913,9 +3099,10 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
        /* remove it from the disk list */
        for (j = 0; j < NWD; j++) {
                struct gendisk *disk = hba[i]->gendisk[j];
-               if (disk->flags & GENHD_FL_UP)
-                       blk_cleanup_queue(disk->queue);
+               if (disk->flags & GENHD_FL_UP) {
                        del_gendisk(disk);
+                       blk_cleanup_queue(disk->queue);
+               }
        }
 
        pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
@@ -2964,5 +3151,43 @@ static void __exit cciss_cleanup(void)
        remove_proc_entry("cciss", proc_root_driver);
 }
 
+static void fail_all_cmds(unsigned long ctlr)
+{
+       /* If we get here, the board is apparently dead. */
+       ctlr_info_t *h = hba[ctlr];
+       CommandList_struct *c;
+       unsigned long flags;
+
+       printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
+       h->alive = 0;   /* the controller apparently died... */
+
+       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+
+       pci_disable_device(h->pdev); /* Make sure it is really dead. */
+
+       /* move everything off the request queue onto the completed queue */
+       while( (c = h->reqQ) != NULL ) {
+               removeQ(&(h->reqQ), c);
+               h->Qdepth--;
+               addQ (&(h->cmpQ), c);
+       }
+
+       /* Now, fail everything on the completed queue with a HW error */
+       while( (c = h->cmpQ) != NULL ) {
+               removeQ(&h->cmpQ, c);
+               c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+               if (c->cmd_type == CMD_RWREQ) {
+                       complete_command(h, c, 0);
+               } else if (c->cmd_type == CMD_IOCTL_PEND)
+                       complete(c->waiting);
+#ifdef CONFIG_CISS_SCSI_TAPE
+                       else if (c->cmd_type == CMD_SCSI)
+                               complete_scsi_command(c, 0, 0);
+#endif
+       }
+       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+       return;
+}
+
 module_init(cciss_init);
 module_exit(cciss_cleanup);
index 566587d0a5003726dc75e5fe7ea67ad639581c54..ef277baee9fdc565834a04dda71f1da3014bba72 100644 (file)
@@ -35,7 +35,13 @@ typedef struct _drive_info_struct
        int     heads;
        int     sectors;
        int     cylinders;
-       int     raid_level;
+       int     raid_level; /* set to -1 to indicate that
+                            * the drive is not in use/configured
+                           */
+       int     busy_configuring; /*This is set when the drive is being removed
+                                  *to prevent it from being opened or it's queue
+                                  *from being started.
+                                 */
 } drive_info_struct;
 
 struct ctlr_info 
@@ -83,6 +89,7 @@ struct ctlr_info
        int                     nr_allocs;
        int                     nr_frees; 
        int                     busy_configuring;
+       int                     busy_initializing;
 
        /* This element holds the zero based queue number of the last
         * queue to be started.  It is used for fairness.
@@ -94,6 +101,7 @@ struct ctlr_info
 #ifdef CONFIG_CISS_SCSI_TAPE
        void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
+       unsigned char alive;
 };
 
 /*  Defining the diffent access_menthods */
index a88a88817623fb34b230141eba5f0ae7d068c95b..53fea549ba8b23a6714cfd8a33fc55705893986e 100644 (file)
@@ -226,6 +226,10 @@ typedef struct _ErrorInfo_struct {
 #define CMD_MSG_DONE   0x04
 #define CMD_MSG_TIMEOUT 0x05
 
+/* This structure needs to be divisible by 8 for new
+ * indexing method.
+ */
+#define PADSIZE (sizeof(long) - 4)
 typedef struct _CommandList_struct {
   CommandListHeader_struct Header;
   RequestBlock_struct      Request;
@@ -236,14 +240,14 @@ typedef struct _CommandList_struct {
   ErrorInfo_struct *      err_info; /* pointer to the allocated mem */ 
   int                     ctlr;
   int                     cmd_type; 
+  long                    cmdindex;
   struct _CommandList_struct *prev;
   struct _CommandList_struct *next;
   struct request *        rq;
   struct completion *waiting;
   int   retry_count;
-#ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
-#endif
+  char   pad[PADSIZE];
 } CommandList_struct;
 
 //Configuration Table Structure
index f16e3caed58a36129ff7046531607ea6cfb07fa3..e183a3ef7839fdabd5dfc8a2ec9d1f1fa11d94db 100644 (file)
@@ -93,6 +93,7 @@ struct cciss_scsi_cmd_stack_elem_t {
        CommandList_struct cmd;
        ErrorInfo_struct Err;
        __u32 busaddr;
+       __u32 pad;
 };
 
 #pragma pack()
@@ -877,7 +878,7 @@ cciss_scsi_interpret_error(CommandList_struct *cp)
 
 static int
 cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, 
-                InquiryData_struct *buf)
+                unsigned char *buf, unsigned char bufsize)
 {
        int rc;
        CommandList_struct *cp;
@@ -900,11 +901,10 @@ cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
        cdb[1] = 0;
        cdb[2] = 0;
        cdb[3] = 0;
-       cdb[4] = sizeof(*buf) & 0xff;
+       cdb[4] = bufsize;
        cdb[5] = 0;
        rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb, 
-                               6, (unsigned char *) buf, 
-                               sizeof(*buf), XFER_READ);
+                               6, buf, bufsize, XFER_READ);
 
        if (rc != 0) return rc; /* something went wrong */
 
@@ -1000,9 +1000,10 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
           that though.  
 
         */
-
+#define OBDR_TAPE_INQ_SIZE 49
+#define OBDR_TAPE_SIG "$DR-10"
        ReportLunData_struct *ld_buff;
-       InquiryData_struct *inq_buff;
+       unsigned char *inq_buff;
        unsigned char scsi3addr[8];
        ctlr_info_t *c;
        __u32 num_luns=0;
@@ -1020,7 +1021,7 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
                return;
        }
        memset(ld_buff, 0, reportlunsize);
-       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+       inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
         if (inq_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
                 kfree(ld_buff);
@@ -1051,19 +1052,36 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
 
                /* for each physical lun, do an inquiry */
                if (ld_buff->LUN[i][3] & 0xC0) continue;
-               memset(inq_buff, 0, sizeof(InquiryData_struct));
+               memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
                memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
 
-               if (cciss_scsi_do_inquiry(hba[cntl_num], 
-                       scsi3addr, inq_buff) != 0)
-               {
+               if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, inq_buff,
+                       (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
                        /* Inquiry failed (msg printed already) */
                        devtype = 0; /* so we will skip this device. */
                } else /* what kind of device is this? */
-                       devtype = (inq_buff->data_byte[0] & 0x1f);
+                       devtype = (inq_buff[0] & 0x1f);
 
                switch (devtype)
                {
+                 case 0x05: /* CD-ROM */ {
+
+                       /* We don't *really* support actual CD-ROM devices,
+                        * just this "One Button Disaster Recovery" tape drive
+                        * which temporarily pretends to be a CD-ROM drive.
+                        * So we check that the device is really an OBDR tape
+                        * device by checking for "$DR-10" in bytes 43-48 of
+                        * the inquiry data.
+                        */
+                               char obdr_sig[7];
+
+                               strncpy(obdr_sig, &inq_buff[43], 6);
+                               obdr_sig[6] = '\0';
+                               if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)
+                                       /* Not OBDR device, ignore it. */
+                                       break;
+                       }
+                       /* fall through . . . */
                  case 0x01: /* sequential access, (tape) */
                  case 0x08: /* medium changer */
                        if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
@@ -1126,6 +1144,7 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
 
        int buflen, datalen;
        ctlr_info_t *ci;
+       int i;
        int cntl_num;
 
 
@@ -1136,8 +1155,28 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
        cntl_num = ci->ctlr;    /* Get our index into the hba[] array */
 
        if (func == 0) {        /* User is reading from /proc/scsi/ciss*?/?*  */
-               buflen = sprintf(buffer, "hostnum=%d\n", sh->host_no);  
-
+               buflen = sprintf(buffer, "cciss%d: SCSI host: %d\n",
+                               cntl_num, sh->host_no);
+
+               /* this information is needed by apps to know which cciss
+                  device corresponds to which scsi host number without
+                  having to open a scsi target device node.  The device
+                  information is not a duplicate of /proc/scsi/scsi because
+                  the two may be out of sync due to scsi hotplug, rather
+                  this info is for an app to be able to use to know how to
+                  get them back in sync. */
+
+               for (i=0;i<ccissscsi[cntl_num].ndevices;i++) {
+                       struct cciss_scsi_dev_t *sd = &ccissscsi[cntl_num].dev[i];
+                       buflen += sprintf(&buffer[buflen], "c%db%dt%dl%d %02d "
+                               "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                               sh->host_no, sd->bus, sd->target, sd->lun,
+                               sd->devtype,
+                               sd->scsi3addr[0], sd->scsi3addr[1],
+                               sd->scsi3addr[2], sd->scsi3addr[3],
+                               sd->scsi3addr[4], sd->scsi3addr[5],
+                               sd->scsi3addr[6], sd->scsi3addr[7]);
+               }
                datalen = buflen - offset;
                if (datalen < 0) {      /* they're reading past EOF. */
                        datalen = 0;
@@ -1399,7 +1438,7 @@ cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 
        CPQ_TAPE_LOCK(ctlr, flags);
        size = sprintf(buffer + *len, 
-               "       Sequential access devices: %d\n\n",
+               "Sequential access devices: %d\n\n",
                        ccissscsi[ctlr].ndevices);
        CPQ_TAPE_UNLOCK(ctlr, flags);
        *pos += size; *len += size;
index 7b838342f0a353939324c228212074b15ea48c76..7e22a58926b8ed790636c62f1a036a4799391ee3 100644 (file)
@@ -5,29 +5,41 @@
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  *
- * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and
- * DVD-RW devices (aka an exercise in block layer masturbation)
+ * Packet writing layer for ATAPI and SCSI CD-RW, DVD+RW, DVD-RW and
+ * DVD-RAM devices.
  *
+ * Theory of operation:
  *
- * TODO: (circa order of when I will fix it)
- * - Only able to write on CD-RW media right now.
- * - check host application code on media and set it in write page
- * - interface for UDF <-> packet to negotiate a new location when a write
- *   fails.
- * - handle OPC, especially for -RW media
+ * At the lowest level, there is the standard driver for the CD/DVD device,
+ * typically ide-cd.c or sr.c. This driver can handle read and write requests,
+ * but it doesn't know anything about the special restrictions that apply to
+ * packet writing. One restriction is that write requests must be aligned to
+ * packet boundaries on the physical media, and the size of a write request
+ * must be equal to the packet size. Another restriction is that a
+ * GPCMD_FLUSH_CACHE command has to be issued to the drive before a read
+ * command, if the previous command was a write.
  *
- * Theory of operation:
+ * The purpose of the packet writing driver is to hide these restrictions from
+ * higher layers, such as file systems, and present a block device that can be
+ * randomly read and written using 2kB-sized blocks.
+ *
+ * The lowest layer in the packet writing driver is the packet I/O scheduler.
+ * Its data is defined by the struct packet_iosched and includes two bio
+ * queues with pending read and write requests. These queues are processed
+ * by the pkt_iosched_process_queue() function. The write requests in this
+ * queue are already properly aligned and sized. This layer is responsible for
+ * issuing the flush cache commands and scheduling the I/O in a good order.
  *
- * We use a custom make_request_fn function that forwards reads directly to
- * the underlying CD device. Write requests are either attached directly to
- * a live packet_data object, or simply stored sequentially in a list for
- * later processing by the kcdrwd kernel thread. This driver doesn't use
- * any elevator functionally as defined by the elevator_s struct, but the
- * underlying CD device uses a standard elevator.
+ * The next layer transforms unaligned write requests to aligned writes. This
+ * transformation requires reading missing pieces of data from the underlying
+ * block device, assembling the pieces to full packets and queuing them to the
+ * packet I/O scheduler.
  *
- * This strategy makes it possible to do very late merging of IO requests.
- * A new bio sent to pkt_make_request can be merged with a live packet_data
- * object even if the object is in the data gathering state.
+ * At the top layer there is a custom make_request_fn function that forwards
+ * read requests directly to the iosched queue and puts write requests in the
+ * unaligned write queue. A kernel thread performs the necessary read
+ * gathering to convert the unaligned writes to aligned writes and then feeds
+ * them to the packet I/O scheduler.
  *
  *************************************************************************/
 
@@ -100,10 +112,9 @@ static struct bio *pkt_bio_alloc(int nr_iovecs)
                goto no_bio;
        bio_init(bio);
 
-       bvl = kmalloc(nr_iovecs * sizeof(struct bio_vec), GFP_KERNEL);
+       bvl = kcalloc(nr_iovecs, sizeof(struct bio_vec), GFP_KERNEL);
        if (!bvl)
                goto no_bvl;
-       memset(bvl, 0, nr_iovecs * sizeof(struct bio_vec));
 
        bio->bi_max_vecs = nr_iovecs;
        bio->bi_io_vec = bvl;
@@ -125,10 +136,9 @@ static struct packet_data *pkt_alloc_packet_data(void)
        int i;
        struct packet_data *pkt;
 
-       pkt = kmalloc(sizeof(struct packet_data), GFP_KERNEL);
+       pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL);
        if (!pkt)
                goto no_pkt;
-       memset(pkt, 0, sizeof(struct packet_data));
 
        pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE);
        if (!pkt->w_bio)
@@ -659,7 +669,6 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct page **pages, in
                }
                offs += CD_FRAMESIZE;
                if (offs >= PAGE_SIZE) {
-                       BUG_ON(offs > PAGE_SIZE);
                        offs = 0;
                        p++;
                }
@@ -724,12 +733,6 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        atomic_set(&pkt->io_wait, 0);
        atomic_set(&pkt->io_errors, 0);
 
-       if (pkt->cache_valid) {
-               VPRINTK("pkt_gather_data: zone %llx cached\n",
-                       (unsigned long long)pkt->sector);
-               goto out_account;
-       }
-
        /*
         * Figure out which frames we need to read before we can write.
         */
@@ -738,6 +741,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
                int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
                int num_frames = bio->bi_size / CD_FRAMESIZE;
+               pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
                BUG_ON(first_frame < 0);
                BUG_ON(first_frame + num_frames > pkt->frames);
                for (f = first_frame; f < first_frame + num_frames; f++)
@@ -745,6 +749,12 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        }
        spin_unlock(&pkt->lock);
 
+       if (pkt->cache_valid) {
+               VPRINTK("pkt_gather_data: zone %llx cached\n",
+                       (unsigned long long)pkt->sector);
+               goto out_account;
+       }
+
        /*
         * Schedule reads for missing parts of the packet.
         */
@@ -778,7 +788,6 @@ out_account:
                frames_read, (unsigned long long)pkt->sector);
        pd->stats.pkt_started++;
        pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9);
-       pd->stats.secs_w += pd->settings.size;
 }
 
 /*
@@ -794,10 +803,11 @@ static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zo
                        list_del_init(&pkt->list);
                        if (pkt->sector != zone)
                                pkt->cache_valid = 0;
-                       break;
+                       return pkt;
                }
        }
-       return pkt;
+       BUG();
+       return NULL;
 }
 
 static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt)
@@ -941,12 +951,10 @@ try_next_bio:
        }
 
        pkt = pkt_get_packet_data(pd, zone);
-       BUG_ON(!pkt);
 
        pd->current_sector = zone + pd->settings.size;
        pkt->sector = zone;
        pkt->frames = pd->settings.size >> 2;
-       BUG_ON(pkt->frames > PACKET_MAX_SIZE);
        pkt->write_size = 0;
 
        /*
@@ -1636,6 +1644,10 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
                printk("pktcdvd: detected zero packet size!\n");
                pd->settings.size = 128;
        }
+       if (pd->settings.size > PACKET_MAX_SECTORS) {
+               printk("pktcdvd: packet size is too big\n");
+               return -ENXIO;
+       }
        pd->settings.fp = ti.fp;
        pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
 
@@ -2198,7 +2210,6 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
         * No matching packet found. Store the bio in the work queue.
         */
        node = mempool_alloc(pd->rb_pool, GFP_NOIO);
-       BUG_ON(!node);
        node->bio = bio;
        spin_lock(&pd->lock);
        BUG_ON(pd->bio_queue_size < 0);
@@ -2406,7 +2417,6 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
        struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
 
        VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode));
-       BUG_ON(!pd);
 
        switch (cmd) {
        /*
@@ -2477,10 +2487,9 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
                return -EBUSY;
        }
 
-       pd = kmalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
+       pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
        if (!pd)
                return ret;
-       memset(pd, 0, sizeof(struct pktcdvd_device));
 
        pd->rb_pool = mempool_create(PKT_RB_POOL_SIZE, pkt_rb_alloc, pkt_rb_free, NULL);
        if (!pd->rb_pool)
index abb2df249fd35dbb3242d31285f75586022ab324..856c2278e9d0b74ea1a8a168be4743f859505a99 100644 (file)
@@ -123,6 +123,7 @@ static int verify_command(struct file *file, unsigned char *cmd)
                safe_for_read(READ_12),
                safe_for_read(READ_16),
                safe_for_read(READ_BUFFER),
+               safe_for_read(READ_DEFECT_DATA),
                safe_for_read(READ_LONG),
                safe_for_read(INQUIRY),
                safe_for_read(MODE_SENSE),
index 2a36561eec68dab6efc8e690167df7a78668f1eb..a124f8c5d062dd65b29775881f9b9c55a0d95a14 100644 (file)
@@ -2053,10 +2053,6 @@ static int __init rs_init(void)
        state->icount.rx = state->icount.tx = 0;
        state->icount.frame = state->icount.parity = 0;
        state->icount.overrun = state->icount.brk = 0;
-       /*
-       if(state->port && check_region(state->port,REGION_LENGTH(state)))
-         continue;
-       */
 
        printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n",
                       state->line);
index c3898afce3aed341e06e56a7d03b0425f27296b4..344001b45af94b3caa8ac0cf83979e224bb61e96 100644 (file)
@@ -84,6 +84,17 @@ config 977_WATCHDOG
 
          Not sure? It's safe to say N.
 
+config IXP2000_WATCHDOG
+       tristate "IXP2000 Watchdog"
+       depends on WATCHDOG && ARCH_IXP2000
+       help
+         Say Y here if to include support for the watchdog timer
+         in the Intel IXP2000(2400, 2800, 2850) network processors.
+         This driver can be built as a module by choosing M. The module
+         will be called ixp2000_wdt.
+
+         Say N if you are unsure.
+
 config IXP4XX_WATCHDOG
        tristate "IXP4xx Watchdog"
        depends on WATCHDOG && ARCH_IXP4XX
@@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG
 
          Say N if you are unsure.
 
-config IXP2000_WATCHDOG
-       tristate "IXP2000 Watchdog"
-       depends on WATCHDOG && ARCH_IXP2000
-       help
-         Say Y here if to include support for the watchdog timer
-         in the Intel IXP2000(2400, 2800, 2850) network processors.
-         This driver can be built as a module by choosing M. The module
-         will be called ixp2000_wdt.
-
-         Say N if you are unsure.
-
 config S3C2410_WATCHDOG
        tristate "S3C2410 Watchdog"
        depends on WATCHDOG && ARCH_S3C2410
@@ -139,6 +139,15 @@ config SA1100_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called sa1100_wdt.
 
+config MPCORE_WATCHDOG
+       tristate "MPcore watchdog"
+       depends on WATCHDOG && ARM_MPCORE_PLATFORM && LOCAL_TIMERS
+       help
+         Watchdog timer embedded into the MPcore system.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mpcore_wdt.
+
 # X86 (i386 + ia64 + x86_64) Architecture
 
 config ACQUIRE_WDT
@@ -224,6 +233,16 @@ config IB700_WDT
 
          Most people will say N.
 
+config IBMASR
+        tristate "IBM Automatic Server Restart"
+        depends on WATCHDOG && X86
+        help
+         This is the driver for the IBM Automatic Server Restart watchdog
+         timer builtin into some eServer xSeries machines.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ibmasr.
+
 config WAFER_WDT
        tristate "ICP Wafer 5823 Single Board Computer Watchdog"
        depends on WATCHDOG && X86
@@ -234,6 +253,16 @@ config WAFER_WDT
          To compile this driver as a module, choose M here: the
          module will be called wafer5823wdt.
 
+config I6300ESB_WDT
+       tristate "Intel 6300ESB Timer/Watchdog"
+       depends on WATCHDOG && X86 && PCI
+       ---help---
+         Hardware driver for the watchdog timer built into the Intel
+         6300ESB controller hub.
+
+         To compile this driver as a module, choose M here: the
+         module will be called i6300esb.
+
 config I8XX_TCO
        tristate "Intel i8xx TCO Timer/Watchdog"
        depends on WATCHDOG && (X86 || IA64) && PCI
@@ -289,6 +318,19 @@ config 60XX_WDT
          You can compile this driver directly into the kernel, or use
          it as a module.  The module will be called sbc60xxwdt.
 
+config SBC8360_WDT
+       tristate "SBC8360 Watchdog Timer"
+       depends on WATCHDOG && X86
+       ---help---
+
+         This is the driver for the hardware watchdog on the SBC8360 Single
+         Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com).
+
+         To compile this driver as a module, choose M here: the
+         module will be called sbc8360.ko.
+
+         Most people will say N.
+
 config CPU5_WDT
        tristate "SMA CPU5 Watchdog"
        depends on WATCHDOG && X86
@@ -327,6 +369,19 @@ config W83877F_WDT
 
          Most people will say N.
 
+config W83977F_WDT
+       tristate "W83977F (PCM-5335) Watchdog Timer"
+       depends on WATCHDOG && X86
+       ---help---
+         This is the driver for the hardware watchdog on the W83977F I/O chip
+         as used in AAEON's PCM-5335 SBC (and likely others).  This
+         watchdog simply watches your kernel to make sure it doesn't freeze,
+         and if it does, it reboots your computer after a certain amount of
+         time.
+
+         To compile this driver as a module, choose M here: the
+         module will be called w83977f_wdt.
+
 config MACHZ_WDT
        tristate "ZF MachZ Watchdog"
        depends on WATCHDOG && X86
@@ -346,6 +401,10 @@ config 8xx_WDT
        tristate "MPC8xx Watchdog Timer"
        depends on WATCHDOG && 8xx
 
+config MV64X60_WDT
+       tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
+       depends on WATCHDOG && MV64X60
+
 config BOOKE_WDT
        tristate "PowerPC Book-E Watchdog Timer"
        depends on WATCHDOG && (BOOKE || 4xx)
@@ -353,6 +412,17 @@ config BOOKE_WDT
          Please see Documentation/watchdog/watchdog-api.txt for
          more information.
 
+# PPC64 Architecture
+
+config WATCHDOG_RTAS
+       tristate "RTAS watchdog"
+       depends on WATCHDOG && PPC_RTAS
+       help
+         This driver adds watchdog support for the RTAS watchdog.
+
+          To compile this driver as a module, choose M here. The module
+         will be called wdrtas.
+
 # MIPS Architecture
 
 config INDYDOG
@@ -421,16 +491,6 @@ config WATCHDOG_RIO
          machines.  The watchdog timeout period is normally one minute but
          can be changed with a boot-time parameter.
 
-# ppc64 RTAS watchdog
-config WATCHDOG_RTAS
-       tristate "RTAS watchdog"
-       depends on WATCHDOG && PPC_RTAS
-       help
-         This driver adds watchdog support for the RTAS watchdog.
-
-          To compile this driver as a module, choose M here. The module
-         will be called wdrtas.
-
 #
 # ISA-based Watchdog Cards
 #
index cfeac6f10137e5fc30862d8f287a53d3c084e73a..cfd0a39877102224f901856f805562ed4feb1b33 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
+obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 
 # X86 (i386 + ia64 + x86_64) Architecture
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
@@ -38,22 +39,27 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
 obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
 obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
 obj-$(CONFIG_IB700_WDT) += ib700wdt.o
+obj-$(CONFIG_IBMASR) += ibmasr.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
 obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
 obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
 
 # PowerPC Architecture
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
+obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
 
 # PPC64 Architecture
 obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
-obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
 
 # MIPS Architecture
 obj-$(CONFIG_INDYDOG) += indydog.o
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
new file mode 100644 (file)
index 0000000..93785f1
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ *     i6300esb:       Watchdog timer driver for Intel 6300ESB chipset
+ *
+ *     (c) Copyright 2004 Google Inc.
+ *     (c) Copyright 2005 David Härdeman <david@2gen.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *      based on i810-tco.c which is in turn based on softdog.c
+ *
+ *     The timer is implemented in the following I/O controller hubs:
+ *     (See the intel documentation on http://developer.intel.com.)
+ *     6300ESB chip : document number 300641-003
+ *
+ *  2004YYZZ Ross Biro
+ *     Initial version 0.01
+ *  2004YYZZ Ross Biro
+ *     Version 0.02
+ *  20050210 David Härdeman <david@2gen.com>
+ *      Ported driver to kernel 2.6
+ */
+
+/*
+ *      Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* Module and version information */
+#define ESB_VERSION "0.03"
+#define ESB_MODULE_NAME "i6300ESB timer"
+#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
+#define PFX ESB_MODULE_NAME ": "
+
+/* PCI configuration registers */
+#define ESB_CONFIG_REG  0x60            /* Config register                   */
+#define ESB_LOCK_REG    0x68            /* WDT lock register                 */
+
+/* Memory mapped registers */
+#define ESB_TIMER1_REG  BASEADDR + 0x00 /* Timer1 value after each reset     */
+#define ESB_TIMER2_REG  BASEADDR + 0x04 /* Timer2 value after each reset     */
+#define ESB_GINTSR_REG  BASEADDR + 0x08 /* General Interrupt Status Register */
+#define ESB_RELOAD_REG  BASEADDR + 0x0c /* Reload register                   */
+
+/* Lock register bits */
+#define ESB_WDT_FUNC    ( 0x01 << 2 )   /* Watchdog functionality            */
+#define ESB_WDT_ENABLE  ( 0x01 << 1 )   /* Enable WDT                        */
+#define ESB_WDT_LOCK    ( 0x01 << 0 )   /* Lock (nowayout)                   */
+
+/* Config register bits */
+#define ESB_WDT_REBOOT  ( 0x01 << 5 )   /* Enable reboot on timeout          */
+#define ESB_WDT_FREQ    ( 0x01 << 2 )   /* Decrement frequency               */
+#define ESB_WDT_INTTYPE ( 0x11 << 0 )   /* Interrupt type on timer1 timeout  */
+
+/* Reload register bits */
+#define ESB_WDT_RELOAD ( 0x01 << 8 )    /* prevent timeout                   */
+
+/* Magic constants */
+#define ESB_UNLOCK1     0x80            /* Step 1 to unlock reset registers  */
+#define ESB_UNLOCK2     0x86            /* Step 2 to unlock reset registers  */
+
+/* internal variables */
+static void __iomem *BASEADDR;
+static spinlock_t esb_lock; /* Guards the hardware */
+static unsigned long timer_alive;
+static struct pci_dev *esb_pci;
+static unsigned short triggered; /* The status of the watchdog upon boot */
+static char esb_expect_close;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30   /* 30 sec default heartbeat (1<heartbeat<2*1023) */
+static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Some i6300ESB specific functions
+ */
+
+/*
+ * Prepare for reloading the timer by unlocking the proper registers.
+ * This is performed by first writing 0x80 followed by 0x86 to the
+ * reload register. After this the appropriate registers can be written
+ * to once before they need to be unlocked again.
+ */
+static inline void esb_unlock_registers(void) {
+        writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
+        writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
+}
+
+static void esb_timer_start(void)
+{
+       u8 val;
+
+       /* Enable or Enable + Lock? */
+       val = 0x02 | (nowayout ? 0x01 : 0x00);
+
+        pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
+}
+
+static int esb_timer_stop(void)
+{
+       u8 val;
+
+       spin_lock(&esb_lock);
+       /* First, reset timers as suggested by the docs */
+       esb_unlock_registers();
+       writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+       /* Then disable the WDT */
+       pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0);
+       pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val);
+       spin_unlock(&esb_lock);
+
+       /* Returns 0 if the timer was disabled, non-zero otherwise */
+       return (val & 0x01);
+}
+
+static void esb_timer_keepalive(void)
+{
+       spin_lock(&esb_lock);
+       esb_unlock_registers();
+       writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+        /* FIXME: Do we need to flush anything here? */
+       spin_unlock(&esb_lock);
+}
+
+static int esb_timer_set_heartbeat(int time)
+{
+       u32 val;
+
+       if (time < 0x1 || time > (2 * 0x03ff))
+               return -EINVAL;
+
+       spin_lock(&esb_lock);
+
+       /* We shift by 9, so if we are passed a value of 1 sec,
+        * val will be 1 << 9 = 512, then write that to two
+        * timers => 2 * 512 = 1024 (which is decremented at 1KHz)
+        */
+       val = time << 9;
+
+       /* Write timer 1 */
+       esb_unlock_registers();
+       writel(val, ESB_TIMER1_REG);
+
+       /* Write timer 2 */
+       esb_unlock_registers();
+        writel(val, ESB_TIMER2_REG);
+
+        /* Reload */
+       esb_unlock_registers();
+       writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+
+       /* FIXME: Do we need to flush everything out? */
+
+       /* Done */
+       heartbeat = time;
+       spin_unlock(&esb_lock);
+       return 0;
+}
+
+static int esb_timer_read (void)
+{
+               u32 count;
+
+       /* This isn't documented, and doesn't take into
+         * acount which stage is running, but it looks
+         * like a 20 bit count down, so we might as well report it.
+         */
+        pci_read_config_dword(esb_pci, 0x64, &count);
+        return (int)count;
+}
+
+/*
+ *     /dev/watchdog handling
+ */
+
+static int esb_open (struct inode *inode, struct file *file)
+{
+        /* /dev/watchdog can only be opened once */
+        if (test_and_set_bit(0, &timer_alive))
+                return -EBUSY;
+
+        /* Reload and activate timer */
+        esb_timer_keepalive ();
+        esb_timer_start ();
+
+       return nonseekable_open(inode, file);
+}
+
+static int esb_release (struct inode *inode, struct file *file)
+{
+        /* Shut off the timer. */
+        if (esb_expect_close == 42) {
+                esb_timer_stop ();
+        } else {
+                printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+                esb_timer_keepalive ();
+        }
+        clear_bit(0, &timer_alive);
+        esb_expect_close = 0;
+        return 0;
+}
+
+static ssize_t esb_write (struct file *file, const char __user *data,
+                         size_t len, loff_t * ppos)
+{
+       /* See if we got the magic character 'V' and reload the timer */
+        if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /* note: just in case someone wrote the magic character
+                        * five months ago... */
+                       esb_expect_close = 0;
+
+                       /* scan to see whether or not we got the magic character */
+                       for (i = 0; i != len; i++) {
+                               char c;
+                               if(get_user(c, data+i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       esb_expect_close = 42;
+                       }
+               }
+
+               /* someone wrote to us, we should reload the timer */
+               esb_timer_keepalive ();
+       }
+       return len;
+}
+
+static int esb_ioctl (struct inode *inode, struct file *file,
+                     unsigned int cmd, unsigned long arg)
+{
+       int new_options, retval = -EINVAL;
+       int new_heartbeat;
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       static struct watchdog_info ident = {
+               .options =              WDIOF_SETTIMEOUT |
+                                       WDIOF_KEEPALIVEPING |
+                                       WDIOF_MAGICCLOSE,
+               .firmware_version =     0,
+               .identity =             ESB_MODULE_NAME,
+       };
+
+       switch (cmd) {
+               case WDIOC_GETSUPPORT:
+                       return copy_to_user(argp, &ident,
+                                           sizeof (ident)) ? -EFAULT : 0;
+
+               case WDIOC_GETSTATUS:
+                       return put_user (esb_timer_read(), p);
+
+               case WDIOC_GETBOOTSTATUS:
+                       return put_user (triggered, p);
+
+                case WDIOC_KEEPALIVE:
+                        esb_timer_keepalive ();
+                        return 0;
+
+                case WDIOC_SETOPTIONS:
+                {
+                        if (get_user (new_options, p))
+                                return -EFAULT;
+
+                        if (new_options & WDIOS_DISABLECARD) {
+                                esb_timer_stop ();
+                                retval = 0;
+                        }
+
+                        if (new_options & WDIOS_ENABLECARD) {
+                                esb_timer_keepalive ();
+                                esb_timer_start ();
+                                retval = 0;
+                        }
+
+                        return retval;
+                }
+
+                case WDIOC_SETTIMEOUT:
+                {
+                        if (get_user(new_heartbeat, p))
+                                return -EFAULT;
+
+                        if (esb_timer_set_heartbeat(new_heartbeat))
+                            return -EINVAL;
+
+                        esb_timer_keepalive ();
+                        /* Fall */
+                }
+
+                case WDIOC_GETTIMEOUT:
+                        return put_user(heartbeat, p);
+
+                default:
+                        return -ENOIOCTLCMD;
+        }
+}
+
+/*
+ *      Notify system
+ */
+
+static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
+{
+        if (code==SYS_DOWN || code==SYS_HALT) {
+                /* Turn the WDT off */
+                esb_timer_stop ();
+        }
+
+        return NOTIFY_DONE;
+}
+
+/*
+ *      Kernel Interfaces
+ */
+
+static struct file_operations esb_fops = {
+        .owner =        THIS_MODULE,
+        .llseek =       no_llseek,
+        .write =        esb_write,
+        .ioctl =        esb_ioctl,
+        .open =         esb_open,
+        .release =      esb_release,
+};
+
+static struct miscdevice esb_miscdev = {
+        .minor =        WATCHDOG_MINOR,
+        .name =         "watchdog",
+        .fops =         &esb_fops,
+};
+
+static struct notifier_block esb_notifier = {
+        .notifier_call =        esb_notify_sys,
+};
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id esb_pci_tbl[] = {
+        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
+        { 0, },                 /* End of list */
+};
+MODULE_DEVICE_TABLE (pci, esb_pci_tbl);
+
+/*
+ *      Init & exit routines
+ */
+
+static unsigned char __init esb_getdevice (void)
+{
+       u8 val1;
+       unsigned short val2;
+
+        struct pci_dev *dev = NULL;
+        /*
+         *      Find the PCI device
+         */
+
+        for_each_pci_dev(dev) {
+                if (pci_match_id(esb_pci_tbl, dev)) {
+                        esb_pci = dev;
+                        break;
+                }
+       }
+
+        if (esb_pci) {
+               if (pci_enable_device(esb_pci)) {
+                       printk (KERN_ERR PFX "failed to enable device\n");
+                       goto err_devput;
+               }
+
+               if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {
+                       printk (KERN_ERR PFX "failed to request region\n");
+                       goto err_disable;
+               }
+
+               BASEADDR = ioremap(pci_resource_start(esb_pci, 0),
+                                  pci_resource_len(esb_pci, 0));
+               if (BASEADDR == NULL) {
+                       /* Something's wrong here, BASEADDR has to be set */
+                       printk (KERN_ERR PFX "failed to get BASEADDR\n");
+                        goto err_release;
+                }
+
+               /*
+                * The watchdog has two timers, it can be setup so that the
+                * expiry of timer1 results in an interrupt and the expiry of
+                * timer2 results in a reboot. We set it to not generate
+                * any interrupts as there is not much we can do with it
+                * right now.
+                *
+                * We also enable reboots and set the timer frequency to
+                * the PCI clock divided by 2^15 (approx 1KHz).
+                */
+               pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003);
+
+               /* Check that the WDT isn't already locked */
+               pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
+               if (val1 & ESB_WDT_LOCK)
+                       printk (KERN_WARNING PFX "nowayout already set\n");
+
+               /* Set the timer to watchdog mode and disable it for now */
+               pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
+
+               /* Check if the watchdog was previously triggered */
+               esb_unlock_registers();
+               val2 = readw(ESB_RELOAD_REG);
+               triggered = (val2 & (0x01 << 9) >> 9);
+
+               /* Reset trigger flag and timers */
+               esb_unlock_registers();
+               writew((0x11 << 8), ESB_RELOAD_REG);
+
+               /* Done */
+               return 1;
+
+err_release:
+               pci_release_region(esb_pci, 0);
+err_disable:
+               pci_disable_device(esb_pci);
+err_devput:
+               pci_dev_put(esb_pci);
+       }
+       return 0;
+}
+
+static int __init watchdog_init (void)
+{
+        int ret;
+
+        spin_lock_init(&esb_lock);
+
+        /* Check whether or not the hardware watchdog is there */
+        if (!esb_getdevice () || esb_pci == NULL)
+                return -ENODEV;
+
+        /* Check that the heartbeat value is within it's range ; if not reset to the default */
+        if (esb_timer_set_heartbeat (heartbeat)) {
+                esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT);
+                printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n",
+                      heartbeat);
+        }
+
+        ret = register_reboot_notifier(&esb_notifier);
+        if (ret != 0) {
+                printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+                        ret);
+                goto err_unmap;
+        }
+
+        ret = misc_register(&esb_miscdev);
+        if (ret != 0) {
+                printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+                        WATCHDOG_MINOR, ret);
+                goto err_notifier;
+        }
+
+        esb_timer_stop ();
+
+        printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
+                BASEADDR, heartbeat, nowayout);
+
+        return 0;
+
+err_notifier:
+        unregister_reboot_notifier(&esb_notifier);
+err_unmap:
+       iounmap(BASEADDR);
+/* err_release: */
+       pci_release_region(esb_pci, 0);
+/* err_disable: */
+       pci_disable_device(esb_pci);
+/* err_devput: */
+       pci_dev_put(esb_pci);
+        return ret;
+}
+
+static void __exit watchdog_cleanup (void)
+{
+       /* Stop the timer before we leave */
+       if (!nowayout)
+               esb_timer_stop ();
+
+       /* Deregister */
+       misc_deregister(&esb_miscdev);
+        unregister_reboot_notifier(&esb_notifier);
+       iounmap(BASEADDR);
+       pci_release_region(esb_pci, 0);
+       pci_disable_device(esb_pci);
+       pci_dev_put(esb_pci);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
+
+MODULE_AUTHOR("Ross Biro and David Härdeman");
+MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
new file mode 100644 (file)
index 0000000..294c474
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * IBM Automatic Server Restart driver.
+ *
+ * Copyright (c) 2005 Andrey Panin <pazke@donpac.ru>
+ *
+ * Based on driver written by Pete Reynolds.
+ * Copyright (c) IBM Corporation, 1998-2004.
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/dmi.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+enum {
+       ASMTYPE_UNKNOWN,
+       ASMTYPE_TOPAZ,
+       ASMTYPE_JASPER,
+       ASMTYPE_PEARL,
+       ASMTYPE_JUNIPER,
+       ASMTYPE_SPRUCE,
+};
+
+#define PFX "ibmasr: "
+
+#define TOPAZ_ASR_REG_OFFSET   4
+#define TOPAZ_ASR_TOGGLE       0x40
+#define TOPAZ_ASR_DISABLE      0x80
+
+/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */
+#define PEARL_BASE     0xe04
+#define PEARL_WRITE    0xe06
+#define PEARL_READ     0xe07
+
+#define PEARL_ASR_DISABLE_MASK 0x80    /* bit 7: disable = 1, enable = 0 */
+#define PEARL_ASR_TOGGLE_MASK  0x40    /* bit 6: 0, then 1, then 0 */
+
+/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */
+#define JASPER_ASR_REG_OFFSET  0x38
+
+#define JASPER_ASR_DISABLE_MASK        0x01    /* bit 0: disable = 1, enable = 0 */
+#define JASPER_ASR_TOGGLE_MASK 0x02    /* bit 1: 0, then 1, then 0 */
+
+#define JUNIPER_BASE_ADDRESS   0x54b   /* Base address of Juniper ASR */
+#define JUNIPER_ASR_DISABLE_MASK 0x01  /* bit 0: disable = 1 enable = 0 */
+#define JUNIPER_ASR_TOGGLE_MASK        0x02    /* bit 1: 0, then 1, then 0 */
+
+#define SPRUCE_BASE_ADDRESS    0x118e  /* Base address of Spruce ASR */
+#define SPRUCE_ASR_DISABLE_MASK        0x01    /* bit 1: disable = 1 enable = 0 */
+#define SPRUCE_ASR_TOGGLE_MASK 0x02    /* bit 0: 0, then 1, then 0 */
+
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+static unsigned long asr_is_open;
+static char asr_expect_close;
+
+static unsigned int asr_type, asr_base, asr_length;
+static unsigned int asr_read_addr, asr_write_addr;
+static unsigned char asr_toggle_mask, asr_disable_mask;
+
+static void asr_toggle(void)
+{
+       unsigned char reg = inb(asr_read_addr);
+
+       outb(reg & ~asr_toggle_mask, asr_write_addr);
+       reg = inb(asr_read_addr);
+
+       outb(reg | asr_toggle_mask, asr_write_addr);
+       reg = inb(asr_read_addr);
+
+       outb(reg & ~asr_toggle_mask, asr_write_addr);
+       reg = inb(asr_read_addr);
+}
+
+static void asr_enable(void)
+{
+       unsigned char reg;
+
+       if (asr_type == ASMTYPE_TOPAZ) {
+               /* asr_write_addr == asr_read_addr */
+               reg = inb(asr_read_addr);
+               outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE),
+                    asr_read_addr);
+       } else {
+               /*
+                * First make sure the hardware timer is reset by toggling
+                * ASR hardware timer line.
+                */
+               asr_toggle();
+
+               reg = inb(asr_read_addr);
+               outb(reg & ~asr_disable_mask, asr_write_addr);
+       }
+       reg = inb(asr_read_addr);
+}
+
+static void asr_disable(void)
+{
+       unsigned char reg = inb(asr_read_addr);
+
+       if (asr_type == ASMTYPE_TOPAZ)
+               /* asr_write_addr == asr_read_addr */
+               outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE,
+                    asr_read_addr);
+       else {
+               outb(reg | asr_toggle_mask, asr_write_addr);
+               reg = inb(asr_read_addr);
+
+               outb(reg | asr_disable_mask, asr_write_addr);
+       }
+       reg = inb(asr_read_addr);
+}
+
+static int __init asr_get_base_address(void)
+{
+       unsigned char low, high;
+       const char *type = "";
+
+       asr_length = 1;
+
+       switch (asr_type) {
+       case ASMTYPE_TOPAZ:
+               /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */
+               outb(0x07, 0x2e);
+               outb(0x07, 0x2f);
+
+               /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */
+               outb(0x60, 0x2e);
+               high = inb(0x2f);
+
+               /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */
+               outb(0x61, 0x2e);
+               low = inb(0x2f);
+
+               asr_base = (high << 16) | low;
+               asr_read_addr = asr_write_addr =
+                       asr_base + TOPAZ_ASR_REG_OFFSET;
+               asr_length = 5;
+
+               break;
+
+       case ASMTYPE_JASPER:
+               type = "Jaspers ";
+
+               /* FIXME: need to use pci_config_lock here, but it's not exported */
+
+/*             spin_lock_irqsave(&pci_config_lock, flags);*/
+
+               /* Select the SuperIO chip in the PCI I/O port register */
+               outl(0x8000f858, 0xcf8);
+
+               /*
+                * Read the base address for the SuperIO chip.
+                * Only the lower 16 bits are valid, but the address is word
+                * aligned so the last bit must be masked off.
+                */
+               asr_base = inl(0xcfc) & 0xfffe;
+
+/*             spin_unlock_irqrestore(&pci_config_lock, flags);*/
+
+               asr_read_addr = asr_write_addr =
+                       asr_base + JASPER_ASR_REG_OFFSET;
+               asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
+               asr_disable_mask = JASPER_ASR_DISABLE_MASK;
+               asr_length = JASPER_ASR_REG_OFFSET + 1;
+
+               break;
+
+       case ASMTYPE_PEARL:
+               type = "Pearls ";
+               asr_base = PEARL_BASE;
+               asr_read_addr = PEARL_READ;
+               asr_write_addr = PEARL_WRITE;
+               asr_toggle_mask = PEARL_ASR_TOGGLE_MASK;
+               asr_disable_mask = PEARL_ASR_DISABLE_MASK;
+               asr_length = 4;
+               break;
+
+       case ASMTYPE_JUNIPER:
+               type = "Junipers ";
+               asr_base = JUNIPER_BASE_ADDRESS;
+               asr_read_addr = asr_write_addr = asr_base;
+               asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK;
+               asr_disable_mask = JUNIPER_ASR_DISABLE_MASK;
+               break;
+
+       case ASMTYPE_SPRUCE:
+               type = "Spruce's ";
+               asr_base = SPRUCE_BASE_ADDRESS;
+               asr_read_addr = asr_write_addr = asr_base;
+               asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK;
+               asr_disable_mask = SPRUCE_ASR_DISABLE_MASK;
+               break;
+       }
+
+       if (!request_region(asr_base, asr_length, "ibmasr")) {
+               printk(KERN_ERR PFX "address %#x already in use\n",
+                       asr_base);
+               return -EBUSY;
+       }
+
+       printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);
+
+       return 0;
+}
+
+
+static ssize_t asr_write(struct file *file, const char __user *buf,
+                        size_t count, loff_t *ppos)
+{
+       if (count) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /* In case it was set long ago */
+                       asr_expect_close = 0;
+
+                       for (i = 0; i != count; i++) {
+                               char c;
+                               if (get_user(c, buf + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       asr_expect_close = 42;
+                       }
+               }
+               asr_toggle();
+       }
+       return count;
+}
+
+static int asr_ioctl(struct inode *inode, struct file *file,
+                    unsigned int cmd, unsigned long arg)
+{
+       static const struct watchdog_info ident = {
+               .options =      WDIOF_KEEPALIVEPING | 
+                               WDIOF_MAGICCLOSE,
+               .identity =     "IBM ASR"
+       };
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int heartbeat;
+
+       switch (cmd) {
+               case WDIOC_GETSUPPORT:
+                       return copy_to_user(argp, &ident, sizeof(ident)) ?
+                               -EFAULT : 0;
+
+               case WDIOC_GETSTATUS:
+               case WDIOC_GETBOOTSTATUS:
+                       return put_user(0, p);
+
+               case WDIOC_KEEPALIVE:
+                       asr_toggle();
+                       return 0;
+
+               /*
+                * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
+                * and WDIOC_GETTIMEOUT always returns 256.
+                */
+               case WDIOC_GETTIMEOUT:
+                       heartbeat = 256;
+                       return put_user(heartbeat, p);
+
+               case WDIOC_SETOPTIONS: {
+                       int new_options, retval = -EINVAL;
+
+                       if (get_user(new_options, p))
+                               return -EFAULT;
+
+                       if (new_options & WDIOS_DISABLECARD) {
+                               asr_disable();
+                               retval = 0;
+                       }
+
+                       if (new_options & WDIOS_ENABLECARD) {
+                               asr_enable();
+                               asr_toggle();
+                               retval = 0;
+                       }
+
+                       return retval;
+               }
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static int asr_open(struct inode *inode, struct file *file)
+{
+       if(test_and_set_bit(0, &asr_is_open))
+               return -EBUSY;
+
+       asr_toggle();
+       asr_enable();
+
+       return nonseekable_open(inode, file);
+}
+
+static int asr_release(struct inode *inode, struct file *file)
+{
+       if (asr_expect_close == 42)
+               asr_disable();
+       else {
+               printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
+               asr_toggle();
+       }
+       clear_bit(0, &asr_is_open);
+       asr_expect_close = 0;
+       return 0;
+}
+
+static struct file_operations asr_fops = {
+       .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
+       .write =        asr_write,
+       .ioctl =        asr_ioctl,
+       .open =         asr_open,
+       .release =      asr_release,
+};
+
+static struct miscdevice asr_miscdev = {
+       .minor =        WATCHDOG_MINOR,
+       .name =         "watchdog",
+       .fops =         &asr_fops,
+};
+
+
+struct ibmasr_id {
+       const char *desc;
+       int type;
+};
+
+static struct ibmasr_id __initdata ibmasr_id_table[] = {
+       { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },
+       { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },
+       { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },
+       { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER },
+       { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE },
+       { NULL }
+};
+
+static int __init ibmasr_init(void)
+{
+       struct ibmasr_id *id;
+       int rc;
+
+       for (id = ibmasr_id_table; id->desc; id++) {
+               if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) {
+                       asr_type = id->type;
+                       break;
+               }
+       }
+
+       if (!asr_type)
+               return -ENODEV;
+
+       rc = misc_register(&asr_miscdev);
+       if (rc < 0) {
+               printk(KERN_ERR PFX "failed to register misc device\n");
+               return rc;
+       }
+
+       rc = asr_get_base_address();
+       if (rc) {
+               misc_deregister(&asr_miscdev);
+               return rc;
+       }
+
+       return 0;
+}
+
+static void __exit ibmasr_exit(void)
+{
+       if (!nowayout)
+               asr_disable();
+
+       misc_deregister(&asr_miscdev);
+
+       release_region(asr_base, asr_length);
+}
+
+module_init(ibmasr_init);
+module_exit(ibmasr_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
+MODULE_AUTHOR("Andrey Panin");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
new file mode 100644 (file)
index 0000000..c694eee
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ *     Watchdog driver for the mpcore watchdog timer
+ *
+ *     (c) Copyright 2004 ARM Limited
+ *
+ *     Based on the SoftDog driver:
+ *     (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *                             http://www.redhat.com
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ *     warranty for any of this software. This material is provided
+ *     "AS-IS" and at no charge.
+ *
+ *     (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <asm/uaccess.h>
+
+struct mpcore_wdt {
+       unsigned long   timer_alive;
+       struct device   *dev;
+       void __iomem    *base;
+       int             irq;
+       unsigned int    perturb;
+       char            expect_close;
+};
+
+static struct platform_device *mpcore_wdt_dev;
+
+extern unsigned int mpcore_timer_rate;
+
+#define TIMER_MARGIN   60
+static int mpcore_margin = TIMER_MARGIN;
+module_param(mpcore_margin, int, 0);
+MODULE_PARM_DESC(mpcore_margin, "MPcore timer margin in seconds. (0<mpcore_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define ONLY_TESTING   0
+static int mpcore_noboot = ONLY_TESTING;
+module_param(mpcore_noboot, int, 0);
+MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, set to 1 to ignore reboots, 0 to reboot (default=" __MODULE_STRING(ONLY_TESTING) ")");
+
+/*
+ *     This is the interrupt handler.  Note that we only use this
+ *     in testing mode, so don't actually do a reboot here.
+ */
+static irqreturn_t mpcore_wdt_fire(int irq, void *arg, struct pt_regs *regs)
+{
+       struct mpcore_wdt *wdt = arg;
+
+       /* Check it really was our interrupt */
+       if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
+               dev_printk(KERN_CRIT, wdt->dev, "Triggered - Reboot ignored.\n");
+
+               /* Clear the interrupt on the watchdog */
+               writel(1, wdt->base + TWD_WDOG_INTSTAT);
+
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+/*
+ *     mpcore_wdt_keepalive - reload the timer
+ *
+ *     Note that the spec says a DIFFERENT value must be written to the reload
+ *     register each time.  The "perturb" variable deals with this by adding 1
+ *     to the count every other time the function is called.
+ */
+static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt)
+{
+       unsigned int count;
+
+       /* Assume prescale is set to 256 */
+       count = (mpcore_timer_rate / 256) * mpcore_margin;
+
+       /* Reload the counter */
+       writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
+
+       wdt->perturb = wdt->perturb ? 0 : 1;
+}
+
+static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
+{
+       writel(0x12345678, wdt->base + TWD_WDOG_DISABLE);
+       writel(0x87654321, wdt->base + TWD_WDOG_DISABLE);
+       writel(0x0, wdt->base + TWD_WDOG_CONTROL);
+}
+
+static void mpcore_wdt_start(struct mpcore_wdt *wdt)
+{
+       dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
+
+       /* This loads the count register but does NOT start the count yet */
+       mpcore_wdt_keepalive(wdt);
+
+       if (mpcore_noboot) {
+               /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */
+               writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL);
+       } else {
+               /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
+               writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
+       }
+}
+
+static int mpcore_wdt_set_heartbeat(int t)
+{
+       if (t < 0x0001 || t > 0xFFFF)
+               return -EINVAL;
+
+       mpcore_margin = t;
+       return 0;
+}
+
+/*
+ *     /dev/watchdog handling
+ */
+static int mpcore_wdt_open(struct inode *inode, struct file *file)
+{
+       struct mpcore_wdt *wdt = dev_get_drvdata(&mpcore_wdt_dev->dev);
+
+       if (test_and_set_bit(0, &wdt->timer_alive))
+               return -EBUSY;
+
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       file->private_data = wdt;
+
+       /*
+        *      Activate timer
+        */
+       mpcore_wdt_start(wdt);
+
+       return nonseekable_open(inode, file);
+}
+
+static int mpcore_wdt_release(struct inode *inode, struct file *file)
+{
+       struct mpcore_wdt *wdt = file->private_data;
+
+       /*
+        *      Shut off the timer.
+        *      Lock it in if it's a module and we set nowayout
+        */
+       if (wdt->expect_close == 42) {
+               mpcore_wdt_stop(wdt);
+       } else {
+               dev_printk(KERN_CRIT, wdt->dev, "unexpected close, not stopping watchdog!\n");
+               mpcore_wdt_keepalive(wdt);
+       }
+       clear_bit(0, &wdt->timer_alive);
+       wdt->expect_close = 0;
+       return 0;
+}
+
+static ssize_t mpcore_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+       struct mpcore_wdt *wdt = file->private_data;
+
+       /*  Can't seek (pwrite) on this device  */
+       if (ppos != &file->f_pos)
+               return -ESPIPE;
+
+       /*
+        *      Refresh the timer.
+        */
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /* In case it was set long ago */
+                       wdt->expect_close = 0;
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       wdt->expect_close = 42;
+                       }
+               }
+               mpcore_wdt_keepalive(wdt);
+       }
+       return len;
+}
+
+static struct watchdog_info ident = {
+       .options                = WDIOF_SETTIMEOUT |
+                                 WDIOF_KEEPALIVEPING |
+                                 WDIOF_MAGICCLOSE,
+       .identity               = "MPcore Watchdog",
+};
+
+static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
+                            unsigned int cmd, unsigned long arg)
+{
+       struct mpcore_wdt *wdt = file->private_data;
+       int ret;
+       union {
+               struct watchdog_info ident;
+               int i;
+       } uarg;
+
+       if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
+               return -ENOIOCTLCMD;
+
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
+               ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
+               if (ret)
+                       return -EFAULT;
+       }
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               uarg.ident = ident;
+               ret = 0;
+               break;
+
+       case WDIOC_SETOPTIONS:
+               ret = -EINVAL;
+               if (uarg.i & WDIOS_DISABLECARD) {
+                       mpcore_wdt_stop(wdt);
+                       ret = 0;
+               }
+               if (uarg.i & WDIOS_ENABLECARD) {
+                       mpcore_wdt_start(wdt);
+                       ret = 0;
+               }
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               uarg.i = 0;
+               ret = 0;
+               break;
+
+       case WDIOC_KEEPALIVE:
+               mpcore_wdt_keepalive(wdt);
+               ret = 0;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = mpcore_wdt_set_heartbeat(uarg.i);
+               if (ret)
+                       break;
+
+               mpcore_wdt_keepalive(wdt);
+               /* Fall */
+       case WDIOC_GETTIMEOUT:
+               uarg.i = mpcore_margin;
+               ret = 0;
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+               ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd));
+               if (ret)
+                       ret = -EFAULT;
+       }
+       return ret;
+}
+
+/*
+ *     System shutdown handler.  Turn off the watchdog if we're
+ *     restarting or halting the system.
+ */
+static void mpcore_wdt_shutdown(struct device *_dev)
+{
+       struct mpcore_wdt *wdt = dev_get_drvdata(_dev);
+
+       if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
+               mpcore_wdt_stop(wdt);
+}
+
+/*
+ *     Kernel Interfaces
+ */
+static struct file_operations mpcore_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = mpcore_wdt_write,
+       .ioctl          = mpcore_wdt_ioctl,
+       .open           = mpcore_wdt_open,
+       .release        = mpcore_wdt_release,
+};
+
+static struct miscdevice mpcore_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &mpcore_wdt_fops,
+};
+
+static int __devinit mpcore_wdt_probe(struct device *_dev)
+{
+       struct platform_device *dev = to_platform_device(_dev);
+       struct mpcore_wdt *wdt;
+       struct resource *res;
+       int ret;
+
+       /* We only accept one device, and it must have an id of -1 */
+       if (dev->id != -1)
+               return -ENODEV;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENODEV;
+               goto err_out;
+       }
+
+       wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
+       if (!wdt) {
+               ret = -ENOMEM;
+               goto err_out;
+       }
+       memset(wdt, 0, sizeof(struct mpcore_wdt));
+
+       wdt->dev = &dev->dev;
+       wdt->irq = platform_get_irq(dev, 0);
+       wdt->base = ioremap(res->start, res->end - res->start + 1);
+       if (!wdt->base) {
+               ret = -ENOMEM;
+               goto err_free;
+       }
+
+       mpcore_wdt_miscdev.dev = &dev->dev;
+       ret = misc_register(&mpcore_wdt_miscdev);
+       if (ret) {
+               dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n",
+                          WATCHDOG_MINOR, ret);
+               goto err_misc;
+       }
+
+       ret = request_irq(wdt->irq, mpcore_wdt_fire, SA_INTERRUPT, "mpcore_wdt", wdt);
+       if (ret) {
+               dev_printk(KERN_ERR, _dev, "cannot register IRQ%d for watchdog\n", wdt->irq);
+               goto err_irq;
+       }
+
+       mpcore_wdt_stop(wdt);
+       dev_set_drvdata(&dev->dev, wdt);
+       mpcore_wdt_dev = dev;
+
+       return 0;
+
+ err_irq:
+       misc_deregister(&mpcore_wdt_miscdev);
+ err_misc:
+       iounmap(wdt->base);
+ err_free:
+       kfree(wdt);
+ err_out:
+       return ret;
+}
+
+static int __devexit mpcore_wdt_remove(struct device *dev)
+{
+       struct mpcore_wdt *wdt = dev_get_drvdata(dev);
+
+       dev_set_drvdata(dev, NULL);
+
+       misc_deregister(&mpcore_wdt_miscdev);
+
+       mpcore_wdt_dev = NULL;
+
+       free_irq(wdt->irq, wdt);
+       iounmap(wdt->base);
+       kfree(wdt);
+       return 0;
+}
+
+static struct device_driver mpcore_wdt_driver = {
+       .name           = "mpcore_wdt",
+       .bus            = &platform_bus_type,
+       .probe          = mpcore_wdt_probe,
+       .remove         = __devexit_p(mpcore_wdt_remove),
+       .shutdown       = mpcore_wdt_shutdown,
+};
+
+static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n";
+
+static int __init mpcore_wdt_init(void)
+{
+       /*
+        * Check that the margin value is within it's range;
+        * if not reset to the default
+        */
+       if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
+               mpcore_wdt_set_heartbeat(TIMER_MARGIN);
+               printk(KERN_INFO "mpcore_margin value must be 0<mpcore_margin<65536, using %d\n",
+                       TIMER_MARGIN);
+       }
+
+       printk(banner, mpcore_noboot, mpcore_margin, nowayout);
+
+       return driver_register(&mpcore_wdt_driver);
+}
+
+static void __exit mpcore_wdt_exit(void)
+{
+       driver_unregister(&mpcore_wdt_driver);
+}
+
+module_init(mpcore_wdt_init);
+module_exit(mpcore_wdt_exit);
+
+MODULE_AUTHOR("ARM Limited");
+MODULE_DESCRIPTION("MPcore Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
new file mode 100644 (file)
index 0000000..1436aea
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ *
+ * Platform-specific setup code should configure the dog to generate
+ * interrupt or reset as required.  This code only enables/disables
+ * and services the watchdog.
+ *
+ * Derived from mpc8xx_wdt.c, with the following copyright.
+ * 
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/mv64x60.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* MV64x60 WDC (config) register access definitions */
+#define MV64x60_WDC_CTL1_MASK  (3 << 24)
+#define MV64x60_WDC_CTL1(val)  ((val & 3) << 24)
+#define MV64x60_WDC_CTL2_MASK  (3 << 26)
+#define MV64x60_WDC_CTL2(val)  ((val & 3) << 26)
+
+/* Flags bits */
+#define MV64x60_WDOG_FLAG_OPENED       0
+#define MV64x60_WDOG_FLAG_ENABLED      1
+
+static unsigned long wdt_flags;
+static int wdt_status;
+static void __iomem *mv64x60_regs;
+static int mv64x60_wdt_timeout;
+
+static void mv64x60_wdt_reg_write(u32 val)
+{
+       /* Allow write only to CTL1 / CTL2 fields, retaining values in
+        * other fields.
+        */
+       u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
+       data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);
+       data |= val;
+       writel(data, mv64x60_regs + MV64x60_WDT_WDC);
+}
+
+static void mv64x60_wdt_service(void)
+{
+       /* Write 01 followed by 10 to CTL2 */
+       mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));
+       mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));
+}
+
+static void mv64x60_wdt_handler_disable(void)
+{
+       if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
+               /* Write 01 followed by 10 to CTL1 */
+               mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
+               mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+               printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
+       }
+}
+
+static void mv64x60_wdt_handler_enable(void)
+{
+       if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
+               /* Write 01 followed by 10 to CTL1 */
+               mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
+               mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+               printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+       }
+}
+
+static int mv64x60_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
+               return -EBUSY;
+
+       mv64x60_wdt_service();
+       mv64x60_wdt_handler_enable();
+
+       return 0;
+}
+
+static int mv64x60_wdt_release(struct inode *inode, struct file *file)
+{
+       mv64x60_wdt_service();
+
+#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
+       mv64x60_wdt_handler_disable();
+#endif
+
+       clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
+
+       return 0;
+}
+
+static ssize_t mv64x60_wdt_write(struct file *file, const char *data,
+                                size_t len, loff_t * ppos)
+{
+       if (*ppos != file->f_pos)
+               return -ESPIPE;
+
+       if (len)
+               mv64x60_wdt_service();
+
+       return len;
+}
+
+static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
+                            unsigned int cmd, unsigned long arg)
+{
+       int timeout;
+       static struct watchdog_info info = {
+               .options = WDIOF_KEEPALIVEPING,
+               .firmware_version = 0,
+               .identity = "MV64x60 watchdog",
+       };
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user((void *)arg, &info, sizeof(info)))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               if (put_user(wdt_status, (int *)arg))
+                       return -EFAULT;
+               wdt_status &= ~WDIOF_KEEPALIVEPING;
+               break;
+
+       case WDIOC_GETTEMP:
+               return -EOPNOTSUPP;
+
+       case WDIOC_SETOPTIONS:
+               return -EOPNOTSUPP;
+
+       case WDIOC_KEEPALIVE:
+               mv64x60_wdt_service();
+               wdt_status |= WDIOF_KEEPALIVEPING;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               return -EOPNOTSUPP;
+
+       case WDIOC_GETTIMEOUT:
+               timeout = mv64x60_wdt_timeout * HZ;
+               if (put_user(timeout, (int *)arg))
+                       return -EFAULT;
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+
+static struct file_operations mv64x60_wdt_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .write = mv64x60_wdt_write,
+       .ioctl = mv64x60_wdt_ioctl,
+       .open = mv64x60_wdt_open,
+       .release = mv64x60_wdt_release,
+};
+
+static struct miscdevice mv64x60_wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &mv64x60_wdt_fops,
+};
+
+static int __devinit mv64x60_wdt_probe(struct device *dev)
+{
+       struct platform_device *pd = to_platform_device(dev);
+       struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data;
+       int bus_clk = 133;
+
+       mv64x60_wdt_timeout = 10;
+       if (pdata) {
+               mv64x60_wdt_timeout = pdata->timeout;
+               bus_clk = pdata->bus_clk;
+       }
+
+       mv64x60_regs = mv64x60_get_bridge_vbase();
+
+       writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,
+              mv64x60_regs + MV64x60_WDT_WDC);
+
+       return misc_register(&mv64x60_wdt_miscdev);
+}
+
+static int __devexit mv64x60_wdt_remove(struct device *dev)
+{
+       misc_deregister(&mv64x60_wdt_miscdev);
+
+       mv64x60_wdt_service();
+       mv64x60_wdt_handler_disable();
+
+       return 0;
+}
+
+static struct device_driver mv64x60_wdt_driver = {
+       .name = MV64x60_WDT_NAME,
+       .bus = &platform_bus_type,
+       .probe = mv64x60_wdt_probe,
+       .remove = __devexit_p(mv64x60_wdt_remove),
+};
+
+static struct platform_device *mv64x60_wdt_dev;
+
+static int __init mv64x60_wdt_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "MV64x60 watchdog driver\n");
+
+       mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME,
+                                                         -1, NULL, 0);
+       if (IS_ERR(mv64x60_wdt_dev)) {
+               ret = PTR_ERR(mv64x60_wdt_dev);
+               goto out;
+       }
+
+       ret = driver_register(&mv64x60_wdt_driver);
+      out:
+       return ret;
+}
+
+static void __exit mv64x60_wdt_exit(void)
+{
+       driver_unregister(&mv64x60_wdt_driver);
+       platform_device_unregister(mv64x60_wdt_dev);
+}
+
+module_init(mv64x60_wdt_init);
+module_exit(mv64x60_wdt_exit);
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("MV64x60 watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 2b13afb09c5dfc4d601e65256ccf20bacc0641b2..5a80adbf8032565aec110a5f050d30612af62497 100644 (file)
  *     Includes, defines, variables, module parameters, ...
  */
 
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/config.h>      /* For CONFIG_WATCHDOG_NOWAYOUT/... */
+#include <linux/module.h>      /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h>       /* For standard types (like size_t) */
+#include <linux/errno.h>       /* For the -ENODEV/... values */
+#include <linux/kernel.h>      /* For printk/panic/... */
+#include <linux/delay.h>       /* For mdelay function */
+#include <linux/miscdevice.h>  /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h>    /* For the watchdog specific items */
+#include <linux/notifier.h>    /* For notifier support */
+#include <linux/reboot.h>      /* For reboot_notifier stuff */
+#include <linux/init.h>                /* For __init/__exit/... */
+#include <linux/fs.h>          /* For file operations */
+#include <linux/pci.h>         /* For pci functions */
+#include <linux/ioport.h>      /* For io-port access */
+#include <linux/spinlock.h>    /* For spin_lock/spin_unlock/... */
+
+#include <asm/uaccess.h>       /* For copy_to_user/put_user/... */
+#include <asm/io.h>            /* For inb/outb/... */
 
 /* Module and version information */
 #define WATCHDOG_VERSION "1.01"
-#define WATCHDOG_DATE "15 Mar 2005"
+#define WATCHDOG_DATE "02 Sep 2005"
 #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
 #define WATCHDOG_NAME "pcwd_pci"
 #define PFX WATCHDOG_NAME ": "
@@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
                                return -EFAULT;
 
                        if (new_options & WDIOS_DISABLECARD) {
-                               pcipcwd_stop();
+                               if (pcipcwd_stop())
+                                       return -EIO;
                                retval = 0;
                        }
 
                        if (new_options & WDIOS_ENABLECARD) {
-                               pcipcwd_start();
+                               if (pcipcwd_start())
+                                       return -EIO;
                                retval = 0;
                        }
 
index 8b292bf343c4169d57ee694fbc14f38d9c659695..3625b2601b4257603b6e0b365a012cdc06fbe2a5 100644 (file)
@@ -464,7 +464,7 @@ static void s3c2410wdt_shutdown(struct device *dev)
 static unsigned long wtcon_save;
 static unsigned long wtdat_save;
 
-static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level)
+static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level)
 {
        if (level == SUSPEND_POWER_DOWN) {
                /* Save watchdog state, and turn it off. */
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c
new file mode 100644 (file)
index 0000000..c6cbf80
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ *     SBC8360 Watchdog driver
+ *
+ *     (c) Copyright 2005 Webcon, Inc.
+ *
+ *     Based on ib700wdt.c, which is based on advantechwdt.c which is based
+ *      on acquirewdt.c which is based on wdt.c.
+ *
+ *     (c) Copyright 2001 Charles Howes <chowes@vsol.net>
+ *
+ *      Based on advantechwdt.c which is based on acquirewdt.c which
+ *       is based on wdt.c.
+ *
+ *     (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *     Based on acquirewdt.c which is based on wdt.c.
+ *     Original copyright messages:
+ *
+ *     (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *                             http://www.redhat.com
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ *     warranty for any of this software. This material is provided
+ *     "AS-IS" and at no charge.
+ *
+ *     (c) Copyright 1995    Alan Cox <alan@redhat.com>
+ *
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *           Added timeout module option to override default
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+static unsigned long sbc8360_is_open;
+static spinlock_t sbc8360_lock;
+static char expect_close;
+
+#define PFX "sbc8360: "
+
+/*
+ *
+ * Watchdog Timer Configuration
+ *
+ * The function of the watchdog timer is to reset the system automatically
+ * and is defined at I/O port 0120H and 0121H.  To enable the watchdog timer
+ * and allow the system to reset, write appropriate values from the table
+ * below to I/O port 0120H and 0121H.  To disable the timer, write a zero
+ * value to I/O port 0121H for the system to stop the watchdog function.
+ *
+ * The following describes how the timer should be programmed (according to
+ * the vendor documentation)
+ *
+ * Enabling Watchdog:
+ * MOV AX,000AH (enable, phase I)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000BH (enable, phase II)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000nH (set multiplier n, from 1-4)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000mH (set base timer m, from 0-F)
+ * MOV DX,0121H
+ * OUT DX,AX
+ *
+ * Reset timer:
+ * MOV AX,000mH (same as set base timer, above)
+ * MOV DX,0121H
+ * OUT DX,AX
+ *
+ * Disabling Watchdog:
+ * MOV AX,0000H (a zero value)
+ * MOV DX,0120H
+ * OUT DX,AX
+ *
+ * Watchdog timeout configuration values:
+ *             N
+ *     M |     1       2       3       4
+ *     --|----------------------------------
+ *     0 |     0.5s    5s      50s     100s
+ *     1 |     1s      10s     100s    200s
+ *     2 |     1.5s    15s     150s    300s
+ *     3 |     2s      20s     200s    400s
+ *     4 |     2.5s    25s     250s    500s
+ *     5 |     3s      30s     300s    600s
+ *     6 |     3.5s    35s     350s    700s
+ *     7 |     4s      40s     400s    800s
+ *     8 |     4.5s    45s     450s    900s
+ *     9 |     5s      50s     500s    1000s
+ *     A |     5.5s    55s     550s    1100s
+ *     B |     6s      60s     600s    1200s
+ *     C |     6.5s    65s     650s    1300s
+ *     D |     7s      70s     700s    1400s
+ *     E |     7.5s    75s     750s    1500s
+ *     F |     8s      80s     800s    1600s
+ *
+ * Another way to say the same things is:
+ *  For N=1, Timeout = (M+1) * 0.5s
+ *  For N=2, Timeout = (M+1) * 5s
+ *  For N=3, Timeout = (M+1) * 50s
+ *  For N=4, Timeout = (M+1) * 100s
+ *
+ */
+
+static int wd_times[64][2] = {
+       {0, 1},                 /* 0  = 0.5s */
+       {1, 1},                 /* 1  = 1s   */
+       {2, 1},                 /* 2  = 1.5s */
+       {3, 1},                 /* 3  = 2s   */
+       {4, 1},                 /* 4  = 2.5s */
+       {5, 1},                 /* 5  = 3s   */
+       {6, 1},                 /* 6  = 3.5s */
+       {7, 1},                 /* 7  = 4s   */
+       {8, 1},                 /* 8  = 4.5s */
+       {9, 1},                 /* 9  = 5s   */
+       {0xA, 1},               /* 10 = 5.5s */
+       {0xB, 1},               /* 11 = 6s   */
+       {0xC, 1},               /* 12 = 6.5s */
+       {0xD, 1},               /* 13 = 7s   */
+       {0xE, 1},               /* 14 = 7.5s */
+       {0xF, 1},               /* 15 = 8s   */
+       {0, 2},                 /* 16 = 5s  */
+       {1, 2},                 /* 17 = 10s */
+       {2, 2},                 /* 18 = 15s */
+       {3, 2},                 /* 19 = 20s */
+       {4, 2},                 /* 20 = 25s */
+       {5, 2},                 /* 21 = 30s */
+       {6, 2},                 /* 22 = 35s */
+       {7, 2},                 /* 23 = 40s */
+       {8, 2},                 /* 24 = 45s */
+       {9, 2},                 /* 25 = 50s */
+       {0xA, 2},               /* 26 = 55s */
+       {0xB, 2},               /* 27 = 60s */
+       {0xC, 2},               /* 28 = 65s */
+       {0xD, 2},               /* 29 = 70s */
+       {0xE, 2},               /* 30 = 75s */
+       {0xF, 2},               /* 31 = 80s */
+       {0, 3},                 /* 32 = 50s  */
+       {1, 3},                 /* 33 = 100s */
+       {2, 3},                 /* 34 = 150s */
+       {3, 3},                 /* 35 = 200s */
+       {4, 3},                 /* 36 = 250s */
+       {5, 3},                 /* 37 = 300s */
+       {6, 3},                 /* 38 = 350s */
+       {7, 3},                 /* 39 = 400s */
+       {8, 3},                 /* 40 = 450s */
+       {9, 3},                 /* 41 = 500s */
+       {0xA, 3},               /* 42 = 550s */
+       {0xB, 3},               /* 43 = 600s */
+       {0xC, 3},               /* 44 = 650s */
+       {0xD, 3},               /* 45 = 700s */
+       {0xE, 3},               /* 46 = 750s */
+       {0xF, 3},               /* 47 = 800s */
+       {0, 4},                 /* 48 = 100s */
+       {1, 4},                 /* 49 = 200s */
+       {2, 4},                 /* 50 = 300s */
+       {3, 4},                 /* 51 = 400s */
+       {4, 4},                 /* 52 = 500s */
+       {5, 4},                 /* 53 = 600s */
+       {6, 4},                 /* 54 = 700s */
+       {7, 4},                 /* 55 = 800s */
+       {8, 4},                 /* 56 = 900s */
+       {9, 4},                 /* 57 = 1000s */
+       {0xA, 4},               /* 58 = 1100s */
+       {0xB, 4},               /* 59 = 1200s */
+       {0xC, 4},               /* 60 = 1300s */
+       {0xD, 4},               /* 61 = 1400s */
+       {0xE, 4},               /* 62 = 1500s */
+       {0xF, 4}                /* 63 = 1600s */
+};
+
+#define SBC8360_ENABLE 0x120
+#define SBC8360_BASETIME 0x121
+
+static int timeout = 27;
+static int wd_margin = 0xB;
+static int wd_multiplier = 2;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(timeout, int, 27);
+MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+                "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ *     Kernel methods.
+ */
+
+/* Activate and pre-configure watchdog */
+static void sbc8360_activate(void)
+{
+       /* Enable the watchdog */
+       outb(0x0A, SBC8360_ENABLE);
+       msleep_interruptible(100);
+       outb(0x0B, SBC8360_ENABLE);
+       msleep_interruptible(100);
+       /* Set timeout multiplier */
+       outb(wd_multiplier, SBC8360_ENABLE);
+       msleep_interruptible(100);
+       /* Nothing happens until first sbc8360_ping() */
+}
+
+/* Kernel pings watchdog */
+static void sbc8360_ping(void)
+{
+       /* Write the base timer register */
+       outb(wd_margin, SBC8360_BASETIME);
+}
+
+/* Userspace pings kernel driver, or requests clean close */
+static ssize_t sbc8360_write(struct file *file, const char __user * buf,
+                            size_t count, loff_t * ppos)
+{
+       if (count) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /* In case it was set long ago */
+                       expect_close = 0;
+
+                       for (i = 0; i != count; i++) {
+                               char c;
+                               if (get_user(c, buf + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       expect_close = 42;
+                       }
+               }
+               sbc8360_ping();
+       }
+       return count;
+}
+
+static int sbc8360_open(struct inode *inode, struct file *file)
+{
+       spin_lock(&sbc8360_lock);
+       if (test_and_set_bit(0, &sbc8360_is_open)) {
+               spin_unlock(&sbc8360_lock);
+               return -EBUSY;
+       }
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       /* Activate and ping once to start the countdown */
+       spin_unlock(&sbc8360_lock);
+       sbc8360_activate();
+       sbc8360_ping();
+       return nonseekable_open(inode, file);
+}
+
+static int sbc8360_close(struct inode *inode, struct file *file)
+{
+       spin_lock(&sbc8360_lock);
+       if (expect_close == 42)
+               outb(0, SBC8360_ENABLE);
+       else
+               printk(KERN_CRIT PFX
+                      "SBC8360 device closed unexpectedly.  SBC8360 will not stop!\n");
+
+       clear_bit(0, &sbc8360_is_open);
+       expect_close = 0;
+       spin_unlock(&sbc8360_lock);
+       return 0;
+}
+
+/*
+ *     Notifier for system down
+ */
+
+static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,
+                             void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT) {
+               /* Disable the SBC8360 Watchdog */
+               outb(0, SBC8360_ENABLE);
+       }
+       return NOTIFY_DONE;
+}
+
+/*
+ *     Kernel Interfaces
+ */
+
+static struct file_operations sbc8360_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .write = sbc8360_write,
+       .open = sbc8360_open,
+       .release = sbc8360_close,
+};
+
+static struct miscdevice sbc8360_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &sbc8360_fops,
+};
+
+/*
+ *     The SBC8360 needs to learn about soft shutdowns in order to
+ *     turn the timebomb registers off.
+ */
+
+static struct notifier_block sbc8360_notifier = {
+       .notifier_call = sbc8360_notify_sys,
+};
+
+static int __init sbc8360_init(void)
+{
+       int res;
+       unsigned long int mseconds = 60000;
+
+       spin_lock_init(&sbc8360_lock);
+       res = misc_register(&sbc8360_miscdev);
+       if (res) {
+               printk(KERN_ERR PFX "failed to register misc device\n");
+               goto out_nomisc;
+       }
+
+       if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
+               printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
+                      SBC8360_ENABLE);
+               res = -EIO;
+               goto out_noenablereg;
+       }
+       if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
+               printk(KERN_ERR PFX
+                      "BASETIME method I/O %X is not available.\n",
+                      SBC8360_BASETIME);
+               res = -EIO;
+               goto out_nobasetimereg;
+       }
+
+       res = register_reboot_notifier(&sbc8360_notifier);
+       if (res) {
+               printk(KERN_ERR PFX "Failed to register reboot notifier.\n");
+               goto out_noreboot;
+       }
+
+       if (timeout < 0 || timeout > 63) {
+               printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+               res = -EINVAL;
+               goto out_noreboot;
+       }
+
+       wd_margin = wd_times[timeout][0];
+       wd_multiplier = wd_times[timeout][1];
+
+       if (wd_multiplier == 1)
+               mseconds = (wd_margin + 1) * 500;
+       else if (wd_multiplier == 2)
+               mseconds = (wd_margin + 1) * 5000;
+       else if (wd_multiplier == 3)
+               mseconds = (wd_margin + 1) * 50000;
+       else if (wd_multiplier == 4)
+               mseconds = (wd_margin + 1) * 100000;
+
+       /* My kingdom for the ability to print "0.5 seconds" in the kernel! */
+       printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);
+
+       return 0;
+
+      out_noreboot:
+       release_region(SBC8360_ENABLE, 1);
+       release_region(SBC8360_BASETIME, 1);
+      out_noenablereg:
+      out_nobasetimereg:
+       misc_deregister(&sbc8360_miscdev);
+      out_nomisc:
+       return res;
+}
+
+static void __exit sbc8360_exit(void)
+{
+       misc_deregister(&sbc8360_miscdev);
+       unregister_reboot_notifier(&sbc8360_notifier);
+       release_region(SBC8360_ENABLE, 1);
+       release_region(SBC8360_BASETIME, 1);
+}
+
+module_init(sbc8360_init);
+module_exit(sbc8360_exit);
+
+MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>");
+MODULE_DESCRIPTION("SBC8360 watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+/* end of sbc8360.c */
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
new file mode 100644 (file)
index 0000000..a7ff64c
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ *     W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip
+ *
+ *     (c) Copyright 2005  Jose Goncalves <jose.goncalves@inov.pt>
+ *
+ *      Based on w83877f_wdt.c by Scott Jennings,
+ *           and wdt977.c by Woody Suwalski
+ *
+ *                     -----------------------
+ *
+ *     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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define WATCHDOG_VERSION  "1.00"
+#define WATCHDOG_NAME     "W83977F WDT"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+
+#define IO_INDEX_PORT     0x3F0
+#define IO_DATA_PORT      (IO_INDEX_PORT+1)
+
+#define UNLOCK_DATA       0x87
+#define LOCK_DATA         0xAA
+#define DEVICE_REGISTER   0x07
+
+#define        DEFAULT_TIMEOUT   45            /* default timeout in seconds */
+
+static int timeout = DEFAULT_TIMEOUT;
+static int timeoutW;                   /* timeout in watchdog counter units */
+static unsigned long timer_alive;
+static int testmode;
+static char expect_close;
+static spinlock_t spinlock;
+
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Start the watchdog
+ */
+
+static int wdt_start(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
+       /* Unlock the SuperIO chip */
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+       /*
+        * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
+        * F2 has the timeout in watchdog counter units.
+        * F3 is set to enable watchdog LED blink at timeout.
+        * F4 is used to just clear the TIMEOUT'ed state (bit 0).
+        */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF2,IO_INDEX_PORT);
+       outb_p(timeoutW,IO_DATA_PORT);
+       outb_p(0xF3,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF4,IO_INDEX_PORT);
+       outb_p(0x00,IO_DATA_PORT);
+
+       /* Set device Aux2 active */
+       outb_p(0x30,IO_INDEX_PORT);
+       outb_p(0x01,IO_DATA_PORT);
+
+       /* 
+        * Select device Aux1 (dev=7) to set GP16 as the watchdog output
+        * (in reg E6) and GP13 as the watchdog LED output (in reg E3).
+        * Map GP16 at pin 119.
+        * In test mode watch the bit 0 on F4 to indicate "triggered" or
+        * check watchdog LED on SBC.
+        */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x07,IO_DATA_PORT);
+       if (!testmode)
+       {
+               unsigned pin_map;
+
+               outb_p(0xE6,IO_INDEX_PORT);
+               outb_p(0x0A,IO_DATA_PORT);
+               outb_p(0x2C,IO_INDEX_PORT);
+               pin_map = inb_p(IO_DATA_PORT);
+               pin_map |= 0x10;
+               pin_map &= ~(0x20);
+               outb_p(0x2C,IO_INDEX_PORT);
+               outb_p(pin_map,IO_DATA_PORT);
+       }
+       outb_p(0xE3,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+
+       /* Set device Aux1 active */
+       outb_p(0x30,IO_INDEX_PORT);
+       outb_p(0x01,IO_DATA_PORT);
+
+       /* Lock the SuperIO chip */
+       outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       printk(KERN_INFO PFX "activated.\n");
+
+       return 0;
+}
+
+/*
+ * Stop the watchdog
+ */
+
+static int wdt_stop(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
+       /* Unlock the SuperIO chip */
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+       /* 
+        * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
+        * F2 is reset to its default value (watchdog timer disabled).
+        * F3 is reset to its default state.
+        * F4 clears the TIMEOUT'ed state (bit 0) - back to default.
+        */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF2,IO_INDEX_PORT);
+       outb_p(0xFF,IO_DATA_PORT);
+       outb_p(0xF3,IO_INDEX_PORT);
+       outb_p(0x00,IO_DATA_PORT);
+       outb_p(0xF4,IO_INDEX_PORT);
+       outb_p(0x00,IO_DATA_PORT);
+       outb_p(0xF2,IO_INDEX_PORT);
+       outb_p(0x00,IO_DATA_PORT);
+
+       /*
+        * Select device Aux1 (dev=7) to set GP16 (in reg E6) and 
+        * Gp13 (in reg E3) as inputs.
+        */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x07,IO_DATA_PORT);
+       if (!testmode)
+       {
+               outb_p(0xE6,IO_INDEX_PORT);
+               outb_p(0x01,IO_DATA_PORT);
+       }
+       outb_p(0xE3,IO_INDEX_PORT);
+       outb_p(0x01,IO_DATA_PORT);
+
+       /* Lock the SuperIO chip */
+       outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       printk(KERN_INFO PFX "shutdown.\n");
+
+       return 0;
+}
+
+/*
+ * Send a keepalive ping to the watchdog
+ * This is done by simply re-writing the timeout to reg. 0xF2
+ */
+
+static int wdt_keepalive(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
+       /* Unlock the SuperIO chip */
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+       /* Select device Aux2 (device=8) to kick watchdog reg F2 */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF2,IO_INDEX_PORT);
+       outb_p(timeoutW,IO_DATA_PORT);
+
+       /* Lock the SuperIO chip */
+       outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       return 0;
+}
+
+/*
+ * Set the watchdog timeout value
+ */
+
+static int wdt_set_timeout(int t)
+{
+       int tmrval;
+
+       /*
+        * Convert seconds to watchdog counter time units, rounding up.
+        * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup 
+        * value. This information is supplied in the PCM-5335 manual and was
+        * checked by me on a real board. This is a bit strange because W83977f
+        * datasheet says counter unit is in minutes!
+        */
+       if (t < 15)
+               return -EINVAL;
+
+       tmrval = ((t + 15) + 29) / 30;
+
+       if (tmrval > 255)
+               return -EINVAL;
+
+       /*
+        * timeout is the timeout in seconds, 
+        * timeoutW is the timeout in watchdog counter units.
+        */
+       timeoutW = tmrval;
+       timeout = (timeoutW * 30) - 15;
+       return 0;
+}
+
+/*
+ * Get the watchdog status
+ */
+
+static int wdt_get_status(int *status)
+{
+       int new_status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
+       /* Unlock the SuperIO chip */
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+       /* Select device Aux2 (device=8) to read watchdog reg F4 */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF4,IO_INDEX_PORT);
+       new_status = inb_p(IO_DATA_PORT);
+
+       /* Lock the SuperIO chip */
+       outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       *status = 0;
+       if (new_status & 1)
+               *status |= WDIOF_CARDRESET;
+
+       return 0;
+}
+
+
+/*
+ *     /dev/watchdog handling
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+       /* If the watchdog is alive we don't need to start it again */
+       if( test_and_set_bit(0, &timer_alive) )
+               return -EBUSY;
+
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       wdt_start();
+       return nonseekable_open(inode, file);
+}
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+       /*
+        * Shut off the timer.
+        * Lock it in if it's a module and we set nowayout
+        */
+       if (expect_close == 42)
+       {
+               wdt_stop();
+               clear_bit(0, &timer_alive);
+       } else {
+               wdt_keepalive();
+               printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
+       }
+       expect_close = 0;
+       return 0;
+}
+
+/*
+ *      wdt_write:
+ *      @file: file handle to the watchdog
+ *      @buf: buffer to write (unused as data does not matter here
+ *      @count: count of bytes
+ *      @ppos: pointer to the position to write. No seeks allowed
+ *
+ *      A write to a watchdog device is defined as a keepalive signal. Any
+ *      write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       /* See if we got the magic character 'V' and reload the timer */
+       if(count)
+       {
+               if (!nowayout)
+               {
+                       size_t ofs;
+
+                       /* note: just in case someone wrote the magic character long ago */
+                       expect_close = 0;
+
+                       /* scan to see whether or not we got the magic character */
+                       for(ofs = 0; ofs != count; ofs++)
+                       {
+                               char c;
+                               if (get_user(c, buf + ofs))
+                                       return -EFAULT;
+                               if (c == 'V') {
+                                       expect_close = 42;
+                               }
+                       }
+               }
+
+               /* someone wrote to us, we should restart timer */
+               wdt_keepalive();
+       }
+       return count;
+}
+
+/*
+ *      wdt_ioctl:
+ *      @inode: inode of the device
+ *      @file: file handle to the device
+ *      @cmd: watchdog command
+ *      @arg: argument pointer
+ *
+ *      The watchdog API defines a common set of functions for all watchdogs
+ *      according to their available features.
+ */
+
+static struct watchdog_info ident = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+       .firmware_version =     1,
+       .identity = WATCHDOG_NAME,
+};
+
+static int wdt_ioctl(struct inode *inode, struct file *file,
+       unsigned int cmd, unsigned long arg)
+{
+       int status;
+       int new_options, retval = -EINVAL;
+       int new_timeout;
+       union {
+               struct watchdog_info __user *ident;
+               int __user *i;
+       } uarg;
+
+       uarg.i = (int __user *)arg;
+
+       switch(cmd)
+       {
+       default:
+               return -ENOIOCTLCMD;
+
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+               wdt_get_status(&status);
+               return put_user(status, uarg.i);
+
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, uarg.i);
+
+       case WDIOC_KEEPALIVE:
+               wdt_keepalive();
+               return 0;
+
+       case WDIOC_SETOPTIONS:
+               if (get_user (new_options, uarg.i))
+                       return -EFAULT;
+
+               if (new_options & WDIOS_DISABLECARD) {
+                       wdt_stop();
+                       retval = 0;
+               }
+
+               if (new_options & WDIOS_ENABLECARD) {
+                       wdt_start();
+                       retval = 0;
+               }
+
+               return retval;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_timeout, uarg.i))
+                       return -EFAULT;
+
+               if (wdt_set_timeout(new_timeout))
+                   return -EINVAL;
+
+               wdt_keepalive();
+               /* Fall */
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(timeout, uarg.i);
+
+       }
+}
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+       void *unused)
+{
+       if (code==SYS_DOWN || code==SYS_HALT)
+               wdt_stop();
+       return NOTIFY_DONE;
+}
+
+static struct file_operations wdt_fops=
+{
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = wdt_write,
+       .ioctl          = wdt_ioctl,
+       .open           = wdt_open,
+       .release        = wdt_release,
+};
+
+static struct miscdevice wdt_miscdev=
+{
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &wdt_fops,
+};
+
+static struct notifier_block wdt_notifier = {
+       .notifier_call = wdt_notify_sys,
+};
+
+static int __init w83977f_wdt_init(void)
+{
+       int rc;
+
+        printk(KERN_INFO PFX DRIVER_VERSION);
+
+       spin_lock_init(&spinlock);
+
+       /*
+        * Check that the timeout value is within it's range ; 
+        * if not reset to the default
+        */
+       if (wdt_set_timeout(timeout)) {
+               wdt_set_timeout(DEFAULT_TIMEOUT);
+               printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n",
+                       DEFAULT_TIMEOUT);
+       }
+
+       if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
+       {
+               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+                       IO_INDEX_PORT);
+               rc = -EIO;
+               goto err_out;
+       }
+
+       rc = misc_register(&wdt_miscdev);
+       if (rc)
+       {
+               printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+                       wdt_miscdev.minor, rc);
+               goto err_out_region;
+       }
+
+       rc = register_reboot_notifier(&wdt_notifier);
+       if (rc)
+       {
+               printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+                       rc);
+               goto err_out_miscdev;
+       }
+
+       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
+               timeout, nowayout, testmode);
+
+       return 0;
+
+err_out_miscdev:
+       misc_deregister(&wdt_miscdev);
+err_out_region:
+       release_region(IO_INDEX_PORT,2);
+err_out:
+       return rc;
+}
+
+static void __exit w83977f_wdt_exit(void)
+{
+       wdt_stop();
+       misc_deregister(&wdt_miscdev);
+       unregister_reboot_notifier(&wdt_notifier);
+       release_region(IO_INDEX_PORT,2);
+}
+
+module_init(w83977f_wdt_init);
+module_exit(w83977f_wdt_exit);
+
+MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>");
+MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig
new file mode 100644 (file)
index 0000000..0bc2059
--- /dev/null
@@ -0,0 +1,13 @@
+menu "Connector - unified userspace <-> kernelspace linker"
+
+config CONNECTOR
+       tristate "Connector - unified userspace <-> kernelspace linker"
+       depends on NET
+       ---help---
+         This is unified userspace <-> kernelspace connector working on top
+         of the netlink socket protocol.
+
+         Connector support can also be built as a module.  If so, the module
+         will be called cn.ko.
+
+endmenu
diff --git a/drivers/connector/Makefile b/drivers/connector/Makefile
new file mode 100644 (file)
index 0000000..12ca79e
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_CONNECTOR)                += cn.o
+
+cn-y                           += cn_queue.o connector.o
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
new file mode 100644 (file)
index 0000000..9666321
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *     cn_queue.c
+ * 
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 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.  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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/suspend.h>
+#include <linux/connector.h>
+#include <linux/delay.h>
+
+static void cn_queue_wrapper(void *data)
+{
+       struct cn_callback_entry *cbq = data;
+
+       cbq->cb->callback(cbq->cb->priv);
+       cbq->destruct_data(cbq->ddata);
+       cbq->ddata = NULL;
+}
+
+static struct cn_callback_entry *cn_queue_alloc_callback_entry(struct cn_callback *cb)
+{
+       struct cn_callback_entry *cbq;
+
+       cbq = kzalloc(sizeof(*cbq), GFP_KERNEL);
+       if (!cbq) {
+               printk(KERN_ERR "Failed to create new callback queue.\n");
+               return NULL;
+       }
+
+       cbq->cb = cb;
+       INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq);
+       return cbq;
+}
+
+static void cn_queue_free_callback(struct cn_callback_entry *cbq)
+{
+       cancel_delayed_work(&cbq->work);
+       flush_workqueue(cbq->pdev->cn_queue);
+
+       kfree(cbq);
+}
+
+int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
+{
+       return ((i1->idx == i2->idx) && (i1->val == i2->val));
+}
+
+int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb)
+{
+       struct cn_callback_entry *cbq, *__cbq;
+       int found = 0;
+
+       cbq = cn_queue_alloc_callback_entry(cb);
+       if (!cbq)
+               return -ENOMEM;
+
+       atomic_inc(&dev->refcnt);
+       cbq->pdev = dev;
+
+       spin_lock_bh(&dev->queue_lock);
+       list_for_each_entry(__cbq, &dev->queue_list, callback_entry) {
+               if (cn_cb_equal(&__cbq->cb->id, &cb->id)) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found)
+               list_add_tail(&cbq->callback_entry, &dev->queue_list);
+       spin_unlock_bh(&dev->queue_lock);
+
+       if (found) {
+               atomic_dec(&dev->refcnt);
+               cn_queue_free_callback(cbq);
+               return -EINVAL;
+       }
+
+       cbq->nls = dev->nls;
+       cbq->seq = 0;
+       cbq->group = cbq->cb->id.idx;
+
+       return 0;
+}
+
+void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id)
+{
+       struct cn_callback_entry *cbq, *n;
+       int found = 0;
+
+       spin_lock_bh(&dev->queue_lock);
+       list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) {
+               if (cn_cb_equal(&cbq->cb->id, id)) {
+                       list_del(&cbq->callback_entry);
+                       found = 1;
+                       break;
+               }
+       }
+       spin_unlock_bh(&dev->queue_lock);
+
+       if (found) {
+               cn_queue_free_callback(cbq);
+               atomic_dec_and_test(&dev->refcnt);
+       }
+}
+
+struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls)
+{
+       struct cn_queue_dev *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       snprintf(dev->name, sizeof(dev->name), "%s", name);
+       atomic_set(&dev->refcnt, 0);
+       INIT_LIST_HEAD(&dev->queue_list);
+       spin_lock_init(&dev->queue_lock);
+
+       dev->nls = nls;
+       dev->netlink_groups = 0;
+
+       dev->cn_queue = create_workqueue(dev->name);
+       if (!dev->cn_queue) {
+               kfree(dev);
+               return NULL;
+       }
+
+       return dev;
+}
+
+void cn_queue_free_dev(struct cn_queue_dev *dev)
+{
+       struct cn_callback_entry *cbq, *n;
+
+       flush_workqueue(dev->cn_queue);
+       destroy_workqueue(dev->cn_queue);
+
+       spin_lock_bh(&dev->queue_lock);
+       list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry)
+               list_del(&cbq->callback_entry);
+       spin_unlock_bh(&dev->queue_lock);
+
+       while (atomic_read(&dev->refcnt)) {
+               printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
+                      dev->name, atomic_read(&dev->refcnt));
+               msleep(1000);
+       }
+
+       kfree(dev);
+       dev = NULL;
+}
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
new file mode 100644 (file)
index 0000000..aaf6d46
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ *     connector.c
+ * 
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 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.  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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/moduleparam.h>
+#include <linux/connector.h>
+
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
+
+static u32 cn_idx = CN_IDX_CONNECTOR;
+static u32 cn_val = CN_VAL_CONNECTOR;
+
+module_param(cn_idx, uint, 0);
+module_param(cn_val, uint, 0);
+MODULE_PARM_DESC(cn_idx, "Connector's main device idx.");
+MODULE_PARM_DESC(cn_val, "Connector's main device val.");
+
+static DECLARE_MUTEX(notify_lock);
+static LIST_HEAD(notify_list);
+
+static struct cn_dev cdev;
+
+int cn_already_initialized = 0;
+
+/*
+ * msg->seq and msg->ack are used to determine message genealogy.
+ * When someone sends message it puts there locally unique sequence
+ * and random acknowledge numbers.  Sequence number may be copied into
+ * nlmsghdr->nlmsg_seq too.
+ *
+ * Sequence number is incremented with each message to be sent.
+ *
+ * If we expect reply to our message then the sequence number in
+ * received message MUST be the same as in original message, and
+ * acknowledge number MUST be the same + 1.
+ *
+ * If we receive a message and its sequence number is not equal to the
+ * one we are expecting then it is a new message.
+ *
+ * If we receive a message and its sequence number is the same as one
+ * we are expecting but it's acknowledgement number is not equal to
+ * the acknowledgement number in the original message + 1, then it is
+ * a new message.
+ *
+ */
+int cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask)
+{
+       struct cn_callback_entry *__cbq;
+       unsigned int size;
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       struct cn_msg *data;
+       struct cn_dev *dev = &cdev;
+       u32 group = 0;
+       int found = 0;
+
+       if (!__group) {
+               spin_lock_bh(&dev->cbdev->queue_lock);
+               list_for_each_entry(__cbq, &dev->cbdev->queue_list,
+                                   callback_entry) {
+                       if (cn_cb_equal(&__cbq->cb->id, &msg->id)) {
+                               found = 1;
+                               group = __cbq->group;
+                       }
+               }
+               spin_unlock_bh(&dev->cbdev->queue_lock);
+
+               if (!found)
+                       return -ENODEV;
+       } else {
+               group = __group;
+       }
+
+       size = NLMSG_SPACE(sizeof(*msg) + msg->len);
+
+       skb = alloc_skb(size, gfp_mask);
+       if (!skb)
+               return -ENOMEM;
+
+       nlh = NLMSG_PUT(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh));
+
+       data = NLMSG_DATA(nlh);
+
+       memcpy(data, msg, sizeof(*data) + msg->len);
+
+       NETLINK_CB(skb).dst_group = group;
+
+       netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
+
+       return 0;
+
+nlmsg_failure:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+/*
+ * Callback helper - queues work and setup destructor for given data.
+ */
+static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data)
+{
+       struct cn_callback_entry *__cbq;
+       struct cn_dev *dev = &cdev;
+       int found = 0;
+
+       spin_lock_bh(&dev->cbdev->queue_lock);
+       list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) {
+               if (cn_cb_equal(&__cbq->cb->id, &msg->id)) {
+                       /*
+                        * Let's scream if there is some magic and the
+                        * data will arrive asynchronously here.
+                        * [i.e. netlink messages will be queued].
+                        * After the first warning I will fix it
+                        * quickly, but now I think it is
+                        * impossible. --zbr (2004_04_27).
+                        */
+                       if (likely(!test_bit(0, &__cbq->work.pending) &&
+                                       __cbq->ddata == NULL)) {
+                               __cbq->cb->priv = msg;
+
+                               __cbq->ddata = data;
+                               __cbq->destruct_data = destruct_data;
+
+                               if (queue_work(dev->cbdev->cn_queue,
+                                               &__cbq->work))
+                                       found = 1;
+                       } else {
+                               printk("%s: cbq->data=%p, "
+                                      "work->pending=%08lx.\n",
+                                      __func__, __cbq->ddata,
+                                      __cbq->work.pending);
+                               WARN_ON(1);
+                       }
+                       break;
+               }
+       }
+       spin_unlock_bh(&dev->cbdev->queue_lock);
+
+       return found ? 0 : -ENODEV;
+}
+
+/*
+ * Skb receive helper - checks skb and msg size and calls callback
+ * helper.
+ */
+static int __cn_rx_skb(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+       u32 pid, uid, seq, group;
+       struct cn_msg *msg;
+
+       pid = NETLINK_CREDS(skb)->pid;
+       uid = NETLINK_CREDS(skb)->uid;
+       seq = nlh->nlmsg_seq;
+       group = NETLINK_CB((skb)).dst_group;
+       msg = NLMSG_DATA(nlh);
+
+       return cn_call_callback(msg, (void (*)(void *))kfree_skb, skb);
+}
+
+/*
+ * Main netlink receiving function.
+ *
+ * It checks skb and netlink header sizes and calls the skb receive
+ * helper with a shared skb.
+ */
+static void cn_rx_skb(struct sk_buff *__skb)
+{
+       struct nlmsghdr *nlh;
+       u32 len;
+       int err;
+       struct sk_buff *skb;
+
+       skb = skb_get(__skb);
+
+       if (skb->len >= NLMSG_SPACE(0)) {
+               nlh = (struct nlmsghdr *)skb->data;
+
+               if (nlh->nlmsg_len < sizeof(struct cn_msg) ||
+                   skb->len < nlh->nlmsg_len ||
+                   nlh->nlmsg_len > CONNECTOR_MAX_MSG_SIZE) {
+                       kfree_skb(skb);
+                       goto out;
+               }
+
+               len = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (len > skb->len)
+                       len = skb->len;
+
+               err = __cn_rx_skb(skb, nlh);
+               if (err < 0)
+                       kfree_skb(skb);
+       }
+
+out:
+       kfree_skb(__skb);
+}
+
+/*
+ * Netlink socket input callback - dequeues the skbs and calls the
+ * main netlink receiving function.
+ */
+static void cn_input(struct sock *sk, int len)
+{
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
+               cn_rx_skb(skb);
+}
+
+/*
+ * Notification routing.
+ *
+ * Gets id and checks if there are notification request for it's idx
+ * and val.  If there are such requests notify the listeners with the
+ * given notify event.
+ *
+ */
+static void cn_notify(struct cb_id *id, u32 notify_event)
+{
+       struct cn_ctl_entry *ent;
+
+       down(&notify_lock);
+       list_for_each_entry(ent, &notify_list, notify_entry) {
+               int i;
+               struct cn_notify_req *req;
+               struct cn_ctl_msg *ctl = ent->msg;
+               int idx_found, val_found;
+
+               idx_found = val_found = 0;
+
+               req = (struct cn_notify_req *)ctl->data;
+               for (i = 0; i < ctl->idx_notify_num; ++i, ++req) {
+                       if (id->idx >= req->first && 
+                                       id->idx < req->first + req->range) {
+                               idx_found = 1;
+                               break;
+                       }
+               }
+
+               for (i = 0; i < ctl->val_notify_num; ++i, ++req) {
+                       if (id->val >= req->first && 
+                                       id->val < req->first + req->range) {
+                               val_found = 1;
+                               break;
+                       }
+               }
+
+               if (idx_found && val_found) {
+                       struct cn_msg m = { .ack = notify_event, };
+
+                       memcpy(&m.id, id, sizeof(m.id));
+                       cn_netlink_send(&m, ctl->group, GFP_KERNEL);
+               }
+       }
+       up(&notify_lock);
+}
+
+/*
+ * Callback add routing - adds callback with given ID and name.
+ * If there is registered callback with the same ID it will not be added.
+ *
+ * May sleep.
+ */
+int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))
+{
+       int err;
+       struct cn_dev *dev = &cdev;
+       struct cn_callback *cb;
+
+       cb = kzalloc(sizeof(*cb), GFP_KERNEL);
+       if (!cb)
+               return -ENOMEM;
+
+       scnprintf(cb->name, sizeof(cb->name), "%s", name);
+
+       memcpy(&cb->id, id, sizeof(cb->id));
+       cb->callback = callback;
+
+       err = cn_queue_add_callback(dev->cbdev, cb);
+       if (err) {
+               kfree(cb);
+               return err;
+       }
+
+       cn_notify(id, 0);
+
+       return 0;
+}
+
+/*
+ * Callback remove routing - removes callback
+ * with given ID.
+ * If there is no registered callback with given
+ * ID nothing happens.
+ *
+ * May sleep while waiting for reference counter to become zero.
+ */
+void cn_del_callback(struct cb_id *id)
+{
+       struct cn_dev *dev = &cdev;
+
+       cn_queue_del_callback(dev->cbdev, id);
+       cn_notify(id, 1);
+}
+
+/*
+ * Checks two connector's control messages to be the same.
+ * Returns 1 if they are the same or if the first one is corrupted.
+ */
+static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
+{
+       int i;
+       struct cn_notify_req *req1, *req2;
+
+       if (m1->idx_notify_num != m2->idx_notify_num)
+               return 0;
+
+       if (m1->val_notify_num != m2->val_notify_num)
+               return 0;
+
+       if (m1->len != m2->len)
+               return 0;
+
+       if ((m1->idx_notify_num + m1->val_notify_num) * sizeof(*req1) !=
+           m1->len)
+               return 1;
+
+       req1 = (struct cn_notify_req *)m1->data;
+       req2 = (struct cn_notify_req *)m2->data;
+
+       for (i = 0; i < m1->idx_notify_num; ++i) {
+               if (req1->first != req2->first || req1->range != req2->range)
+                       return 0;
+               req1++;
+               req2++;
+       }
+
+       for (i = 0; i < m1->val_notify_num; ++i) {
+               if (req1->first != req2->first || req1->range != req2->range)
+                       return 0;
+               req1++;
+               req2++;
+       }
+
+       return 1;
+}
+
+/*
+ * Main connector device's callback.
+ *
+ * Used for notification of a request's processing.
+ */
+static void cn_callback(void *data)
+{
+       struct cn_msg *msg = data;
+       struct cn_ctl_msg *ctl;
+       struct cn_ctl_entry *ent;
+       u32 size;
+
+       if (msg->len < sizeof(*ctl))
+               return;
+
+       ctl = (struct cn_ctl_msg *)msg->data;
+
+       size = (sizeof(*ctl) + ((ctl->idx_notify_num +
+                                ctl->val_notify_num) *
+                               sizeof(struct cn_notify_req)));
+
+       if (msg->len != size)
+               return;
+
+       if (ctl->len + sizeof(*ctl) != msg->len)
+               return;
+
+       /*
+        * Remove notification.
+        */
+       if (ctl->group == 0) {
+               struct cn_ctl_entry *n;
+
+               down(&notify_lock);
+               list_for_each_entry_safe(ent, n, &notify_list, notify_entry) {
+                       if (cn_ctl_msg_equals(ent->msg, ctl)) {
+                               list_del(&ent->notify_entry);
+                               kfree(ent);
+                       }
+               }
+               up(&notify_lock);
+
+               return;
+       }
+
+       size += sizeof(*ent);
+
+       ent = kzalloc(size, GFP_KERNEL);
+       if (!ent)
+               return;
+
+       ent->msg = (struct cn_ctl_msg *)(ent + 1);
+
+       memcpy(ent->msg, ctl, size - sizeof(*ent));
+
+       down(&notify_lock);
+       list_add(&ent->notify_entry, &notify_list);
+       up(&notify_lock);
+}
+
+static int __init cn_init(void)
+{
+       struct cn_dev *dev = &cdev;
+       int err;
+
+       dev->input = cn_input;
+       dev->id.idx = cn_idx;
+       dev->id.val = cn_val;
+
+       dev->nls = netlink_kernel_create(NETLINK_CONNECTOR,
+                                        CN_NETLINK_USERS + 0xf,
+                                        dev->input, THIS_MODULE);
+       if (!dev->nls)
+               return -EIO;
+
+       dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls);
+       if (!dev->cbdev) {
+               if (dev->nls->sk_socket)
+                       sock_release(dev->nls->sk_socket);
+               return -EINVAL;
+       }
+
+       err = cn_add_callback(&dev->id, "connector", &cn_callback);
+       if (err) {
+               cn_queue_free_dev(dev->cbdev);
+               if (dev->nls->sk_socket)
+                       sock_release(dev->nls->sk_socket);
+               return -EINVAL;
+       }
+
+       cn_already_initialized = 1;
+
+       return 0;
+}
+
+static void __exit cn_fini(void)
+{
+       struct cn_dev *dev = &cdev;
+
+       cn_already_initialized = 0;
+
+       cn_del_callback(&dev->id);
+       cn_queue_free_dev(dev->cbdev);
+       if (dev->nls->sk_socket)
+               sock_release(dev->nls->sk_socket);
+}
+
+module_init(cn_init);
+module_exit(cn_fini);
+
+EXPORT_SYMBOL_GPL(cn_add_callback);
+EXPORT_SYMBOL_GPL(cn_del_callback);
+EXPORT_SYMBOL_GPL(cn_netlink_send);
index 138dc50270e3e51e714893602c937b5fa95ec14e..7e72e922b41c2ca603c8bcde49aa549005d52dbf 100644 (file)
@@ -411,6 +411,23 @@ config SENSORS_W83627EHF
          This driver can also be built as a module.  If so, the module
          will be called w83627ehf.
 
+config SENSORS_HDAPS
+       tristate "IBM Hard Drive Active Protection System (hdaps)"
+       depends on HWMON && INPUT && X86
+       default n
+       help
+         This driver provides support for the IBM Hard Drive Active Protection
+         System (hdaps), which provides an accelerometer and other misc. data.
+         Supported laptops include the IBM ThinkPad T41, T42, T43, and R51.
+         The accelerometer data is readable via sysfs.
+
+         This driver also provides an input class device, allowing the
+         laptop to act as a pinball machine-esque mouse.  This is off by
+         default but enabled via sysfs or the module parameter "mousedev".
+
+         Say Y here if you have an applicable laptop and want to experience
+         the awesome power of hdaps.
+
 config HWMON_DEBUG_CHIP
        bool "Hardware Monitoring Chip debugging messages"
        depends on HWMON
index 381f1bf04cc5531f2f4f2376f2c0afc61fff57b7..f7d6a2f61ee74b4f442f25213b40f66b761fc36a 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_FSCHER)  += fscher.o
 obj-$(CONFIG_SENSORS_FSCPOS)   += fscpos.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)  += gl520sm.o
+obj-$(CONFIG_SENSORS_HDAPS)    += hdaps.o
 obj-$(CONFIG_SENSORS_IT87)     += it87.o
 obj-$(CONFIG_SENSORS_LM63)     += lm63.o
 obj-$(CONFIG_SENSORS_LM75)     += lm75.o
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
new file mode 100644 (file)
index 0000000..eaebfc1
--- /dev/null
@@ -0,0 +1,739 @@
+/*
+ * drivers/hwmon/hdaps.c - driver for IBM's Hard Drive Active Protection System
+ *
+ * Copyright (C) 2005 Robert Love <rml@novell.com>
+ * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
+ *
+ * The HardDisk Active Protection System (hdaps) is present in the IBM ThinkPad
+ * T41, T42, T43, R51, and X40, at least.  It provides a basic two-axis
+ * accelerometer and other data, such as the device's temperature.
+ *
+ * Based on the document by Mark A. Smith available at
+ * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial
+ * and error.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+#define HDAPS_LOW_PORT         0x1600  /* first port used by hdaps */
+#define HDAPS_NR_PORTS         0x30    /* 0x1600 - 0x162f */
+
+#define STATE_FRESH            0x50    /* accelerometer data is fresh */
+
+#define REFRESH_ASYNC          0x00    /* do asynchronous refresh */
+#define REFRESH_SYNC           0x01    /* do synchronous refresh */
+
+#define HDAPS_PORT_STATE       0x1611  /* device state */
+#define HDAPS_PORT_YPOS                0x1612  /* y-axis position */
+#define        HDAPS_PORT_XPOS         0x1614  /* x-axis position */
+#define HDAPS_PORT_TEMP1       0x1616  /* device temperature, in celcius */
+#define HDAPS_PORT_YVAR                0x1617  /* y-axis variance (what is this?) */
+#define HDAPS_PORT_XVAR                0x1619  /* x-axis variance (what is this?) */
+#define HDAPS_PORT_TEMP2       0x161b  /* device temperature (again?) */
+#define HDAPS_PORT_UNKNOWN     0x161c  /* what is this? */
+#define HDAPS_PORT_KMACT       0x161d  /* keyboard or mouse activity */
+
+#define HDAPS_READ_MASK                0xff    /* some reads have the low 8 bits set */
+
+#define KEYBD_MASK             0x20    /* set if keyboard activity */
+#define MOUSE_MASK             0x40    /* set if mouse activity */
+#define KEYBD_ISSET(n)         (!! (n & KEYBD_MASK))   /* keyboard used? */
+#define MOUSE_ISSET(n)         (!! (n & MOUSE_MASK))   /* mouse used? */
+
+#define INIT_TIMEOUT_MSECS     4000    /* wait up to 4s for device init ... */
+#define INIT_WAIT_MSECS                200     /* ... in 200ms increments */
+
+static struct platform_device *pdev;
+static struct input_dev hdaps_idev;
+static struct timer_list hdaps_timer;
+static unsigned int hdaps_mousedev_threshold = 4;
+static unsigned long hdaps_poll_ms = 50;
+static unsigned int hdaps_mousedev;
+static unsigned int hdaps_invert;
+static u8 km_activity;
+static int rest_x;
+static int rest_y;
+
+static DECLARE_MUTEX(hdaps_sem);
+
+/*
+ * __get_latch - Get the value from a given port.  Callers must hold hdaps_sem.
+ */
+static inline u8 __get_latch(u16 port)
+{
+       return inb(port) & HDAPS_READ_MASK;
+}
+
+/*
+ * __check_latch - Check a port latch for a given value.  Callers must hold
+ * hdaps_sem.  Returns zero if the port contains the given value.
+ */
+static inline unsigned int __check_latch(u16 port, u8 val)
+{
+       if (__get_latch(port) == val)
+               return 0;
+       return -EINVAL;
+}
+
+/*
+ * __wait_latch - Wait up to 100us for a port latch to get a certain value,
+ * returning zero if the value is obtained.  Callers must hold hdaps_sem.
+ */
+static unsigned int __wait_latch(u16 port, u8 val)
+{
+       unsigned int i;
+
+       for (i = 0; i < 20; i++) {
+               if (!__check_latch(port, val))
+                       return 0;
+               udelay(5);
+       }
+
+       return -EINVAL;
+}
+
+/*
+ * __device_refresh - Request a refresh from the accelerometer.
+ *
+ * If sync is REFRESH_SYNC, we perform a synchronous refresh and will wait.
+ * Returns zero if successful and nonzero on error.
+ *
+ * If sync is REFRESH_ASYNC, we merely kick off a new refresh if the device is
+ * not up-to-date.  Always returns zero.
+ *
+ * Callers must hold hdaps_sem.
+ */
+static int __device_refresh(unsigned int sync)
+{
+       u8 state;
+
+       udelay(100);
+
+       state = inb(0x1604);
+       if (state == STATE_FRESH)
+               return 0;
+
+       outb(0x11, 0x1610);
+       outb(0x01, 0x161f);
+       if (sync == REFRESH_ASYNC)
+               return 0;
+
+       return __wait_latch(0x1604, STATE_FRESH);
+}
+
+/*
+ * __device_complete - Indicate to the accelerometer that we are done reading
+ * data, and then initiate an async refresh.  Callers must hold hdaps_sem.
+ */
+static inline void __device_complete(void)
+{
+       inb(0x161f);
+       inb(0x1604);
+       __device_refresh(REFRESH_ASYNC);
+}
+
+static int __hdaps_readb_one(unsigned int port, u8 *val)
+{
+       /* do a sync refresh -- we need to be sure that we read fresh data */
+       if (__device_refresh(REFRESH_SYNC))
+               return -EIO;
+
+       *val = inb(port);
+       __device_complete();
+
+       return 0;
+}
+
+/*
+ * hdaps_readb_one - reads a byte from a single I/O port, placing the value in
+ * the given pointer.  Returns zero on success or a negative error on failure.
+ * Can sleep.
+ */
+static int hdaps_readb_one(unsigned int port, u8 *val)
+{
+       int ret;
+
+       down(&hdaps_sem);
+       ret = __hdaps_readb_one(port, val);
+       up(&hdaps_sem);
+
+       return ret;
+}
+
+static int __hdaps_read_pair(unsigned int port1, unsigned int port2,
+                            int *x, int *y)
+{
+       /* do a sync refresh -- we need to be sure that we read fresh data */
+       if (__device_refresh(REFRESH_SYNC))
+               return -EIO;
+
+       *y = inw(port2);
+       *x = inw(port1);
+       km_activity = inb(HDAPS_PORT_KMACT);
+       __device_complete();
+
+       /* if hdaps_invert is set, negate the two values */
+       if (hdaps_invert) {
+               *x = -*x;
+               *y = -*y;
+       }
+
+       return 0;
+}
+
+/*
+ * hdaps_read_pair - reads the values from a pair of ports, placing the values
+ * in the given pointers.  Returns zero on success.  Can sleep.
+ */
+static int hdaps_read_pair(unsigned int port1, unsigned int port2,
+                          int *val1, int *val2)
+{
+       int ret;
+
+       down(&hdaps_sem);
+       ret = __hdaps_read_pair(port1, port2, val1, val2);
+       up(&hdaps_sem);
+
+       return ret;
+}
+
+/* initialize the accelerometer */
+static int hdaps_device_init(void)
+{
+       unsigned int total_msecs = INIT_TIMEOUT_MSECS;
+       int ret = -ENXIO;
+
+       down(&hdaps_sem);
+
+       outb(0x13, 0x1610);
+       outb(0x01, 0x161f);
+       if (__wait_latch(0x161f, 0x00))
+               goto out;
+
+       /*
+        * The 0x03 value appears to only work on some thinkpads, such as the
+        * T42p.  Others return 0x01.
+        *
+        * The 0x02 value occurs when the chip has been previously initialized.
+        */
+       if (__check_latch(0x1611, 0x03) &&
+                    __check_latch(0x1611, 0x02) &&
+                    __check_latch(0x1611, 0x01))
+               goto out;
+
+       printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x).\n",
+              __get_latch(0x1611));
+
+       outb(0x17, 0x1610);
+       outb(0x81, 0x1611);
+       outb(0x01, 0x161f);
+       if (__wait_latch(0x161f, 0x00))
+               goto out;
+       if (__wait_latch(0x1611, 0x00))
+               goto out;
+       if (__wait_latch(0x1612, 0x60))
+               goto out;
+       if (__wait_latch(0x1613, 0x00))
+               goto out;
+       outb(0x14, 0x1610);
+       outb(0x01, 0x1611);
+       outb(0x01, 0x161f);
+       if (__wait_latch(0x161f, 0x00))
+               goto out;
+       outb(0x10, 0x1610);
+       outb(0xc8, 0x1611);
+       outb(0x00, 0x1612);
+       outb(0x02, 0x1613);
+       outb(0x01, 0x161f);
+       if (__wait_latch(0x161f, 0x00))
+               goto out;
+       if (__device_refresh(REFRESH_SYNC))
+               goto out;
+       if (__wait_latch(0x1611, 0x00))
+               goto out;
+
+       /* we have done our dance, now let's wait for the applause */
+       while (total_msecs > 0) {
+               u8 ignored;
+
+               /* a read of the device helps push it into action */
+               __hdaps_readb_one(HDAPS_PORT_UNKNOWN, &ignored);
+               if (!__wait_latch(0x1611, 0x02)) {
+                       ret = 0;
+                       break;
+               }
+
+               msleep(INIT_WAIT_MSECS);
+               total_msecs -= INIT_WAIT_MSECS;
+       }
+
+out:
+       up(&hdaps_sem);
+       return ret;
+}
+
+
+/* Input class stuff */
+
+/*
+ * hdaps_calibrate - Zero out our "resting" values. Callers must hold hdaps_sem.
+ */
+static void hdaps_calibrate(void)
+{
+       int x, y;
+
+       if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
+               return;
+
+       rest_x = x;
+       rest_y = y;
+}
+
+static void hdaps_mousedev_poll(unsigned long unused)
+{
+       int x, y;
+
+       /* Cannot sleep.  Try nonblockingly.  If we fail, try again later. */
+       if (down_trylock(&hdaps_sem)) {
+               mod_timer(&hdaps_timer,jiffies+msecs_to_jiffies(hdaps_poll_ms));
+               return;
+       }
+
+       if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
+               goto out;
+
+       x -= rest_x;
+       y -= rest_y;
+       if (abs(x) > hdaps_mousedev_threshold)
+               input_report_rel(&hdaps_idev, REL_X, x);
+       if (abs(y) > hdaps_mousedev_threshold)
+               input_report_rel(&hdaps_idev, REL_Y, y);
+       input_sync(&hdaps_idev);
+
+       mod_timer(&hdaps_timer, jiffies + msecs_to_jiffies(hdaps_poll_ms));
+
+out:
+       up(&hdaps_sem);
+}
+
+/*
+ * hdaps_mousedev_enable - enable the input class device.  Can sleep.
+ */
+static void hdaps_mousedev_enable(void)
+{
+       down(&hdaps_sem);
+
+       /* calibrate the device before enabling */
+       hdaps_calibrate();
+
+       /* initialize the input class */
+       init_input_dev(&hdaps_idev);
+       hdaps_idev.dev = &pdev->dev;
+       hdaps_idev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       hdaps_idev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       hdaps_idev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT);
+       input_register_device(&hdaps_idev);
+
+       /* start up our timer */
+       init_timer(&hdaps_timer);
+       hdaps_timer.function = hdaps_mousedev_poll;
+       hdaps_timer.expires = jiffies + msecs_to_jiffies(hdaps_poll_ms);
+       add_timer(&hdaps_timer);
+
+       hdaps_mousedev = 1;
+
+       up(&hdaps_sem);
+
+       printk(KERN_INFO "hdaps: input device enabled.\n");
+}
+
+/*
+ * hdaps_mousedev_disable - disable the input class device.  Caller must hold
+ * hdaps_sem.
+ */
+static void hdaps_mousedev_disable(void)
+{
+       down(&hdaps_sem);
+       if (hdaps_mousedev) {
+               hdaps_mousedev = 0;
+               del_timer_sync(&hdaps_timer);
+               input_unregister_device(&hdaps_idev);
+       }
+       up(&hdaps_sem);
+}
+
+
+/* Device model stuff */
+
+static int hdaps_probe(struct device *dev)
+{
+       int ret;
+
+       ret = hdaps_device_init();
+       if (ret)
+               return ret;
+
+       printk(KERN_INFO "hdaps: device successfully initialized.\n");
+       return 0;
+}
+
+static int hdaps_resume(struct device *dev, u32 level)
+{
+       if (level == RESUME_ENABLE)
+               return hdaps_device_init();
+       return 0;
+}
+
+static struct device_driver hdaps_driver = {
+       .name = "hdaps",
+       .bus = &platform_bus_type,
+       .owner = THIS_MODULE,
+       .probe = hdaps_probe,
+       .resume = hdaps_resume
+};
+
+
+/* Sysfs Files */
+
+static ssize_t hdaps_position_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int ret, x, y;
+
+       ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "(%d,%d)\n", x, y);
+}
+
+static ssize_t hdaps_variance_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       int ret, x, y;
+
+       ret = hdaps_read_pair(HDAPS_PORT_XVAR, HDAPS_PORT_YVAR, &x, &y);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "(%d,%d)\n", x, y);
+}
+
+static ssize_t hdaps_temp1_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u8 temp;
+       int ret;
+
+       ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%u\n", temp);
+}
+
+static ssize_t hdaps_temp2_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u8 temp;
+       int ret;
+
+       ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%u\n", temp);
+}
+
+static ssize_t hdaps_keyboard_activity_show(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf)
+{
+       return sprintf(buf, "%u\n", KEYBD_ISSET(km_activity));
+}
+
+static ssize_t hdaps_mouse_activity_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       return sprintf(buf, "%u\n", MOUSE_ISSET(km_activity));
+}
+
+static ssize_t hdaps_calibrate_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "(%d,%d)\n", rest_x, rest_y);
+}
+
+static ssize_t hdaps_calibrate_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       down(&hdaps_sem);
+       hdaps_calibrate();
+       up(&hdaps_sem);
+
+       return count;
+}
+
+static ssize_t hdaps_invert_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", hdaps_invert);
+}
+
+static ssize_t hdaps_invert_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       int invert;
+
+       if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0))
+               return -EINVAL;
+
+       hdaps_invert = invert;
+       hdaps_calibrate();
+
+       return count;
+}
+
+static ssize_t hdaps_mousedev_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", hdaps_mousedev);
+}
+
+static ssize_t hdaps_mousedev_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       int enable;
+
+       if (sscanf(buf, "%d", &enable) != 1)
+               return -EINVAL;
+
+       if (enable == 1)
+               hdaps_mousedev_enable();
+       else if (enable == 0)
+               hdaps_mousedev_disable();
+       else
+               return -EINVAL;
+
+       return count;
+}
+
+static ssize_t hdaps_poll_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%lu\n", hdaps_poll_ms);
+}
+
+static ssize_t hdaps_poll_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       unsigned int poll;
+
+       if (sscanf(buf, "%u", &poll) != 1 || poll == 0)
+               return -EINVAL;
+       hdaps_poll_ms = poll;
+
+       return count;
+}
+
+static ssize_t hdaps_threshold_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", hdaps_mousedev_threshold);
+}
+
+static ssize_t hdaps_threshold_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       unsigned int threshold;
+
+       if (sscanf(buf, "%u", &threshold) != 1 || threshold == 0)
+               return -EINVAL;
+       hdaps_mousedev_threshold = threshold;
+
+       return count;
+}
+
+static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
+static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL);
+static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
+static DEVICE_ATTR(temp2, 0444, hdaps_temp2_show, NULL);
+static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL);
+static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);
+static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store);
+static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);
+static DEVICE_ATTR(mousedev, 0644, hdaps_mousedev_show, hdaps_mousedev_store);
+static DEVICE_ATTR(mousedev_poll_ms, 0644, hdaps_poll_show, hdaps_poll_store);
+static DEVICE_ATTR(mousedev_threshold, 0644, hdaps_threshold_show,
+                  hdaps_threshold_store);
+
+static struct attribute *hdaps_attributes[] = {
+       &dev_attr_position.attr,
+       &dev_attr_variance.attr,
+       &dev_attr_temp1.attr,
+       &dev_attr_temp2.attr,
+       &dev_attr_keyboard_activity.attr,
+       &dev_attr_mouse_activity.attr,
+       &dev_attr_calibrate.attr,
+       &dev_attr_mousedev.attr,
+       &dev_attr_mousedev_threshold.attr,
+       &dev_attr_mousedev_poll_ms.attr,
+       &dev_attr_invert.attr,
+       NULL,
+};
+
+static struct attribute_group hdaps_attribute_group = {
+       .attrs = hdaps_attributes,
+};
+
+
+/* Module stuff */
+
+/*
+ * XXX: We should be able to return nonzero and halt the detection process.
+ * But there is a bug in dmi_check_system() where a nonzero return from the
+ * first match will result in a return of failure from dmi_check_system().
+ * I fixed this; the patch is in 2.6-mm.  Once in Linus's tree we can make
+ * hdaps_dmi_match_invert() return hdaps_dmi_match(), which in turn returns 1.
+ */
+static int hdaps_dmi_match(struct dmi_system_id *id)
+{
+       printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
+       return 0;
+}
+
+static int hdaps_dmi_match_invert(struct dmi_system_id *id)
+{
+       hdaps_invert = 1;
+       printk(KERN_INFO "hdaps: inverting axis readings.\n");
+       return 0;
+}
+
+#define HDAPS_DMI_MATCH_NORMAL(model)  {               \
+       .ident = "IBM " model,                          \
+       .callback = hdaps_dmi_match,                    \
+       .matches = {                                    \
+               DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),     \
+               DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
+       }                                               \
+}
+
+#define HDAPS_DMI_MATCH_INVERT(model)  {               \
+       .ident = "IBM " model,                          \
+       .callback = hdaps_dmi_match_invert,             \
+       .matches = {                                    \
+               DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),     \
+               DMI_MATCH(DMI_PRODUCT_VERSION, model)   \
+       }                                               \
+}
+
+static int __init hdaps_init(void)
+{
+       int ret;
+
+       /* Note that DMI_MATCH(...,"ThinkPad T42") will match "ThinkPad T42p" */
+       struct dmi_system_id hdaps_whitelist[] = {
+               HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"),
+               HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"),
+               HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"),
+               HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"),
+               HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"),
+               HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"),
+               HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"),
+               HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"),
+               HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"),
+               { .ident = NULL }
+       };
+
+       if (!dmi_check_system(hdaps_whitelist)) {
+               printk(KERN_WARNING "hdaps: supported laptop not found!\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       if (!request_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS, "hdaps")) {
+               ret = -ENXIO;
+               goto out;
+       }
+
+       ret = driver_register(&hdaps_driver);
+       if (ret)
+               goto out_region;
+
+       pdev = platform_device_register_simple("hdaps", -1, NULL, 0);
+       if (IS_ERR(pdev)) {
+               ret = PTR_ERR(pdev);
+               goto out_driver;
+       }
+
+       ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group);
+       if (ret)
+               goto out_device;
+
+       if (hdaps_mousedev)
+               hdaps_mousedev_enable();
+
+       printk(KERN_INFO "hdaps: driver successfully loaded.\n");
+       return 0;
+
+out_device:
+       platform_device_unregister(pdev);
+out_driver:
+       driver_unregister(&hdaps_driver);
+out_region:
+       release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
+out:
+       printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);
+       return ret;
+}
+
+static void __exit hdaps_exit(void)
+{
+       hdaps_mousedev_disable();
+
+       sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
+       platform_device_unregister(pdev);
+       driver_unregister(&hdaps_driver);
+       release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
+
+       printk(KERN_INFO "hdaps: driver unloaded.\n");
+}
+
+module_init(hdaps_init);
+module_exit(hdaps_exit);
+
+module_param_named(mousedev, hdaps_mousedev, bool, 0);
+MODULE_PARM_DESC(mousedev, "enable the input class device");
+
+module_param_named(invert, hdaps_invert, bool, 0);
+MODULE_PARM_DESC(invert, "invert data along each axis");
+
+MODULE_AUTHOR("Robert Love");
+MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
+MODULE_LICENSE("GPL v2");
index 8610bce08244d1bb3f74dcca18ef48112c717073..21aa9a41f62cbc5e7432a73e93318de9be0cf666 100644 (file)
@@ -758,11 +758,6 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
                return -ENODEV;
        }
 
-       if (!address) {
-               dev_err(&dev->dev,"No SiS 5595 sensors found.\n");
-               return -ENODEV;
-       }
-
        s_bridge = pci_dev_get(dev);
        if (i2c_isa_add_driver(&sis5595_driver)) {
                pci_dev_put(s_bridge);
index 7e699a8ede262916369a88c57001f6de86eafbad..c9cc683eba4a9f85d7cda47ef9c1a3023402221f 100644 (file)
@@ -2,8 +2,8 @@
     smsc47m1.c - Part of lm_sensors, Linux kernel modules
                  for hardware monitoring
 
-    Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x
-    Super-I/O chips.
+    Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x,
+    LPC47M15x and LPC47M192 Super-I/O chips.
 
     Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
     Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
index eb84997627c8245456ab40c3d402d72b51104ce9..05ddc88e7dd2e4bc5aa7504041c24cdff17467d1 100644 (file)
@@ -812,11 +812,6 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev,
                return -ENODEV;
        }
 
-       if (!address) {
-               dev_err(&dev->dev, "No Via 686A sensors found.\n");
-               return -ENODEV;
-       }
-
        s_bridge = pci_dev_get(dev);
        if (i2c_isa_add_driver(&via686a_driver)) {
                pci_dev_put(s_bridge);
index 02bd5c0239a2daba693652cdafb431efd75e77a4..3479dc5208e2d3a9ac8d707177a9b17948e7c65f 100644 (file)
@@ -64,6 +64,10 @@ static unsigned short address;
 /* Insmod parameters */
 enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf };
 
+static int reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
+
 static int init = 1;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
@@ -1279,7 +1283,15 @@ static void w83627hf_init_client(struct i2c_client *client)
        int type = data->type;
        u8 tmp;
 
-       if(init) {
+       if (reset) {
+               /* Resetting the chip has been the default for a long time,
+                  but repeatedly caused problems (fans going to full
+                  speed...) so it is now optional. It might even go away if
+                  nobody reports it as being useful, as I see very little
+                  reason why this would be needed at all. */
+               dev_info(&client->dev, "If reset=1 solved a problem you were "
+                        "having, please report!\n");
+
                /* save this register */
                i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);
                /* Reset all except Watchdog values and last conversion values
index 37b49c2daf5f824a5057ff713effce45149f7116..eff5896ce865572baab25f49802077f78f6f8ea7 100644 (file)
@@ -611,7 +611,6 @@ create_iface(struct device_node *np, struct device *dev)
        
        for (i=0; i<nchan; i++) {
                struct keywest_chan* chan = &iface->channels[i];
-               u8 addr;
                
                sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
                chan->iface = iface;
index e0b7a913431e0c1c7664f474a904e8db44a57c92..fe9c0f42a2b7735e746a2a8ac5ddce404b7044f4 100644 (file)
@@ -98,11 +98,6 @@ struct nforce2_smbus {
 #define NVIDIA_SMB_PRTCL_PEC                   0x80
 
 
-/* Other settings */
-#define MAX_TIMEOUT 256
-
-
-
 static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
                       unsigned short flags, char read_write,
                       u8 command, int size, union i2c_smbus_data *data);
index b443b04a4c5a7c1de5263dc4c2120655d88b38c4..0b0aa4f516280bc522769f5761e18cb8dc4e5259 100644 (file)
@@ -601,44 +601,15 @@ EXPORT_SYMBOL(ide_wait_stat);
  */
 u8 eighty_ninty_three (ide_drive_t *drive)
 {
-#if 0
-       if (!HWIF(drive)->udma_four)
+       if(HWIF(drive)->udma_four == 0)
+               return 0;
+       if (!(drive->id->hw_config & 0x6000))
                return 0;
-
-       if (drive->id->major_rev_num) {
-               int hssbd = 0;
-               int i;
-               /*
-                * Determine highest Supported SPEC
-                */
-               for (i=1; i<=15; i++)
-                       if (drive->id->major_rev_num & (1<<i))
-                               hssbd++;
-
-               switch (hssbd) {
-                       case 7:
-                       case 6:
-                       case 5:
-               /* ATA-4 and older do not support above Ultra 33 */
-                       default:
-                               return 0;
-               }
-       }
-
-       return ((u8) (
-#ifndef CONFIG_IDEDMA_IVB
-               (drive->id->hw_config & 0x4000) &&
-#endif /* CONFIG_IDEDMA_IVB */
-                (drive->id->hw_config & 0x6000)) ? 1 : 0);
-
-#else
-
-       return ((u8) ((HWIF(drive)->udma_four) &&
 #ifndef CONFIG_IDEDMA_IVB
-                       (drive->id->hw_config & 0x4000) &&
+       if(!(drive->id->hw_config & 0x4000))
+               return 0;
 #endif /* CONFIG_IDEDMA_IVB */
-                       (drive->id->hw_config & 0x6000)) ? 1 : 0);
-#endif
+       return 1;
 }
 
 EXPORT_SYMBOL(eighty_ninty_three);
index 3de9ab897e421aff8eb235023ee115189678cf19..3d9c7afc86950ad1660852bba5eb680199cde1b2 100644 (file)
@@ -608,7 +608,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
 
 #ifdef __i386__
        if (dev->resource[PCI_ROM_RESOURCE].start) {
-               pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+               pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
                printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
        }
 #endif
index bbde462799843802ccfe66936ef7271618c765ce..be334da7a7549b4fb44f82e59000450875c1abfb 100644 (file)
@@ -173,7 +173,7 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
 
        if (cmd & PCI_COMMAND_MEMORY) {
                if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
-                       pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+                       pci_write_config_dword(dev, PCI_ROM_ADDRESS,
                                dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
                        printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
                                dev->resource[PCI_ROM_RESOURCE].start);
index 627af507643a00453a2d97cf51257ebf405cd4c3..de88218ef7cce8c8eb4912aedb4bdffbd64f7561 100644 (file)
@@ -790,7 +790,7 @@ static void sbp2_host_reset(struct hpsb_host *host)
 static int sbp2_start_device(struct scsi_id_instance_data *scsi_id)
 {
        struct sbp2scsi_host_info *hi = scsi_id->hi;
-       struct scsi_device *sdev;
+       int error;
 
        SBP2_DEBUG("sbp2_start_device");
 
@@ -939,10 +939,10 @@ alloc_fail:
        sbp2_max_speed_and_size(scsi_id);
 
        /* Add this device to the scsi layer now */
-       sdev = scsi_add_device(scsi_id->scsi_host, 0, scsi_id->ud->id, 0);
-       if (IS_ERR(sdev)) {
+       error = scsi_add_device(scsi_id->scsi_host, 0, scsi_id->ud->id, 0);
+       if (error) {
                SBP2_ERR("scsi_add_device failed");
-               return PTR_ERR(sdev);
+               return error;
        }
 
        return 0;
index e55dee3907756425059612c4fe049ecc177d58b3..444f7756fee65fece09ab6ad7204e4205a132c5d 100644 (file)
@@ -132,6 +132,17 @@ config KEYBOARD_CORGI
          To compile this driver as a module, choose M here: the 
          module will be called corgikbd.
 
+config KEYBOARD_SPITZ
+       tristate "Spitz keyboard"
+       depends on PXA_SHARPSL
+       default y
+       help
+         Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
+         SL-C3000 and Sl-C3100 series of PDAs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called spitzkbd.
+
 config KEYBOARD_MAPLE
        tristate "Maple bus keyboard"
        depends on SH_DREAMCAST && MAPLE
index b02eeceea3c32a0b683e703f2d8aa8591b205151..9ce0b87f2facb9fc06fde3ffd497d52b88c0b72c 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_LOCOMO)         += locomokbd.o
 obj-$(CONFIG_KEYBOARD_NEWTON)          += newtonkbd.o
 obj-$(CONFIG_KEYBOARD_98KBD)           += 98kbd.o
 obj-$(CONFIG_KEYBOARD_CORGI)           += corgikbd.o
+obj-$(CONFIG_KEYBOARD_SPITZ)           += spitzkbd.o
 obj-$(CONFIG_KEYBOARD_HIL)             += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
 
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
new file mode 100644 (file)
index 0000000..1714045
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ *  Keyboard driver for Sharp Spitz, Borzoi and Akita (SL-Cxx00 series)
+ *
+ *  Copyright (c) 2005 Richard Purdie
+ *
+ *  Based on corgikbd.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+
+#include <asm/arch/spitz.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#define KB_ROWS                        7
+#define KB_COLS                        11
+#define KB_ROWMASK(r)          (1 << (r))
+#define SCANCODE(r,c)          (((r)<<4) + (c) + 1)
+#define        NR_SCANCODES            ((KB_ROWS<<4) + 1)
+
+#define HINGE_SCAN_INTERVAL    (150) /* ms */
+
+#define SPITZ_KEY_CALENDER     KEY_F1
+#define SPITZ_KEY_ADDRESS      KEY_F2
+#define SPITZ_KEY_FN           KEY_F3
+#define SPITZ_KEY_CANCEL       KEY_F4
+#define SPITZ_KEY_EXOK         KEY_F5
+#define SPITZ_KEY_EXCANCEL     KEY_F6
+#define SPITZ_KEY_EXJOGDOWN    KEY_F7
+#define SPITZ_KEY_EXJOGUP      KEY_F8
+#define SPITZ_KEY_JAP1         KEY_LEFTALT
+#define SPITZ_KEY_JAP2         KEY_RIGHTCTRL
+#define SPITZ_KEY_SYNC         KEY_F9
+#define SPITZ_KEY_MAIL         KEY_F10
+#define SPITZ_KEY_OK           KEY_F11
+#define SPITZ_KEY_MENU         KEY_F12
+
+static unsigned char spitzkbd_keycode[NR_SCANCODES] = {
+       0,                                                                                                                /* 0 */
+       KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0,  /* 1-16 */
+       0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */
+       KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0,                                 /* 33-48 */
+       SPITZ_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0,         /* 49-64 */
+       SPITZ_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0,     /* 65-80 */
+       SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0,      /* 81-96 */
+       KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0  /* 97-112 */
+};
+
+static int spitz_strobes[] = {
+       SPITZ_GPIO_KEY_STROBE0,
+       SPITZ_GPIO_KEY_STROBE1,
+       SPITZ_GPIO_KEY_STROBE2,
+       SPITZ_GPIO_KEY_STROBE3,
+       SPITZ_GPIO_KEY_STROBE4,
+       SPITZ_GPIO_KEY_STROBE5,
+       SPITZ_GPIO_KEY_STROBE6,
+       SPITZ_GPIO_KEY_STROBE7,
+       SPITZ_GPIO_KEY_STROBE8,
+       SPITZ_GPIO_KEY_STROBE9,
+       SPITZ_GPIO_KEY_STROBE10,
+};
+
+static int spitz_senses[] = {
+       SPITZ_GPIO_KEY_SENSE0,
+       SPITZ_GPIO_KEY_SENSE1,
+       SPITZ_GPIO_KEY_SENSE2,
+       SPITZ_GPIO_KEY_SENSE3,
+       SPITZ_GPIO_KEY_SENSE4,
+       SPITZ_GPIO_KEY_SENSE5,
+       SPITZ_GPIO_KEY_SENSE6,
+};
+
+struct spitzkbd {
+       unsigned char keycode[ARRAY_SIZE(spitzkbd_keycode)];
+       struct input_dev input;
+       char phys[32];
+
+       spinlock_t lock;
+       struct timer_list timer;
+       struct timer_list htimer;
+
+       unsigned int suspended;
+       unsigned long suspend_jiffies;
+};
+
+#define KB_DISCHARGE_DELAY     10
+#define KB_ACTIVATE_DELAY      10
+
+/* Helper functions for reading the keyboard matrix
+ * Note: We should really be using pxa_gpio_mode to alter GPDR but it
+ *       requires a function call per GPIO bit which is excessive
+ *       when we need to access 11 bits at once, multiple times.
+ * These functions must be called within local_irq_save()/local_irq_restore()
+ * or similar.
+ */
+static inline void spitzkbd_discharge_all(void)
+{
+       /* STROBE All HiZ */
+       GPCR0  =  SPITZ_GPIO_G0_STROBE_BIT;
+       GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+       GPCR1  =  SPITZ_GPIO_G1_STROBE_BIT;
+       GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+       GPCR2  =  SPITZ_GPIO_G2_STROBE_BIT;
+       GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+       GPCR3  =  SPITZ_GPIO_G3_STROBE_BIT;
+       GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+}
+
+static inline void spitzkbd_activate_all(void)
+{
+       /* STROBE ALL -> High */
+       GPSR0  =  SPITZ_GPIO_G0_STROBE_BIT;
+       GPDR0 |=  SPITZ_GPIO_G0_STROBE_BIT;
+       GPSR1  =  SPITZ_GPIO_G1_STROBE_BIT;
+       GPDR1 |=  SPITZ_GPIO_G1_STROBE_BIT;
+       GPSR2  =  SPITZ_GPIO_G2_STROBE_BIT;
+       GPDR2 |=  SPITZ_GPIO_G2_STROBE_BIT;
+       GPSR3  =  SPITZ_GPIO_G3_STROBE_BIT;
+       GPDR3 |=  SPITZ_GPIO_G3_STROBE_BIT;
+
+       udelay(KB_DISCHARGE_DELAY);
+
+       /* Clear any interrupts we may have triggered when altering the GPIO lines */
+       GEDR0 = SPITZ_GPIO_G0_SENSE_BIT;
+       GEDR1 = SPITZ_GPIO_G1_SENSE_BIT;
+       GEDR2 = SPITZ_GPIO_G2_SENSE_BIT;
+       GEDR3 = SPITZ_GPIO_G3_SENSE_BIT;
+}
+
+static inline void spitzkbd_activate_col(int col)
+{
+       int gpio = spitz_strobes[col];
+       GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+       GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+       GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+       GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+       GPSR(gpio) = GPIO_bit(gpio);
+       GPDR(gpio) |= GPIO_bit(gpio);
+}
+
+static inline void spitzkbd_reset_col(int col)
+{
+       int gpio = spitz_strobes[col];
+       GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+       GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+       GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+       GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+       GPCR(gpio) = GPIO_bit(gpio);
+       GPDR(gpio) |= GPIO_bit(gpio);
+}
+
+static inline int spitzkbd_get_row_status(int col)
+{
+       return ((GPLR0 >> 12) & 0x01) | ((GPLR0 >> 16) & 0x02)
+               | ((GPLR2 >> 25) & 0x04) | ((GPLR1 << 1) & 0x08)
+               | ((GPLR1 >> 0) & 0x10) | ((GPLR1 >> 1) & 0x60);
+}
+
+/*
+ * The spitz keyboard only generates interrupts when a key is pressed.
+ * When a key is pressed, we enable a timer which then scans the
+ * keyboard to detect when the key is released.
+ */
+
+/* Scan the hardware keyboard and push any changes up through the input layer */
+static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs *regs)
+{
+       unsigned int row, col, rowd;
+       unsigned long flags;
+       unsigned int num_pressed, pwrkey = ((GPLR(SPITZ_GPIO_ON_KEY) & GPIO_bit(SPITZ_GPIO_ON_KEY)) != 0);
+
+       if (spitzkbd_data->suspended)
+               return;
+
+       spin_lock_irqsave(&spitzkbd_data->lock, flags);
+
+       if (regs)
+               input_regs(&spitzkbd_data->input, regs);
+
+       num_pressed = 0;
+       for (col = 0; col < KB_COLS; col++) {
+               /*
+                * Discharge the output driver capacitatance
+                * in the keyboard matrix. (Yes it is significant..)
+                */
+
+               spitzkbd_discharge_all();
+               udelay(KB_DISCHARGE_DELAY);
+
+               spitzkbd_activate_col(col);
+               udelay(KB_ACTIVATE_DELAY);
+
+               rowd = spitzkbd_get_row_status(col);
+               for (row = 0; row < KB_ROWS; row++) {
+                       unsigned int scancode, pressed;
+
+                       scancode = SCANCODE(row, col);
+                       pressed = rowd & KB_ROWMASK(row);
+
+                       input_report_key(&spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed);
+
+                       if (pressed)
+                               num_pressed++;
+               }
+               spitzkbd_reset_col(col);
+       }
+
+       spitzkbd_activate_all();
+
+       input_report_key(&spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 );
+       input_report_key(&spitzkbd_data->input, KEY_SUSPEND, pwrkey);
+
+       if (pwrkey && time_after(jiffies, spitzkbd_data->suspend_jiffies + msecs_to_jiffies(1000))) {
+               input_event(&spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1);
+               spitzkbd_data->suspend_jiffies = jiffies;
+       }
+
+       input_sync(&spitzkbd_data->input);
+
+       /* if any keys are pressed, enable the timer */
+       if (num_pressed)
+               mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(100));
+
+       spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
+}
+
+/*
+ * spitz keyboard interrupt handler.
+ */
+static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct spitzkbd *spitzkbd_data = dev_id;
+
+       if (!timer_pending(&spitzkbd_data->timer)) {
+               /** wait chattering delay **/
+               udelay(20);
+               spitzkbd_scankeyboard(spitzkbd_data, regs);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * spitz timer checking for released keys
+ */
+static void spitzkbd_timer_callback(unsigned long data)
+{
+       struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
+       spitzkbd_scankeyboard(spitzkbd_data, NULL);
+}
+
+/*
+ * The hinge switches generate an interrupt.
+ * We debounce the switches and pass them to the input system.
+ */
+
+static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct spitzkbd *spitzkbd_data = dev_id;
+
+       if (!timer_pending(&spitzkbd_data->htimer))
+               mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
+
+       return IRQ_HANDLED;
+}
+
+#define HINGE_STABLE_COUNT 2
+static int sharpsl_hinge_state;
+static int hinge_count;
+
+static void spitzkbd_hinge_timer(unsigned long data)
+{
+       struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
+       unsigned long state;
+       unsigned long flags;
+
+       state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB));
+       if (state != sharpsl_hinge_state) {
+               hinge_count = 0;
+               sharpsl_hinge_state = state;
+       } else if (hinge_count < HINGE_STABLE_COUNT) {
+               hinge_count++;
+       }
+
+       if (hinge_count >= HINGE_STABLE_COUNT) {
+               spin_lock_irqsave(&spitzkbd_data->lock, flags);
+
+               input_report_switch(&spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0));
+               input_report_switch(&spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0));
+               input_sync(&spitzkbd_data->input);
+
+               spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
+       } else {
+               mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
+       }
+}
+
+#ifdef CONFIG_PM
+static int spitzkbd_suspend(struct device *dev, pm_message_t state, uint32_t level)
+{
+       if (level == SUSPEND_POWER_DOWN) {
+               int i;
+               struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+               spitzkbd->suspended = 1;
+
+               /* Set Strobe lines as inputs - *except* strobe line 0 leave this
+                  enabled so we can detect a power button press for resume */
+               for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++)
+                       pxa_gpio_mode(spitz_strobes[i] | GPIO_IN);
+       }
+       return 0;
+}
+
+static int spitzkbd_resume(struct device *dev, uint32_t level)
+{
+       if (level == RESUME_POWER_ON) {
+               int i;
+               struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+
+               for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++)
+                       pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH);
+
+               /* Upon resume, ignore the suspend key for a short while */
+               spitzkbd->suspend_jiffies = jiffies;
+               spitzkbd->suspended = 0;
+       }
+       return 0;
+}
+#else
+#define spitzkbd_suspend       NULL
+#define spitzkbd_resume                NULL
+#endif
+
+static int __init spitzkbd_probe(struct device *dev)
+{
+       int i;
+       struct spitzkbd *spitzkbd;
+
+       spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL);
+       if (!spitzkbd)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev,spitzkbd);
+       strcpy(spitzkbd->phys, "spitzkbd/input0");
+
+       spin_lock_init(&spitzkbd->lock);
+
+       /* Init Keyboard rescan timer */
+       init_timer(&spitzkbd->timer);
+       spitzkbd->timer.function = spitzkbd_timer_callback;
+       spitzkbd->timer.data = (unsigned long) spitzkbd;
+
+       /* Init Hinge Timer */
+       init_timer(&spitzkbd->htimer);
+       spitzkbd->htimer.function = spitzkbd_hinge_timer;
+       spitzkbd->htimer.data = (unsigned long) spitzkbd;
+
+       spitzkbd->suspend_jiffies=jiffies;
+
+       init_input_dev(&spitzkbd->input);
+       spitzkbd->input.private = spitzkbd;
+       spitzkbd->input.name = "Spitz Keyboard";
+       spitzkbd->input.dev = dev;
+       spitzkbd->input.phys = spitzkbd->phys;
+       spitzkbd->input.id.bustype = BUS_HOST;
+       spitzkbd->input.id.vendor = 0x0001;
+       spitzkbd->input.id.product = 0x0001;
+       spitzkbd->input.id.version = 0x0100;
+       spitzkbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
+       spitzkbd->input.keycode = spitzkbd->keycode;
+       spitzkbd->input.keycodesize = sizeof(unsigned char);
+       spitzkbd->input.keycodemax = ARRAY_SIZE(spitzkbd_keycode);
+
+       memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode));
+       for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++)
+               set_bit(spitzkbd->keycode[i], spitzkbd->input.keybit);
+       clear_bit(0, spitzkbd->input.keybit);
+       set_bit(SW_0, spitzkbd->input.swbit);
+       set_bit(SW_1, spitzkbd->input.swbit);
+
+       input_register_device(&spitzkbd->input);
+       mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
+
+       /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
+       for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) {
+               pxa_gpio_mode(spitz_senses[i] | GPIO_IN);
+               if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt,
+                                               SA_INTERRUPT, "Spitzkbd Sense", spitzkbd))
+                       printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i);
+               else
+                       set_irq_type(IRQ_GPIO(spitz_senses[i]),IRQT_RISING);
+       }
+
+       /* Set Strobe lines as outputs - set high */
+       for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++)
+               pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH);
+
+       pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN);
+       pxa_gpio_mode(SPITZ_GPIO_ON_KEY | GPIO_IN);
+       pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN);
+       pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN);
+
+       request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd Sync", spitzkbd);
+       request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd PwrOn", spitzkbd);
+       request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWA", spitzkbd);
+       request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWB", spitzkbd);
+
+       set_irq_type(SPITZ_IRQ_GPIO_SYNC, IRQT_BOTHEDGE);
+       set_irq_type(SPITZ_IRQ_GPIO_ON_KEY, IRQT_BOTHEDGE);
+       set_irq_type(SPITZ_IRQ_GPIO_SWA, IRQT_BOTHEDGE);
+       set_irq_type(SPITZ_IRQ_GPIO_SWB, IRQT_BOTHEDGE);
+
+       printk(KERN_INFO "input: Spitz Keyboard Registered\n");
+
+       return 0;
+}
+
+static int spitzkbd_remove(struct device *dev)
+{
+       int i;
+       struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+
+       for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++)
+               free_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd);
+
+       free_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd);
+       free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd);
+       free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd);
+       free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd);
+
+       del_timer_sync(&spitzkbd->htimer);
+       del_timer_sync(&spitzkbd->timer);
+
+       input_unregister_device(&spitzkbd->input);
+
+       kfree(spitzkbd);
+
+       return 0;
+}
+
+static struct device_driver spitzkbd_driver = {
+       .name           = "spitz-keyboard",
+       .bus            = &platform_bus_type,
+       .probe          = spitzkbd_probe,
+       .remove         = spitzkbd_remove,
+       .suspend        = spitzkbd_suspend,
+       .resume         = spitzkbd_resume,
+};
+
+static int __devinit spitzkbd_init(void)
+{
+       return driver_register(&spitzkbd_driver);
+}
+
+static void __exit spitzkbd_exit(void)
+{
+       driver_unregister(&spitzkbd_driver);
+}
+
+module_init(spitzkbd_init);
+module_exit(spitzkbd_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Spitz Keyboard Driver");
+MODULE_LICENSE("GPLv2");
index 0489af5a80c95bcdf67c2c87e3159bed004eec55..21d55ed4b88a69e08881a4b03f1ef9dbf20548d2 100644 (file)
@@ -24,17 +24,17 @@ config TOUCHSCREEN_BITSY
          module will be called h3600_ts_input.
 
 config TOUCHSCREEN_CORGI
-       tristate "Corgi touchscreen (for Sharp SL-C7xx)"
+       tristate "SharpSL (Corgi and Spitz series) touchscreen driver"
        depends on PXA_SHARPSL
        default y       
        help
          Say Y here to enable the driver for the touchscreen on the 
-         Sharp SL-C7xx series of PDAs.
+         Sharp SL-C7xx and SL-Cxx00 series of PDAs.
 
          If unsure, say N.
 
          To compile this driver as a module, choose M here: the
-         module will be called ads7846_ts.
+         module will be called corgi_ts.
 
 config TOUCHSCREEN_GUNZE
        tristate "Gunze AHL-51S touchscreen"
index 5d19261b884fe8f09ebe48432589011080942e41..4c7fbe55036540463974608157de2f4f11143931 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Touchscreen driver for Sharp Corgi models (SL-C7xx)
+ *  Touchscreen driver for Sharp SL-C7xx and SL-Cxx00 models
  *
  *  Copyright (c) 2004-2005 Richard Purdie
  *
@@ -19,7 +19,7 @@
 #include <linux/slab.h>
 #include <asm/irq.h>
 
-#include <asm/arch/corgi.h>
+#include <asm/arch/sharpsl.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/pxa-regs.h>
 
@@ -47,15 +47,20 @@ struct corgi_ts {
        struct ts_event tc;
        int pendown;
        int power_mode;
+       int irq_gpio;
+       struct corgits_machinfo *machinfo;
 };
 
-#define STATUS_HSYNC           (GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC))
-
-#define SyncHS()       while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
+#ifdef CONFIG_PXA25x
 #define CCNT(a)                asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
 #define PMNC_GET(x)    asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x))
 #define PMNC_SET(x)    asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x))
-
+#endif
+#ifdef CONFIG_PXA27x
+#define CCNT(a)                asm volatile ("mrc p14, 0, %0, C1, C1, 0" : "=r"(a))
+#define PMNC_GET(x)    asm volatile ("mrc p14, 0, %0, C0, C1, 0" : "=r"(x))
+#define PMNC_SET(x)    asm volatile ("mcr p14, 0, %0, C0, C1, 0" : : "r"(x))
+#endif
 
 /* ADS7846 Touch Screen Controller bit definitions */
 #define ADSCTRL_PD0            (1u << 0)       /* PD0 */
@@ -66,12 +71,11 @@ struct corgi_ts {
 #define ADSCTRL_STS            (1u << 7)       /* Start Bit */
 
 /* External Functions */
-extern unsigned long w100fb_get_hsynclen(struct device *dev);
 extern unsigned int get_clk_frequency_khz(int info);
 
-static unsigned long calc_waittime(void)
+static unsigned long calc_waittime(struct corgi_ts *corgi_ts)
 {
-       unsigned long hsync_len = w100fb_get_hsynclen(&corgifb_device.dev);
+       unsigned long hsync_len = corgi_ts->machinfo->get_hsync_len();
 
        if (hsync_len)
                return get_clk_frequency_khz(0)*1000/hsync_len;
@@ -79,7 +83,8 @@ static unsigned long calc_waittime(void)
                return 0;
 }
 
-static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
+static int sync_receive_data_send_cmd(struct corgi_ts *corgi_ts, int doRecive, int doSend,
+               unsigned int address, unsigned long wait_time)
 {
        unsigned long timer1 = 0, timer2, pmnc = 0;
        int pos = 0;
@@ -90,7 +95,7 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add
                        PMNC_SET(0x01);
 
                /* polling HSync */
-               SyncHS();
+               corgi_ts->machinfo->wait_hsync();
                /* get CCNT */
                CCNT(timer1);
        }
@@ -109,7 +114,7 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add
                        CCNT(timer2);
                        if (timer2-timer1 > wait_time) {
                                /* too slow - timeout, try again */
-                               SyncHS();
+                               corgi_ts->machinfo->wait_hsync();
                                /* get OSCR */
                                CCNT(timer1);
                                /* Wait after HSync */
@@ -133,23 +138,23 @@ static int read_xydata(struct corgi_ts *corgi_ts)
        /* critical section */
        local_irq_save(flags);
        corgi_ssp_ads7846_lock();
-       wait_time=calc_waittime();
+       wait_time = calc_waittime(corgi_ts);
 
        /* Y-axis */
-       sync_receive_data_send_cmd(0, 1, 1u, wait_time);
+       sync_receive_data_send_cmd(corgi_ts, 0, 1, 1u, wait_time);
 
        /* Y-axis */
-       sync_receive_data_send_cmd(1, 1, 1u, wait_time);
+       sync_receive_data_send_cmd(corgi_ts, 1, 1, 1u, wait_time);
 
        /* X-axis */
-       y = sync_receive_data_send_cmd(1, 1, 5u, wait_time);
+       y = sync_receive_data_send_cmd(corgi_ts, 1, 1, 5u, wait_time);
 
        /* Z1 */
-       x = sync_receive_data_send_cmd(1, 1, 3u, wait_time);
+       x = sync_receive_data_send_cmd(corgi_ts, 1, 1, 3u, wait_time);
 
        /* Z2 */
-       z1 = sync_receive_data_send_cmd(1, 1, 4u, wait_time);
-       z2 = sync_receive_data_send_cmd(1, 0, 4u, wait_time);
+       z1 = sync_receive_data_send_cmd(corgi_ts, 1, 1, 4u, wait_time);
+       z2 = sync_receive_data_send_cmd(corgi_ts, 1, 0, 4u, wait_time);
 
        /* Power-Down Enable */
        corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
@@ -189,9 +194,9 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
 
 static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs)
 {
-       if ((GPLR(CORGI_GPIO_TP_INT) & GPIO_bit(CORGI_GPIO_TP_INT)) == 0) {
+       if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) {
                /* Disable Interrupt */
-               set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_NOEDGE);
+               set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE);
                if (read_xydata(corgi_ts)) {
                        corgi_ts->pendown = 1;
                        new_data(corgi_ts, regs);
@@ -210,7 +215,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_
                }
 
                /* Enable Falling Edge */
-               set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+               set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING);
                corgi_ts->pendown = 0;
        }
 }
@@ -254,7 +259,7 @@ static int corgits_resume(struct device *dev, uint32_t level)
 
                corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
                /* Enable Falling Edge */
-               set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+               set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING);
                corgi_ts->power_mode = PWR_MODE_ACTIVE;
        }
        return 0;
@@ -267,6 +272,7 @@ static int corgits_resume(struct device *dev, uint32_t level)
 static int __init corgits_probe(struct device *dev)
 {
        struct corgi_ts *corgi_ts;
+       struct platform_device *pdev = to_platform_device(dev);
 
        if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL)))
                return -ENOMEM;
@@ -275,6 +281,14 @@ static int __init corgits_probe(struct device *dev)
 
        memset(corgi_ts, 0, sizeof(struct corgi_ts));
 
+       corgi_ts->machinfo = dev->platform_data;
+       corgi_ts->irq_gpio = platform_get_irq(pdev, 0);
+
+       if (corgi_ts->irq_gpio < 0) {
+               kfree(corgi_ts);
+               return -ENODEV;
+       }
+
        init_input_dev(&corgi_ts->input);
        corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
        corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
@@ -293,8 +307,7 @@ static int __init corgits_probe(struct device *dev)
        corgi_ts->input.id.product = 0x0002;
        corgi_ts->input.id.version = 0x0100;
 
-       pxa_gpio_mode(CORGI_GPIO_TP_INT | GPIO_IN);
-       pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
+       pxa_gpio_mode(IRQ_TO_GPIO(corgi_ts->irq_gpio) | GPIO_IN);
 
        /* Initiaize ADS7846 Difference Reference mode */
        corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
@@ -313,14 +326,14 @@ static int __init corgits_probe(struct device *dev)
        input_register_device(&corgi_ts->input);
        corgi_ts->power_mode = PWR_MODE_ACTIVE;
 
-       if (request_irq(CORGI_IRQ_GPIO_TP_INT, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
+       if (request_irq(corgi_ts->irq_gpio, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
                input_unregister_device(&corgi_ts->input);
                kfree(corgi_ts);
                return -EBUSY;
        }
 
        /* Enable Falling Edge */
-       set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+       set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING);
 
        printk(KERN_INFO "input: Corgi Touchscreen Registered\n");
 
@@ -331,8 +344,9 @@ static int corgits_remove(struct device *dev)
 {
        struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
 
-       free_irq(CORGI_IRQ_GPIO_TP_INT, NULL);
+       free_irq(corgi_ts->irq_gpio, NULL);
        del_timer_sync(&corgi_ts->timer);
+       corgi_ts->machinfo->put_hsync();
        input_unregister_device(&corgi_ts->input);
        kfree(corgi_ts);
        return 0;
index 40b0df04ed9f1620e2d36e8336bb243fda21ce88..1ebed041672d0c3876c892c515e218997a58f38a 100644 (file)
@@ -87,7 +87,7 @@ static int __init sc_init(void)
                         */
                        for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
                                if(!request_region(io[b] + i * 0x400, 1, "sc test")) {
-                                       pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400);
+                                       pr_debug("request_region for 0x%x failed\n", io[b] + i * 0x400);
                                        io[b] = 0;
                                        break;
                                } else
@@ -181,7 +181,7 @@ static int __init sc_init(void)
                        for (i = SRAM_MIN ; i < SRAM_MAX ; i += SRAM_PAGESIZE) {
                                pr_debug("Checking RAM address 0x%x...\n", i);
                                if(request_region(i, SRAM_PAGESIZE, "sc test")) {
-                                       pr_debug("  check_region succeeded\n");
+                                       pr_debug("  request_region succeeded\n");
                                        model = identify_board(i, io[b]);
                                        release_region(i, SRAM_PAGESIZE);
                                        if (model >= 0) {
index 8b4ad70dd1b2f30e197564a90df10cef1252a3fc..877c770558e9c407350da4ea90d92b2e875cefd2 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
-#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
index 013c835ed910d6c9a7d69783a96eb030f7221341..5319a9c9a9796bbf4e0d769a3e120cd98d5dc952 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
-#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
index 53d399b6652b87fb75406dff045b5f429233d6af..022913da8c5994dbfd0468b7fa51ff62b8f2cdcc 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
-#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
index 202bfe6819b887297c06492442de0dd4edacc8f6..6418f03b9ce4b74b1711e03a718efe952028bd06 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
-#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
index c00245d4d24900a59d90eb1e3ab54aaa51eca2b2..b2256d675b4434f8f8553b13d4892089a6edff6e 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
-#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
index 3a464a09221f959c7287ecd8847301c3e24dd798..6f03ce4dd7b0e4fb076c72dcfe9cdec20b122c8f 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/kernel.h>      /* __setup                      */
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
-#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev.h>    /* kernel radio structs         */
 #include <linux/isapnp.h>
index 0732efda6a9831da4f6862acdacf5b3befcd2dad..71971e9bb3422c36acb8280becdfbf03a9c37944 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
-#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
index 248d67fde037268df3d735f435ee561a00bce9f5..b03573c6840e56e632bd52f60aa90aabc45abc81 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
-#include <linux/ioport.h>      /* check_region, request_region */
+#include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <asm/io.h>            /* outb, outb_p                 */
 #include <asm/uaccess.h>       /* copy to/from user            */
index d7da901ebe90617f019360a93bc10dd3cbb587bf..f304f3c147637c92a7956f88c7fc548429f3338a 100644 (file)
@@ -31,7 +31,7 @@
 
 #include <linux/module.h>      /* Modules                        */
 #include <linux/init.h>                /* Initdata                       */
-#include <linux/ioport.h>      /* check_region, request_region   */
+#include <linux/ioport.h>      /* request_region                 */
 #include <linux/proc_fs.h>     /* radio card status report       */
 #include <asm/io.h>            /* outb, outb_p                   */
 #include <asm/uaccess.h>       /* copy to/from user              */
index 342f92df4aba7b924e151dba2c2369a187204371..4c6d6fb49034e04a04d1c2d220e574b5aed1d434 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <linux/module.h>      /* Modules                        */
 #include <linux/init.h>                /* Initdata                       */
-#include <linux/ioport.h>      /* check_region, request_region   */
+#include <linux/ioport.h>      /* request_region                 */
 #include <linux/delay.h>       /* udelay, msleep                 */
 #include <asm/io.h>            /* outb, outb_p                   */
 #include <asm/uaccess.h>       /* copy to/from user              */
index c9106b1d79dff67c83cdc442cdc01d02b6616ec1..4334744652de0b22c23122fa311190ff217e02e1 100644 (file)
@@ -221,9 +221,7 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe,
        int err;
 
        /* Put the analog decoder in standby to keep it quiet */
-       if (core->tda9887_conf) {
-               cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-       }
+       cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
 
        dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
        dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
@@ -402,6 +400,9 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
        }
 
+       /* Put the analog decoder in standby to keep it quiet */
+       cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
        /* register everything */
        return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
 }
index e11e55dc89249279fdbc9fb8c1c807cfb3e74dc1..3cbca7cbea801798bb7a1c7fb05462ed98fb89dd 100644 (file)
@@ -93,7 +93,7 @@ static int dma = 2;
 static inline void wbsd_unlock_config(struct wbsd_host* host)
 {
        BUG_ON(host->config == 0);
-       
+
        outb(host->unlock_code, host->config);
        outb(host->unlock_code, host->config);
 }
@@ -101,14 +101,14 @@ static inline void wbsd_unlock_config(struct wbsd_host* host)
 static inline void wbsd_lock_config(struct wbsd_host* host)
 {
        BUG_ON(host->config == 0);
-       
+
        outb(LOCK_CODE, host->config);
 }
 
 static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
 {
        BUG_ON(host->config == 0);
-       
+
        outb(reg, host->config);
        outb(value, host->config + 1);
 }
@@ -116,7 +116,7 @@ static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
 static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg)
 {
        BUG_ON(host->config == 0);
-       
+
        outb(reg, host->config);
        return inb(host->config + 1);
 }
@@ -140,21 +140,21 @@ static inline u8 wbsd_read_index(struct wbsd_host* host, u8 index)
 static void wbsd_init_device(struct wbsd_host* host)
 {
        u8 setup, ier;
-       
+
        /*
         * Reset chip (SD/MMC part) and fifo.
         */
        setup = wbsd_read_index(host, WBSD_IDX_SETUP);
        setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
        wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-       
+
        /*
         * Set DAT3 to input
         */
        setup &= ~WBSD_DAT3_H;
        wbsd_write_index(host, WBSD_IDX_SETUP, setup);
        host->flags &= ~WBSD_FIGNORE_DETECT;
-       
+
        /*
         * Read back default clock.
         */
@@ -164,12 +164,12 @@ static void wbsd_init_device(struct wbsd_host* host)
         * Power down port.
         */
        outb(WBSD_POWER_N, host->base + WBSD_CSR);
-       
+
        /*
         * Set maximum timeout.
         */
        wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
-       
+
        /*
         * Test for card presence
         */
@@ -177,7 +177,7 @@ static void wbsd_init_device(struct wbsd_host* host)
                host->flags |= WBSD_FCARD_PRESENT;
        else
                host->flags &= ~WBSD_FCARD_PRESENT;
-       
+
        /*
         * Enable interesting interrupts.
         */
@@ -200,9 +200,9 @@ static void wbsd_init_device(struct wbsd_host* host)
 static void wbsd_reset(struct wbsd_host* host)
 {
        u8 setup;
-       
+
        printk(KERN_ERR DRIVER_NAME ": Resetting chip\n");
-       
+
        /*
         * Soft reset of chip (SD/MMC part).
         */
@@ -214,9 +214,9 @@ static void wbsd_reset(struct wbsd_host* host)
 static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq)
 {
        unsigned long dmaflags;
-       
+
        DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-       
+
        if (host->dma >= 0)
        {
                /*
@@ -232,7 +232,7 @@ static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq)
                 */
                wbsd_write_index(host, WBSD_IDX_DMA, 0);
        }
-       
+
        host->mrq = NULL;
 
        /*
@@ -275,7 +275,7 @@ static inline int wbsd_next_sg(struct wbsd_host* host)
            host->offset = 0;
            host->remain = host->cur_sg->length;
          }
-       
+
        return host->num_sg;
 }
 
@@ -297,12 +297,12 @@ static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data)
        struct scatterlist* sg;
        char* dmabuf = host->dma_buffer;
        char* sgbuf;
-       
+
        size = host->size;
-       
+
        sg = data->sg;
        len = data->sg_len;
-       
+
        /*
         * Just loop through all entries. Size might not
         * be the entire list though so make sure that
@@ -317,23 +317,23 @@ static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data)
                        memcpy(dmabuf, sgbuf, sg[i].length);
                kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
                dmabuf += sg[i].length;
-               
+
                if (size < sg[i].length)
                        size = 0;
                else
                        size -= sg[i].length;
-       
+
                if (size == 0)
                        break;
        }
-       
+
        /*
         * Check that we didn't get a request to transfer
         * more data than can fit into the SG list.
         */
-       
+
        BUG_ON(size != 0);
-       
+
        host->size -= size;
 }
 
@@ -343,12 +343,12 @@ static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data)
        struct scatterlist* sg;
        char* dmabuf = host->dma_buffer;
        char* sgbuf;
-       
+
        size = host->size;
-       
+
        sg = data->sg;
        len = data->sg_len;
-       
+
        /*
         * Just loop through all entries. Size might not
         * be the entire list though so make sure that
@@ -363,30 +363,30 @@ static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data)
                        memcpy(sgbuf, dmabuf, sg[i].length);
                kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
                dmabuf += sg[i].length;
-               
+
                if (size < sg[i].length)
                        size = 0;
                else
                        size -= sg[i].length;
-               
+
                if (size == 0)
                        break;
        }
-       
+
        /*
         * Check that we didn't get a request to transfer
         * more data than can fit into the SG list.
         */
-       
+
        BUG_ON(size != 0);
-       
+
        host->size -= size;
 }
 
 /*
  * Command handling
  */
+
 static inline void wbsd_get_short_reply(struct wbsd_host* host,
        struct mmc_command* cmd)
 {
@@ -398,7 +398,7 @@ static inline void wbsd_get_short_reply(struct wbsd_host* host,
                cmd->error = MMC_ERR_INVALID;
                return;
        }
-       
+
        cmd->resp[0] =
                wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
        cmd->resp[0] |=
@@ -415,7 +415,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host,
        struct mmc_command* cmd)
 {
        int i;
-       
+
        /*
         * Correct response type?
         */
@@ -424,7 +424,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host,
                cmd->error = MMC_ERR_INVALID;
                return;
        }
-       
+
        for (i = 0;i < 4;i++)
        {
                cmd->resp[i] =
@@ -442,7 +442,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
 {
        int i;
        u8 status, isr;
-       
+
        DBGF("Sending cmd (%x)\n", cmd->opcode);
 
        /*
@@ -451,16 +451,16 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
         * transfer.
         */
        host->isr = 0;
-       
+
        /*
         * Send the command (CRC calculated by host).
         */
        outb(cmd->opcode, host->base + WBSD_CMDR);
        for (i = 3;i >= 0;i--)
                outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
-       
+
        cmd->error = MMC_ERR_NONE;
-       
+
        /*
         * Wait for the request to complete.
         */
@@ -477,7 +477,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
                 * Read back status.
                 */
                isr = host->isr;
-               
+
                /* Card removed? */
                if (isr & WBSD_INT_CARD)
                        cmd->error = MMC_ERR_TIMEOUT;
@@ -509,13 +509,13 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
        struct mmc_data* data = host->mrq->cmd->data;
        char* buffer;
        int i, fsr, fifo;
-       
+
        /*
         * Handle excessive data.
         */
        if (data->bytes_xfered == host->size)
                return;
-       
+
        buffer = wbsd_kmap_sg(host) + host->offset;
 
        /*
@@ -527,14 +527,14 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
                /*
                 * The size field in the FSR is broken so we have to
                 * do some guessing.
-                */             
+                */
                if (fsr & WBSD_FIFO_FULL)
                        fifo = 16;
                else if (fsr & WBSD_FIFO_FUTHRE)
                        fifo = 8;
                else
                        fifo = 1;
-               
+
                for (i = 0;i < fifo;i++)
                {
                        *buffer = inb(host->base + WBSD_DFR);
@@ -543,23 +543,23 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
                        host->remain--;
 
                        data->bytes_xfered++;
-                       
+
                        /*
                         * Transfer done?
                         */
                        if (data->bytes_xfered == host->size)
                        {
-                               wbsd_kunmap_sg(host);                           
+                               wbsd_kunmap_sg(host);
                                return;
                        }
-                       
+
                        /*
                         * End of scatter list entry?
                         */
                        if (host->remain == 0)
                        {
                                wbsd_kunmap_sg(host);
-                               
+
                                /*
                                 * Get next entry. Check if last.
                                 */
@@ -572,17 +572,17 @@ static void wbsd_empty_fifo(struct wbsd_host* host)
                                         * into the scatter list.
                                         */
                                        BUG_ON(1);
-                                       
+
                                        host->size = data->bytes_xfered;
-                                       
+
                                        return;
                                }
-                               
+
                                buffer = wbsd_kmap_sg(host);
                        }
                }
        }
-       
+
        wbsd_kunmap_sg(host);
 
        /*
@@ -599,7 +599,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
        struct mmc_data* data = host->mrq->cmd->data;
        char* buffer;
        int i, fsr, fifo;
-       
+
        /*
         * Check that we aren't being called after the
         * entire buffer has been transfered.
@@ -618,7 +618,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
                /*
                 * The size field in the FSR is broken so we have to
                 * do some guessing.
-                */             
+                */
                if (fsr & WBSD_FIFO_EMPTY)
                        fifo = 0;
                else if (fsr & WBSD_FIFO_EMTHRE)
@@ -632,9 +632,9 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
                        buffer++;
                        host->offset++;
                        host->remain--;
-                       
+
                        data->bytes_xfered++;
-                       
+
                        /*
                         * Transfer done?
                         */
@@ -650,7 +650,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
                        if (host->remain == 0)
                        {
                                wbsd_kunmap_sg(host);
-                               
+
                                /*
                                 * Get next entry. Check if last.
                                 */
@@ -663,19 +663,19 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
                                         * into the scatter list.
                                         */
                                        BUG_ON(1);
-                                       
+
                                        host->size = data->bytes_xfered;
-                                       
+
                                        return;
                                }
-                               
+
                                buffer = wbsd_kmap_sg(host);
                        }
                }
        }
-       
+
        wbsd_kunmap_sg(host);
-       
+
        /*
         * The controller stops sending interrupts for
         * 'FIFO empty' under certain conditions. So we
@@ -694,7 +694,7 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
                1 << data->blksz_bits, data->blocks, data->flags);
        DBGF("tsac %d ms nsac %d clk\n",
                data->timeout_ns / 1000000, data->timeout_clks);
-       
+
        /*
         * Calculate size.
         */
@@ -708,12 +708,12 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
                wbsd_write_index(host, WBSD_IDX_TAAC, 127);
        else
                wbsd_write_index(host, WBSD_IDX_TAAC, data->timeout_ns/1000000);
-       
+
        if (data->timeout_clks > 255)
                wbsd_write_index(host, WBSD_IDX_NSAC, 255);
        else
                wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks);
-       
+
        /*
         * Inform the chip of how large blocks will be
         * sent. It needs this to determine when to
@@ -732,7 +732,7 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
        else if (host->bus_width == MMC_BUS_WIDTH_4)
        {
                blksize = (1 << data->blksz_bits) + 2 * 4;
-       
+
                wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0)
                        | WBSD_DATA_WIDTH);
                wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
@@ -751,12 +751,12 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
        setup = wbsd_read_index(host, WBSD_IDX_SETUP);
        setup |= WBSD_FIFO_RESET;
        wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-       
+
        /*
         * DMA transfer?
         */
        if (host->dma >= 0)
-       {       
+       {
                /*
                 * The buffer for DMA is only 64 kB.
                 */
@@ -766,17 +766,17 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
                        data->error = MMC_ERR_INVALID;
                        return;
                }
-               
+
                /*
                 * Transfer data from the SG list to
                 * the DMA buffer.
                 */
                if (data->flags & MMC_DATA_WRITE)
                        wbsd_sg_to_dma(host, data);
-               
+
                /*
                 * Initialise the ISA DMA controller.
-                */     
+                */
                dmaflags = claim_dma_lock();
                disable_dma(host->dma);
                clear_dma_ff(host->dma);
@@ -802,17 +802,17 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
                 * output to a minimum.
                 */
                host->firsterr = 1;
-               
+
                /*
                 * Initialise the SG list.
                 */
                wbsd_init_sg(host, data);
-       
+
                /*
                 * Turn off DMA.
                 */
                wbsd_write_index(host, WBSD_IDX_DMA, 0);
-       
+
                /*
                 * Set up FIFO threshold levels (and fill
                 * buffer if doing a write).
@@ -828,8 +828,8 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
                                WBSD_FIFOEN_EMPTY | 8);
                        wbsd_fill_fifo(host);
                }
-       }       
-               
+       }
+
        data->error = MMC_ERR_NONE;
 }
 
@@ -838,7 +838,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
        unsigned long dmaflags;
        int count;
        u8 status;
-       
+
        WARN_ON(host->mrq == NULL);
 
        /*
@@ -855,7 +855,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
        {
                status = wbsd_read_index(host, WBSD_IDX_STATUS);
        } while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE));
-       
+
        /*
         * DMA transfer?
         */
@@ -865,7 +865,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
                 * Disable DMA on the host.
                 */
                wbsd_write_index(host, WBSD_IDX_DMA, 0);
-               
+
                /*
                 * Turn of ISA DMA controller.
                 */
@@ -874,7 +874,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
                clear_dma_ff(host->dma);
                count = get_dma_residue(host->dma);
                release_dma_lock(dmaflags);
-               
+
                /*
                 * Any leftover data?
                 */
@@ -882,7 +882,7 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
                {
                        printk(KERN_ERR DRIVER_NAME ": Incomplete DMA "
                                "transfer. %d bytes left.\n", count);
-                       
+
                        data->error = MMC_ERR_FAILED;
                }
                else
@@ -893,13 +893,13 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
                         */
                        if (data->flags & MMC_DATA_READ)
                                wbsd_dma_to_sg(host, data);
-                       
+
                        data->bytes_xfered = host->size;
                }
        }
-       
+
        DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-       
+
        wbsd_request_end(host, host->mrq);
 }
 
@@ -924,7 +924,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
        cmd = mrq->cmd;
 
        host->mrq = mrq;
-       
+
        /*
         * If there is no card in the slot then
         * timeout immediatly.
@@ -941,18 +941,18 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
        if (cmd->data)
        {
                wbsd_prepare_data(host, cmd->data);
-               
+
                if (cmd->data->error != MMC_ERR_NONE)
                        goto done;
        }
-       
+
        wbsd_send_command(host, cmd);
 
        /*
         * If this is a data transfer the request
         * will be finished after the data has
         * transfered.
-        */     
+        */
        if (cmd->data && (cmd->error == MMC_ERR_NONE))
        {
                /*
@@ -965,7 +965,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
 
                return;
        }
-               
+
 done:
        wbsd_request_end(host, mrq);
 
@@ -976,7 +976,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
 {
        struct wbsd_host* host = mmc_priv(mmc);
        u8 clk, setup, pwr;
-       
+
        DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
             ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select,
             ios->vdd, ios->bus_width);
@@ -989,7 +989,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
         */
        if (ios->power_mode == MMC_POWER_OFF)
                wbsd_init_device(host);
-       
+
        if (ios->clock >= 24000000)
                clk = WBSD_CLK_24M;
        else if (ios->clock >= 16000000)
@@ -1042,7 +1042,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
                mod_timer(&host->ignore_timer, jiffies + HZ/100);
        }
        wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-       
+
        /*
         * Store bus width for later. Will be used when
         * setting up the data transfer.
@@ -1128,7 +1128,7 @@ static inline struct mmc_data* wbsd_get_data(struct wbsd_host* host)
        WARN_ON(!host->mrq->cmd->data);
        if (!host->mrq->cmd->data)
                return NULL;
-       
+
        return host->mrq->cmd->data;
 }
 
@@ -1136,72 +1136,67 @@ static void wbsd_tasklet_card(unsigned long param)
 {
        struct wbsd_host* host = (struct wbsd_host*)param;
        u8 csr;
-       
+       int delay = -1;
+
        spin_lock(&host->lock);
-       
+
        if (host->flags & WBSD_FIGNORE_DETECT)
        {
                spin_unlock(&host->lock);
                return;
        }
-       
+
        csr = inb(host->base + WBSD_CSR);
        WARN_ON(csr == 0xff);
-       
+
        if (csr & WBSD_CARDPRESENT)
        {
                if (!(host->flags & WBSD_FCARD_PRESENT))
                {
                        DBG("Card inserted\n");
                        host->flags |= WBSD_FCARD_PRESENT;
-                       
-                       spin_unlock(&host->lock);
 
-                       /*
-                        * Delay card detection to allow electrical connections
-                        * to stabilise.
-                        */
-                       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+                       delay = 500;
                }
-               else
-                       spin_unlock(&host->lock);
        }
        else if (host->flags & WBSD_FCARD_PRESENT)
        {
                DBG("Card removed\n");
                host->flags &= ~WBSD_FCARD_PRESENT;
-               
+
                if (host->mrq)
                {
                        printk(KERN_ERR DRIVER_NAME
                                ": Card removed during transfer!\n");
                        wbsd_reset(host);
-                       
+
                        host->mrq->cmd->error = MMC_ERR_FAILED;
                        tasklet_schedule(&host->finish_tasklet);
                }
-               
-               /*
-                * Unlock first since we might get a call back.
-                */
-               spin_unlock(&host->lock);
 
-               mmc_detect_change(host->mmc, 0);
+               delay = 0;
        }
-       else
-               spin_unlock(&host->lock);
+
+       /*
+        * Unlock first since we might get a call back.
+        */
+
+       spin_unlock(&host->lock);
+
+       if (delay != -1)
+               mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
 }
 
 static void wbsd_tasklet_fifo(unsigned long param)
 {
        struct wbsd_host* host = (struct wbsd_host*)param;
        struct mmc_data* data;
-       
+
        spin_lock(&host->lock);
-               
+
        if (!host->mrq)
                goto end;
-       
+
        data = wbsd_get_data(host);
        if (!data)
                goto end;
@@ -1220,7 +1215,7 @@ static void wbsd_tasklet_fifo(unsigned long param)
                tasklet_schedule(&host->finish_tasklet);
        }
 
-end:   
+end:
        spin_unlock(&host->lock);
 }
 
@@ -1228,23 +1223,23 @@ static void wbsd_tasklet_crc(unsigned long param)
 {
        struct wbsd_host* host = (struct wbsd_host*)param;
        struct mmc_data* data;
-       
+
        spin_lock(&host->lock);
-       
+
        if (!host->mrq)
                goto end;
-       
+
        data = wbsd_get_data(host);
        if (!data)
                goto end;
-       
+
        DBGF("CRC error\n");
 
        data->error = MMC_ERR_BADCRC;
-       
+
        tasklet_schedule(&host->finish_tasklet);
 
-end:           
+end:
        spin_unlock(&host->lock);
 }
 
@@ -1252,23 +1247,23 @@ static void wbsd_tasklet_timeout(unsigned long param)
 {
        struct wbsd_host* host = (struct wbsd_host*)param;
        struct mmc_data* data;
-       
+
        spin_lock(&host->lock);
-       
+
        if (!host->mrq)
                goto end;
-       
+
        data = wbsd_get_data(host);
        if (!data)
                goto end;
-       
+
        DBGF("Timeout\n");
 
        data->error = MMC_ERR_TIMEOUT;
-       
+
        tasklet_schedule(&host->finish_tasklet);
 
-end:   
+end:
        spin_unlock(&host->lock);
 }
 
@@ -1276,20 +1271,20 @@ static void wbsd_tasklet_finish(unsigned long param)
 {
        struct wbsd_host* host = (struct wbsd_host*)param;
        struct mmc_data* data;
-       
+
        spin_lock(&host->lock);
-       
+
        WARN_ON(!host->mrq);
        if (!host->mrq)
                goto end;
-       
+
        data = wbsd_get_data(host);
        if (!data)
                goto end;
 
        wbsd_finish_data(host, data);
-       
-end:   
+
+end:
        spin_unlock(&host->lock);
 }
 
@@ -1297,7 +1292,7 @@ static void wbsd_tasklet_block(unsigned long param)
 {
        struct wbsd_host* host = (struct wbsd_host*)param;
        struct mmc_data* data;
-       
+
        spin_lock(&host->lock);
 
        if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) !=
@@ -1306,15 +1301,15 @@ static void wbsd_tasklet_block(unsigned long param)
                data = wbsd_get_data(host);
                if (!data)
                        goto end;
-               
+
                DBGF("CRC error\n");
 
                data->error = MMC_ERR_BADCRC;
-       
+
                tasklet_schedule(&host->finish_tasklet);
        }
 
-end:   
+end:
        spin_unlock(&host->lock);
 }
 
@@ -1326,7 +1321,7 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
        struct wbsd_host* host = dev_id;
        int isr;
-       
+
        isr = inb(host->base + WBSD_ISR);
 
        /*
@@ -1334,7 +1329,7 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
         */
        if (isr == 0xff || isr == 0x00)
                return IRQ_NONE;
-       
+
        host->isr |= isr;
 
        /*
@@ -1352,7 +1347,7 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
                tasklet_hi_schedule(&host->block_tasklet);
        if (isr & WBSD_INT_TC)
                tasklet_schedule(&host->finish_tasklet);
-       
+
        return IRQ_HANDLED;
 }
 
@@ -1370,14 +1365,14 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
 {
        struct mmc_host* mmc;
        struct wbsd_host* host;
-       
+
        /*
         * Allocate MMC structure.
         */
        mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
        if (!mmc)
                return -ENOMEM;
-       
+
        host = mmc_priv(mmc);
        host->mmc = mmc;
 
@@ -1391,37 +1386,37 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
        mmc->f_max = 24000000;
        mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
        mmc->caps = MMC_CAP_4_BIT_DATA;
-       
+
        spin_lock_init(&host->lock);
-       
+
        /*
         * Set up timers
         */
        init_timer(&host->ignore_timer);
        host->ignore_timer.data = (unsigned long)host;
        host->ignore_timer.function = wbsd_reset_ignore;
-       
+
        /*
         * Maximum number of segments. Worst case is one sector per segment
         * so this will be 64kB/512.
         */
        mmc->max_hw_segs = 128;
        mmc->max_phys_segs = 128;
-       
+
        /*
         * Maximum number of sectors in one transfer. Also limited by 64kB
         * buffer.
         */
        mmc->max_sectors = 128;
-       
+
        /*
         * Maximum segment size. Could be one segment with the maximum number
         * of segments.
         */
        mmc->max_seg_size = mmc->max_sectors * 512;
-       
+
        dev_set_drvdata(dev, mmc);
-       
+
        return 0;
 }
 
@@ -1429,18 +1424,18 @@ static void __devexit wbsd_free_mmc(struct device* dev)
 {
        struct mmc_host* mmc;
        struct wbsd_host* host;
-       
+
        mmc = dev_get_drvdata(dev);
        if (!mmc)
                return;
-       
+
        host = mmc_priv(mmc);
        BUG_ON(host == NULL);
-       
+
        del_timer_sync(&host->ignore_timer);
-       
+
        mmc_free_host(mmc);
-       
+
        dev_set_drvdata(dev, NULL);
 }
 
@@ -1452,7 +1447,7 @@ static int __devinit wbsd_scan(struct wbsd_host* host)
 {
        int i, j, k;
        int id;
-       
+
        /*
         * Iterate through all ports, all codes to
         * find hardware that is in our known list.
@@ -1461,32 +1456,32 @@ static int __devinit wbsd_scan(struct wbsd_host* host)
        {
                if (!request_region(config_ports[i], 2, DRIVER_NAME))
                        continue;
-                       
+
                for (j = 0;j < sizeof(unlock_codes)/sizeof(int);j++)
                {
                        id = 0xFFFF;
-                       
+
                        outb(unlock_codes[j], config_ports[i]);
                        outb(unlock_codes[j], config_ports[i]);
-                       
+
                        outb(WBSD_CONF_ID_HI, config_ports[i]);
                        id = inb(config_ports[i] + 1) << 8;
 
                        outb(WBSD_CONF_ID_LO, config_ports[i]);
                        id |= inb(config_ports[i] + 1);
-                       
+
                        for (k = 0;k < sizeof(valid_ids)/sizeof(int);k++)
                        {
                                if (id == valid_ids[k])
-                               {                               
+                               {
                                        host->chip_id = id;
                                        host->config = config_ports[i];
                                        host->unlock_code = unlock_codes[i];
-                               
+
                                        return 0;
                                }
                        }
-                       
+
                        if (id != 0xFFFF)
                        {
                                DBG("Unknown hardware (id %x) found at %x\n",
@@ -1495,10 +1490,10 @@ static int __devinit wbsd_scan(struct wbsd_host* host)
 
                        outb(LOCK_CODE, config_ports[i]);
                }
-               
+
                release_region(config_ports[i], 2);
        }
-       
+
        return -ENODEV;
 }
 
@@ -1510,12 +1505,12 @@ static int __devinit wbsd_request_region(struct wbsd_host* host, int base)
 {
        if (io & 0x7)
                return -EINVAL;
-       
+
        if (!request_region(base, 8, DRIVER_NAME))
                return -EIO;
-       
+
        host->base = io;
-               
+
        return 0;
 }
 
@@ -1523,12 +1518,12 @@ static void __devexit wbsd_release_regions(struct wbsd_host* host)
 {
        if (host->base)
                release_region(host->base, 8);
-       
+
        host->base = 0;
 
        if (host->config)
                release_region(host->config, 2);
-       
+
        host->config = 0;
 }
 
@@ -1540,10 +1535,10 @@ static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma)
 {
        if (dma < 0)
                return;
-       
+
        if (request_dma(dma, DRIVER_NAME))
                goto err;
-       
+
        /*
         * We need to allocate a special buffer in
         * order for ISA to be able to DMA to it.
@@ -1558,7 +1553,7 @@ static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma)
         */
        host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer,
                WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
-                       
+
        /*
         * ISA DMA must be aligned on a 64k basis.
         */
@@ -1571,19 +1566,19 @@ static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma)
                goto kfree;
 
        host->dma = dma;
-       
+
        return;
-       
+
 kfree:
        /*
         * If we've gotten here then there is some kind of alignment bug
         */
        BUG_ON(1);
-       
+
        dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
                DMA_BIDIRECTIONAL);
        host->dma_addr = (dma_addr_t)NULL;
-       
+
        kfree(host->dma_buffer);
        host->dma_buffer = NULL;
 
@@ -1604,7 +1599,7 @@ static void __devexit wbsd_release_dma(struct wbsd_host* host)
                kfree(host->dma_buffer);
        if (host->dma >= 0)
                free_dma(host->dma);
-       
+
        host->dma = -1;
        host->dma_buffer = NULL;
        host->dma_addr = (dma_addr_t)NULL;
@@ -1617,7 +1612,7 @@ static void __devexit wbsd_release_dma(struct wbsd_host* host)
 static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
 {
        int ret;
-       
+
        /*
         * Allocate interrupt.
         */
@@ -1625,7 +1620,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
        ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
        if (ret)
                return ret;
-       
+
        host->irq = irq;
 
        /*
@@ -1637,7 +1632,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
        tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
        tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
        tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
-       
+
        return 0;
 }
 
@@ -1647,9 +1642,9 @@ static void __devexit wbsd_release_irq(struct wbsd_host* host)
                return;
 
        free_irq(host->irq, host);
-       
+
        host->irq = 0;
-               
+
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->fifo_tasklet);
        tasklet_kill(&host->crc_tasklet);
@@ -1666,7 +1661,7 @@ static int __devinit wbsd_request_resources(struct wbsd_host* host,
        int base, int irq, int dma)
 {
        int ret;
-       
+
        /*
         * Allocate I/O ports.
         */
@@ -1685,7 +1680,7 @@ static int __devinit wbsd_request_resources(struct wbsd_host* host,
         * Allocate DMA.
         */
        wbsd_request_dma(host, dma);
-       
+
        return 0;
 }
 
@@ -1708,7 +1703,7 @@ static void __devinit wbsd_chip_config(struct wbsd_host* host)
 {
        /*
         * Reset the chip.
-        */     
+        */
        wbsd_write_config(host, WBSD_CONF_SWRST, 1);
        wbsd_write_config(host, WBSD_CONF_SWRST, 0);
 
@@ -1716,23 +1711,23 @@ static void __devinit wbsd_chip_config(struct wbsd_host* host)
         * Select SD/MMC function.
         */
        wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-       
+
        /*
         * Set up card detection.
         */
        wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
-       
+
        /*
         * Configure chip
         */
        wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
        wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
-       
+
        wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
-       
+
        if (host->dma >= 0)
                wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
-       
+
        /*
         * Enable and power up chip.
         */
@@ -1743,26 +1738,26 @@ static void __devinit wbsd_chip_config(struct wbsd_host* host)
 /*
  * Check that configured resources are correct.
  */
+
 static int __devinit wbsd_chip_validate(struct wbsd_host* host)
 {
        int base, irq, dma;
-       
+
        /*
         * Select SD/MMC function.
         */
        wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-       
+
        /*
         * Read configuration.
         */
        base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
        base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
-       
+
        irq = wbsd_read_config(host, WBSD_CONF_IRQ);
-       
+
        dma = wbsd_read_config(host, WBSD_CONF_DRQ);
-       
+
        /*
         * Validate against given configuration.
         */
@@ -1772,7 +1767,7 @@ static int __devinit wbsd_chip_validate(struct wbsd_host* host)
                return 0;
        if ((dma != host->dma) && (host->dma != -1))
                return 0;
-       
+
        return 1;
 }
 
@@ -1788,14 +1783,14 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
        struct wbsd_host* host = NULL;
        struct mmc_host* mmc = NULL;
        int ret;
-       
+
        ret = wbsd_alloc_mmc(dev);
        if (ret)
                return ret;
-       
+
        mmc = dev_get_drvdata(dev);
        host = mmc_priv(mmc);
-       
+
        /*
         * Scan for hardware.
         */
@@ -1814,7 +1809,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
                        return ret;
                }
        }
-       
+
        /*
         * Request resources.
         */
@@ -1825,7 +1820,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
                wbsd_free_mmc(dev);
                return ret;
        }
-       
+
        /*
         * See if chip needs to be configured.
         */
@@ -1842,7 +1837,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
        }
        else
                wbsd_chip_config(host);
-       
+
        /*
         * Power Management stuff. No idea how this works.
         * Not tested.
@@ -1860,7 +1855,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
         * Reset the chip into a known state.
         */
        wbsd_init_device(host);
-       
+
        mmc_add_host(mmc);
 
        printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));
@@ -1882,12 +1877,12 @@ static void __devexit wbsd_shutdown(struct device* dev, int pnp)
 {
        struct mmc_host* mmc = dev_get_drvdata(dev);
        struct wbsd_host* host;
-       
+
        if (!mmc)
                return;
 
        host = mmc_priv(mmc);
-       
+
        mmc_remove_host(mmc);
 
        if (!pnp)
@@ -1900,9 +1895,9 @@ static void __devexit wbsd_shutdown(struct device* dev, int pnp)
                wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
                wbsd_lock_config(host);
        }
-       
+
        wbsd_release_resources(host);
-       
+
        wbsd_free_mmc(dev);
 }
 
@@ -1932,7 +1927,7 @@ static int __devinit
 wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id)
 {
        int io, irq, dma;
-       
+
        /*
         * Get resources from PnP layer.
         */
@@ -1942,9 +1937,9 @@ wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id)
                dma = pnp_dma(pnpdev, 0);
        else
                dma = -1;
-       
+
        DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
-       
+
        return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
 }
 
@@ -1985,7 +1980,7 @@ static struct device_driver wbsd_driver = {
        .bus            = &platform_bus_type,
        .probe          = wbsd_probe,
        .remove         = wbsd_remove,
-       
+
        .suspend        = wbsd_suspend,
        .resume         = wbsd_resume,
 };
@@ -2008,7 +2003,7 @@ static struct pnp_driver wbsd_pnp_driver = {
 static int __init wbsd_drv_init(void)
 {
        int result;
-       
+
        printk(KERN_INFO DRIVER_NAME
                ": Winbond W83L51xD SD/MMC card interface driver, "
                DRIVER_VERSION "\n");
@@ -2023,8 +2018,8 @@ static int __init wbsd_drv_init(void)
                        return result;
        }
 
-#endif /* CONFIG_PNP */        
-       
+#endif /* CONFIG_PNP */
+
        if (nopnp)
        {
                result = driver_register(&wbsd_driver);
@@ -2046,13 +2041,13 @@ static void __exit wbsd_drv_exit(void)
 
        if (!nopnp)
                pnp_unregister_driver(&wbsd_pnp_driver);
-       
-#endif /* CONFIG_PNP */        
+
+#endif /* CONFIG_PNP */
 
        if (nopnp)
        {
                platform_device_unregister(wbsd_device);
-       
+
                driver_unregister(&wbsd_driver);
        }
 
index 9005b5241b3cce44c132f13be7e9b5270cfc691c..249baa701cb0be7f5930e6282c944f499365119a 100644 (file)
 struct wbsd_host
 {
        struct mmc_host*        mmc;            /* MMC structure */
-       
+
        spinlock_t              lock;           /* Mutex */
 
        int                     flags;          /* Driver states */
 
 #define WBSD_FCARD_PRESENT     (1<<0)          /* Card is present */
 #define WBSD_FIGNORE_DETECT    (1<<1)          /* Ignore card detection */
-       
+
        struct mmc_request*     mrq;            /* Current request */
-       
+
        u8                      isr;            /* Accumulated ISR */
-       
+
        struct scatterlist*     cur_sg;         /* Current SG entry */
        unsigned int            num_sg;         /* Number of entries left */
        void*                   mapped_sg;      /* vaddr of mapped sg */
-       
+
        unsigned int            offset;         /* Offset into current entry */
        unsigned int            remain;         /* Data left in curren entry */
 
        int                     size;           /* Total size of transfer */
-       
+
        char*                   dma_buffer;     /* ISA DMA buffer */
        dma_addr_t              dma_addr;       /* Physical address for same */
 
        int                     firsterr;       /* See fifo functions */
-       
+
        u8                      clk;            /* Current clock speed */
        unsigned char           bus_width;      /* Current bus width */
-       
+
        int                     config;         /* Config port */
        u8                      unlock_code;    /* Code to unlock config */
 
        int                     chip_id;        /* ID of controller */
-       
+
        int                     base;           /* I/O port base */
        int                     irq;            /* Interrupt */
        int                     dma;            /* DMA channel */
-       
+
        struct tasklet_struct   card_tasklet;   /* Tasklet structures */
        struct tasklet_struct   fifo_tasklet;
        struct tasklet_struct   crc_tasklet;
        struct tasklet_struct   timeout_tasklet;
        struct tasklet_struct   finish_tasklet;
        struct tasklet_struct   block_tasklet;
-       
-       struct timer_list       detect_timer;   /* Card detection timer */
+
        struct timer_list       ignore_timer;   /* Ignore detection timer */
 };
index 811d92e5f5b1426c83bd0f1992ee00859227733b..cc372136e852750f87f42dd3d69c0d917d074908 100644 (file)
@@ -23,9 +23,6 @@
 #include <linux/mtd/partitions.h>
 #include <asm/io.h>
 
-/****************************************************************************/
-
-
 /****************************************************************************/
 
 struct map_info uclinux_ram_map = {
@@ -60,14 +57,15 @@ int __init uclinux_mtd_init(void)
        struct mtd_info *mtd;
        struct map_info *mapp;
        extern char _ebss;
+       unsigned long addr = (unsigned long) &_ebss;
 
        mapp = &uclinux_ram_map;
-       mapp->phys = (unsigned long) &_ebss;
-       mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8)));
+       mapp->phys = addr;
+       mapp->size = PAGE_ALIGN(ntohl(*((unsigned long *)(addr + 8))));
        mapp->bankwidth = 4;
 
        printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
-               (int) mapp->map_priv_2, (int) mapp->size);
+               (int) mapp->phys, (int) mapp->size);
 
        mapp->virt = ioremap_nocache(mapp->phys, mapp->size);
 
@@ -95,7 +93,6 @@ int __init uclinux_mtd_init(void)
        printk("uclinux[mtd]: set %s to be root filesystem\n",
                uclinux_romfs[0].name);
        ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0);
-       put_mtd_device(mtd);
 
        return(0);
 }
@@ -109,7 +106,7 @@ void __exit uclinux_mtd_cleanup(void)
                map_destroy(uclinux_ram_mtdinfo);
                uclinux_ram_mtdinfo = NULL;
        }
-       if (uclinux_ram_map.map_priv_1) {
+       if (uclinux_ram_map.virt) {
                iounmap((void *) uclinux_ram_map.virt);
                uclinux_ram_map.virt = 0;
        }
index 6bb9232514b4e95a1b6506fe792e61a5f46779e5..54fff9c2e8028cb0a7509dae5cb5ed017bab39ab 100644 (file)
@@ -1738,11 +1738,18 @@ config 68360_ENET
          the Motorola 68360 processor.
 
 config FEC
-       bool "FEC ethernet controller (of ColdFire 5272)"
-       depends on M5272 || M5282
+       bool "FEC ethernet controller (of ColdFire CPUs)"
+       depends on M523x || M527x || M5272 || M528x
        help
          Say Y here if you want to use the built-in 10/100 Fast ethernet
-         controller on the Motorola ColdFire 5272 processor.
+         controller on some Motorola ColdFire processors.
+
+config FEC2
+       bool "Second FEC ethernet controller (on some ColdFire CPUs)"
+       depends on FEC
+       help
+         Say Y here if you want to use the second built-in 10/100 Fast
+         ethernet controller on some Motorola ColdFire processors.
 
 config NE_H8300
        tristate "NE2000 compatible support for H8/300"
index 52c77cbe8c62cf8e104d3639b3ac047737e8d5aa..1f03027354167cd29ba1c82467192f4d6892eecb 100644 (file)
@@ -160,7 +160,7 @@ static int __init com90io_probe(struct net_device *dev)
                return -ENODEV;
        }
        if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) {
-               BUGMSG(D_INIT_REASONS, "IO check_region %x-%x failed.\n",
+               BUGMSG(D_INIT_REASONS, "IO request_region %x-%x failed.\n",
                       ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
                return -ENXIO;
        }
@@ -242,7 +242,7 @@ static int __init com90io_found(struct net_device *dev)
                BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
                return -ENODEV;
        }
-       /* Reserve the I/O region - guaranteed to work by check_region */
+       /* Reserve the I/O region */
        if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)")) {
                free_irq(dev->irq, dev);
                return -EBUSY;
index 83598e32179cee8c1f81b851e37c67f8fc736f87..3a2ace01e444d082daaa31dc30de97c542d19054 100644 (file)
@@ -5015,6 +5015,7 @@ static struct ethtool_ops bnx2_ethtool_ops = {
        .phys_id                = bnx2_phys_id,
        .get_stats_count        = bnx2_get_stats_count,
        .get_ethtool_stats      = bnx2_get_ethtool_stats,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 /* Called with rtnl_lock */
@@ -5442,6 +5443,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_set_drvdata(pdev, dev);
 
        memcpy(dev->dev_addr, bp->mac_addr, 6);
+       memcpy(dev->perm_addr, bp->mac_addr, 6);
        bp->name = board_info[ent->driver_data].name,
        printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "
                "IRQ %d, ",
index 2c7008491378fef4cf71050582e6f88fb9f3e3c7..85504fb900dab5a62402a2ddc60e7ec5febe52e3 100644 (file)
@@ -8,7 +8,7 @@
  * describes connections using the internal parallel port I/O, which
  * is basically all of Port D.
  *
- * Right now, I am very watseful with the buffers.  I allocate memory
+ * Right now, I am very wasteful with the buffers.  I allocate memory
  * pages and then divide them into 2K frame buffers.  This way I know I
  * have buffers large enough to hold one frame within one buffer descriptor.
  * Once I get this working, I will use 64 or 128 byte CPM buffers, which
  * Copyright (c) 2000 Ericsson Radio Systems AB.
  *
  * Support for FEC controller of ColdFire/5270/5271/5272/5274/5275/5280/5282.
- * Copyrught (c) 2001-2004 Greg Ungerer (gerg@snapgear.com)
+ * Copyright (c) 2001-2004 Greg Ungerer (gerg@snapgear.com)
+ *
+ * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
+ * Copyright (c) 2004-2005 Macq Electronique SA.
  */
 
 #include <linux/config.h>
@@ -46,7 +49,8 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 
-#if defined(CONFIG_M527x) || defined(CONFIG_M5272) || defined(CONFIG_M528x)
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
+    defined(CONFIG_M5272) || defined(CONFIG_M528x)
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include "fec.h"
@@ -71,7 +75,7 @@ static unsigned int fec_hw[] = {
 #elif defined(CONFIG_M527x)
        (MCF_MBAR + 0x1000),
        (MCF_MBAR + 0x1800),
-#elif defined(CONFIG_M528x)
+#elif defined(CONFIG_M523x) || defined(CONFIG_M528x)
        (MCF_MBAR + 0x1000),
 #else
        &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec),
@@ -94,12 +98,14 @@ static unsigned char        fec_mac_default[] = {
 #define        FEC_FLASHMAC    0xffe04000
 #elif defined(CONFIG_CANCam)
 #define        FEC_FLASHMAC    0xf0020000
+#elif defined (CONFIG_M5272C3)
+#define        FEC_FLASHMAC    (0xffe04000 + 4)
+#elif defined(CONFIG_MOD5272)
+#define FEC_FLASHMAC   0xffc0406b
 #else
 #define        FEC_FLASHMAC    0
 #endif
 
-unsigned char *fec_flashmac = (unsigned char *) FEC_FLASHMAC;
-
 /* Forward declarations of some structures to support different PHYs
 */
 
@@ -158,7 +164,7 @@ typedef struct {
  * size bits. Other FEC hardware does not, so we need to take that into
  * account when setting it.
  */
-#if defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
 #define        OPT_FRAME_SIZE  (PKT_MAXBUF_SIZE << 16)
 #else
 #define        OPT_FRAME_SIZE  0
@@ -196,7 +202,7 @@ struct fec_enet_private {
        uint    phy_id_done;
        uint    phy_status;
        uint    phy_speed;
-       phy_info_t      *phy;
+       phy_info_t const        *phy;
        struct work_struct phy_task;
 
        uint    sequence_done;
@@ -209,7 +215,6 @@ struct fec_enet_private {
        int     link;
        int     old_link;
        int     full_duplex;
-       unsigned char mac_addr[ETH_ALEN];
 };
 
 static int fec_enet_open(struct net_device *dev);
@@ -237,10 +242,10 @@ typedef struct mii_list {
 } mii_list_t;
 
 #define                NMII    20
-mii_list_t     mii_cmds[NMII];
-mii_list_t     *mii_free;
-mii_list_t     *mii_head;
-mii_list_t     *mii_tail;
+static mii_list_t      mii_cmds[NMII];
+static mii_list_t      *mii_free;
+static mii_list_t      *mii_head;
+static mii_list_t      *mii_tail;
 
 static int     mii_queue(struct net_device *dev, int request, 
                                void (*func)(uint, struct net_device *));
@@ -425,7 +430,7 @@ fec_timeout(struct net_device *dev)
        }
        }
 #endif
-       fec_restart(dev, 0);
+       fec_restart(dev, fep->full_duplex);
        netif_wake_queue(dev);
 }
 
@@ -757,45 +762,52 @@ static void mii_parse_sr(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile uint *s = &(fep->phy_status);
+       uint status;
 
-       *s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
+       status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
 
        if (mii_reg & 0x0004)
-               *s |= PHY_STAT_LINK;
+               status |= PHY_STAT_LINK;
        if (mii_reg & 0x0010)
-               *s |= PHY_STAT_FAULT;
+               status |= PHY_STAT_FAULT;
        if (mii_reg & 0x0020)
-               *s |= PHY_STAT_ANC;
+               status |= PHY_STAT_ANC;
+
+       *s = status;
 }
 
 static void mii_parse_cr(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile uint *s = &(fep->phy_status);
+       uint status;
 
-       *s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP);
+       status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP);
 
        if (mii_reg & 0x1000)
-               *s |= PHY_CONF_ANE;
+               status |= PHY_CONF_ANE;
        if (mii_reg & 0x4000)
-               *s |= PHY_CONF_LOOP;
+               status |= PHY_CONF_LOOP;
+       *s = status;
 }
 
 static void mii_parse_anar(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile uint *s = &(fep->phy_status);
+       uint status;
 
-       *s &= ~(PHY_CONF_SPMASK);
+       status = *s & ~(PHY_CONF_SPMASK);
 
        if (mii_reg & 0x0020)
-               *s |= PHY_CONF_10HDX;
+               status |= PHY_CONF_10HDX;
        if (mii_reg & 0x0040)
-               *s |= PHY_CONF_10FDX;
+               status |= PHY_CONF_10FDX;
        if (mii_reg & 0x0080)
-               *s |= PHY_CONF_100HDX;
+               status |= PHY_CONF_100HDX;
        if (mii_reg & 0x00100)
-               *s |= PHY_CONF_100FDX;
+               status |= PHY_CONF_100FDX;
+       *s = status;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -811,37 +823,34 @@ static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile uint *s = &(fep->phy_status);
+       uint status;
 
-       *s &= ~(PHY_STAT_SPMASK);
-
+       status = *s & ~(PHY_STAT_SPMASK);
        if (mii_reg & 0x0800) {
                if (mii_reg & 0x1000)
-                       *s |= PHY_STAT_100FDX;
+                       status |= PHY_STAT_100FDX;
                else
-                       *s |= PHY_STAT_100HDX;
+                       status |= PHY_STAT_100HDX;
        } else {
                if (mii_reg & 0x1000)
-                       *s |= PHY_STAT_10FDX;
+                       status |= PHY_STAT_10FDX;
                else
-                       *s |= PHY_STAT_10HDX;
+                       status |= PHY_STAT_10HDX;
        }
+       *s = status;
 }
 
-static phy_info_t phy_info_lxt970 = {
-       0x07810000, 
-       "LXT970",
-
-       (const phy_cmd_t []) {  /* config */
+static phy_cmd_t const phy_cmd_lxt970_config[] = {
                { mk_mii_read(MII_REG_CR), mii_parse_cr },
                { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* startup - enable interrupts */
+       };
+static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */
                { mk_mii_write(MII_LXT970_IER, 0x0002), NULL },
                { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* ack_int */
+       };
+static phy_cmd_t const phy_cmd_lxt970_ack_int[] = {
                /* read SR and ISR to acknowledge */
                { mk_mii_read(MII_REG_SR), mii_parse_sr },
                { mk_mii_read(MII_LXT970_ISR), NULL },
@@ -849,11 +858,18 @@ static phy_info_t phy_info_lxt970 = {
                /* find out the current status */
                { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* shutdown - disable interrupts */
+       };
+static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */
                { mk_mii_write(MII_LXT970_IER, 0x0000), NULL },
                { mk_mii_end, }
-       },
+       };
+static phy_info_t const phy_info_lxt970 = {
+       .id = 0x07810000, 
+       .name = "LXT970",
+       .config = phy_cmd_lxt970_config,
+       .startup = phy_cmd_lxt970_startup,
+       .ack_int = phy_cmd_lxt970_ack_int,
+       .shutdown = phy_cmd_lxt970_shutdown
 };
        
 /* ------------------------------------------------------------------------- */
@@ -878,45 +894,44 @@ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile uint *s = &(fep->phy_status);
+       uint status;
 
-       *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
+       status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
 
        if (mii_reg & 0x0400) {
                fep->link = 1;
-               *s |= PHY_STAT_LINK;
+               status |= PHY_STAT_LINK;
        } else {
                fep->link = 0;
        }
        if (mii_reg & 0x0080)
-               *s |= PHY_STAT_ANC;
+               status |= PHY_STAT_ANC;
        if (mii_reg & 0x4000) {
                if (mii_reg & 0x0200)
-                       *s |= PHY_STAT_100FDX;
+                       status |= PHY_STAT_100FDX;
                else
-                       *s |= PHY_STAT_100HDX;
+                       status |= PHY_STAT_100HDX;
        } else {
                if (mii_reg & 0x0200)
-                       *s |= PHY_STAT_10FDX;
+                       status |= PHY_STAT_10FDX;
                else
-                       *s |= PHY_STAT_10HDX;
+                       status |= PHY_STAT_10HDX;
        }
        if (mii_reg & 0x0008)
-               *s |= PHY_STAT_FAULT;
-}
+               status |= PHY_STAT_FAULT;
 
-static phy_info_t phy_info_lxt971 = {
-       0x0001378e, 
-       "LXT971",
+       *s = status;
+}
        
-       (const phy_cmd_t []) {  /* config */  
-               /* limit to 10MBit because my protorype board 
+static phy_cmd_t const phy_cmd_lxt971_config[] = {
+               /* limit to 10MBit because my prototype board 
                 * doesn't work with 100. */
                { mk_mii_read(MII_REG_CR), mii_parse_cr },
                { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
                { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* startup - enable interrupts */
+       };
+static phy_cmd_t const phy_cmd_lxt971_startup[] = {  /* enable interrupts */
                { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
                { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
                { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */
@@ -925,19 +940,26 @@ static phy_info_t phy_info_lxt971 = {
                 * read here to get a valid value in ack_int */
                { mk_mii_read(MII_REG_SR), mii_parse_sr }, 
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* ack_int */
+       };
+static phy_cmd_t const phy_cmd_lxt971_ack_int[] = {
+               /* acknowledge the int before reading status ! */
+               { mk_mii_read(MII_LXT971_ISR), NULL },
                /* find out the current status */
                { mk_mii_read(MII_REG_SR), mii_parse_sr },
                { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
-               /* we only need to read ISR to acknowledge */
-               { mk_mii_read(MII_LXT971_ISR), NULL },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* shutdown - disable interrupts */
+       };
+static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */
                { mk_mii_write(MII_LXT971_IER, 0x0000), NULL },
                { mk_mii_end, }
-       },
+       };
+static phy_info_t const phy_info_lxt971 = {
+       .id = 0x0001378e, 
+       .name = "LXT971",
+       .config = phy_cmd_lxt971_config,
+       .startup = phy_cmd_lxt971_startup,
+       .ack_int = phy_cmd_lxt971_ack_int,
+       .shutdown = phy_cmd_lxt971_shutdown
 };
 
 /* ------------------------------------------------------------------------- */
@@ -956,22 +978,21 @@ static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile uint *s = &(fep->phy_status);
+       uint status;
 
-       *s &= ~(PHY_STAT_SPMASK);
+       status = *s & ~(PHY_STAT_SPMASK);
 
        switch((mii_reg >> 2) & 7) {
-       case 1: *s |= PHY_STAT_10HDX; break;
-       case 2: *s |= PHY_STAT_100HDX; break;
-       case 5: *s |= PHY_STAT_10FDX; break;
-       case 6: *s |= PHY_STAT_100FDX; break;
-       }
+       case 1: status |= PHY_STAT_10HDX; break;
+       case 2: status |= PHY_STAT_100HDX; break;
+       case 5: status |= PHY_STAT_10FDX; break;
+       case 6: status |= PHY_STAT_100FDX; break;
 }
 
-static phy_info_t phy_info_qs6612 = {
-       0x00181440, 
-       "QS6612",
-       
-       (const phy_cmd_t []) {  /* config */  
+       *s = status;
+}
+
+static phy_cmd_t const phy_cmd_qs6612_config[] = {
                /* The PHY powers up isolated on the RPX, 
                 * so send a command to allow operation.
                 */
@@ -981,13 +1002,13 @@ static phy_info_t phy_info_qs6612 = {
                { mk_mii_read(MII_REG_CR), mii_parse_cr },
                { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* startup - enable interrupts */
+       };
+static phy_cmd_t const phy_cmd_qs6612_startup[] = {  /* enable interrupts */
                { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL },
                { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* ack_int */
+       };
+static phy_cmd_t const phy_cmd_qs6612_ack_int[] = {
                /* we need to read ISR, SR and ANER to acknowledge */
                { mk_mii_read(MII_QS6612_ISR), NULL },
                { mk_mii_read(MII_REG_SR), mii_parse_sr },
@@ -996,11 +1017,18 @@ static phy_info_t phy_info_qs6612 = {
                /* read pcr to get info */
                { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* shutdown - disable interrupts */
+       };
+static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */
                { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL },
                { mk_mii_end, }
-       },
+       };
+static phy_info_t const phy_info_qs6612 = {
+       .id = 0x00181440, 
+       .name = "QS6612",
+       .config = phy_cmd_qs6612_config,
+       .startup = phy_cmd_qs6612_startup,
+       .ack_int = phy_cmd_qs6612_ack_int,
+       .shutdown = phy_cmd_qs6612_shutdown
 };
 
 /* ------------------------------------------------------------------------- */
@@ -1020,49 +1048,54 @@ static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile uint *s = &(fep->phy_status);
+       uint status;
 
-       *s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
+       status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
 
        if (mii_reg & 0x0080)
-               *s |= PHY_STAT_ANC;
+               status |= PHY_STAT_ANC;
        if (mii_reg & 0x0400)
-               *s |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX);
+               status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX);
        else
-               *s |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX);
+               status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX);
+
+       *s = status;
 }
 
-static phy_info_t phy_info_am79c874 = {
-       0x00022561, 
-       "AM79C874",
-       
-       (const phy_cmd_t []) {  /* config */  
-               /* limit to 10MBit because my protorype board 
-                * doesn't work with 100. */
+static phy_cmd_t const phy_cmd_am79c874_config[] = {
                { mk_mii_read(MII_REG_CR), mii_parse_cr },
                { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
                { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* startup - enable interrupts */
+       };
+static phy_cmd_t const phy_cmd_am79c874_startup[] = {  /* enable interrupts */
                { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL },
                { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
                { mk_mii_read(MII_REG_SR), mii_parse_sr }, 
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* ack_int */
+       };
+static phy_cmd_t const phy_cmd_am79c874_ack_int[] = {
                /* find out the current status */
                { mk_mii_read(MII_REG_SR), mii_parse_sr },
                { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
                /* we only need to read ISR to acknowledge */
                { mk_mii_read(MII_AM79C874_ICSR), NULL },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* shutdown - disable interrupts */
+       };
+static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */
                { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL },
                { mk_mii_end, }
-       },
+       };
+static phy_info_t const phy_info_am79c874 = {
+       .id = 0x00022561,
+       .name = "AM79C874",
+       .config = phy_cmd_am79c874_config,
+       .startup = phy_cmd_am79c874_startup,
+       .ack_int = phy_cmd_am79c874_ack_int,
+       .shutdown = phy_cmd_am79c874_shutdown
 };
 
+
 /* ------------------------------------------------------------------------- */
 /* Kendin KS8721BL phy                                                       */
 
@@ -1072,37 +1105,40 @@ static phy_info_t phy_info_am79c874 = {
 #define MII_KS8721BL_ICSR      22
 #define        MII_KS8721BL_PHYCR      31
 
-static phy_info_t phy_info_ks8721bl = {
-       0x00022161, 
-       "KS8721BL",
-       
-       (const phy_cmd_t []) {  /* config */  
+static phy_cmd_t const phy_cmd_ks8721bl_config[] = {
                { mk_mii_read(MII_REG_CR), mii_parse_cr },
                { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* startup */
+       };
+static phy_cmd_t const phy_cmd_ks8721bl_startup[] = {  /* enable interrupts */
                { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL },
                { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
                { mk_mii_read(MII_REG_SR), mii_parse_sr }, 
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* ack_int */
+       };
+static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = {
                /* find out the current status */
                { mk_mii_read(MII_REG_SR), mii_parse_sr },
                /* we only need to read ISR to acknowledge */
                { mk_mii_read(MII_KS8721BL_ICSR), NULL },
                { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* shutdown */
+       };
+static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */
                { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL },
                { mk_mii_end, }
-       },
+       };
+static phy_info_t const phy_info_ks8721bl = {
+       .id = 0x00022161, 
+       .name = "KS8721BL",
+       .config = phy_cmd_ks8721bl_config,
+       .startup = phy_cmd_ks8721bl_startup,
+       .ack_int = phy_cmd_ks8721bl_ack_int,
+       .shutdown = phy_cmd_ks8721bl_shutdown
 };
 
 /* ------------------------------------------------------------------------- */
 
-static phy_info_t *phy_info[] = {
+static phy_info_t const * const phy_info[] = {
        &phy_info_lxt970,
        &phy_info_lxt971,
        &phy_info_qs6612,
@@ -1129,16 +1165,23 @@ mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs);
 static void __inline__ fec_request_intrs(struct net_device *dev)
 {
        volatile unsigned long *icrp;
+       static const struct idesc {
+               char *name;
+               unsigned short irq;
+               irqreturn_t (*handler)(int, void *, struct pt_regs *);
+       } *idp, id[] = {
+               { "fec(RX)", 86, fec_enet_interrupt },
+               { "fec(TX)", 87, fec_enet_interrupt },
+               { "fec(OTHER)", 88, fec_enet_interrupt },
+               { "fec(MII)", 66, mii_link_interrupt },
+               { NULL },
+       };
 
        /* Setup interrupt handlers. */
-       if (request_irq(86, fec_enet_interrupt, 0, "fec(RX)", dev) != 0)
-               printk("FEC: Could not allocate FEC(RC) IRQ(86)!\n");
-       if (request_irq(87, fec_enet_interrupt, 0, "fec(TX)", dev) != 0)
-               printk("FEC: Could not allocate FEC(RC) IRQ(87)!\n");
-       if (request_irq(88, fec_enet_interrupt, 0, "fec(OTHER)", dev) != 0)
-               printk("FEC: Could not allocate FEC(OTHER) IRQ(88)!\n");
-       if (request_irq(66, mii_link_interrupt, 0, "fec(MII)", dev) != 0)
-               printk("FEC: Could not allocate MII IRQ(66)!\n");
+       for (idp = id; idp->name; idp++) {
+               if (request_irq(idp->irq, idp->handler, 0, idp->name, dev) != 0)
+                       printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq);
+       }
 
        /* Unmask interrupt at ColdFire 5272 SIM */
        icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);
@@ -1169,17 +1212,16 @@ static void __inline__ fec_get_mac(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile fec_t *fecp;
-       unsigned char *iap, tmpaddr[6];
-       int i;
+       unsigned char *iap, tmpaddr[ETH_ALEN];
 
        fecp = fep->hwp;
 
-       if (fec_flashmac) {
+       if (FEC_FLASHMAC) {
                /*
                 * Get MAC address from FLASH.
                 * If it is all 1's or 0's, use the default.
                 */
-               iap = fec_flashmac;
+               iap = (unsigned char *)FEC_FLASHMAC;
                if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
                    (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
                        iap = fec_mac_default;
@@ -1192,14 +1234,11 @@ static void __inline__ fec_get_mac(struct net_device *dev)
                iap = &tmpaddr[0];
        }
 
-       for (i=0; i<ETH_ALEN; i++)
-               dev->dev_addr[i] = fep->mac_addr[i] = *iap++;
+       memcpy(dev->dev_addr, iap, ETH_ALEN);
 
        /* Adjust MAC if using default MAC address */
-       if (iap == fec_mac_default) {
-               dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] =
-                       iap[ETH_ALEN-1] + fep->index;
-       }
+       if (iap == fec_mac_default)
+                dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
 }
 
 static void __inline__ fec_enable_phy_intr(void)
@@ -1234,48 +1273,44 @@ static void __inline__ fec_uncache(unsigned long addr)
 
 /* ------------------------------------------------------------------------- */
 
-#elif defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
 
 /*
- *     Code specific to Coldfire 5270/5271/5274/5275 and 5280/5282 setups.
+ *     Code specific to Coldfire 5230/5231/5232/5234/5235,
+ *     the 5270/5271/5274/5275 and 5280/5282 setups.
  */
 static void __inline__ fec_request_intrs(struct net_device *dev)
 {
        struct fec_enet_private *fep;
        int b;
+       static const struct idesc {
+               char *name;
+               unsigned short irq;
+       } *idp, id[] = {
+               { "fec(TXF)", 23 },
+               { "fec(TXB)", 24 },
+               { "fec(TXFIFO)", 25 },
+               { "fec(TXCR)", 26 },
+               { "fec(RXF)", 27 },
+               { "fec(RXB)", 28 },
+               { "fec(MII)", 29 },
+               { "fec(LC)", 30 },
+               { "fec(HBERR)", 31 },
+               { "fec(GRA)", 32 },
+               { "fec(EBERR)", 33 },
+               { "fec(BABT)", 34 },
+               { "fec(BABR)", 35 },
+               { NULL },
+       };
 
        fep = netdev_priv(dev);
        b = (fep->index) ? 128 : 64;
 
        /* Setup interrupt handlers. */
-       if (request_irq(b+23, fec_enet_interrupt, 0, "fec(TXF)", dev) != 0)
-               printk("FEC: Could not allocate FEC(TXF) IRQ(%d+23)!\n", b);
-       if (request_irq(b+24, fec_enet_interrupt, 0, "fec(TXB)", dev) != 0)
-               printk("FEC: Could not allocate FEC(TXB) IRQ(%d+24)!\n", b);
-       if (request_irq(b+25, fec_enet_interrupt, 0, "fec(TXFIFO)", dev) != 0)
-               printk("FEC: Could not allocate FEC(TXFIFO) IRQ(%d+25)!\n", b);
-       if (request_irq(b+26, fec_enet_interrupt, 0, "fec(TXCR)", dev) != 0)
-               printk("FEC: Could not allocate FEC(TXCR) IRQ(%d+26)!\n", b);
-
-       if (request_irq(b+27, fec_enet_interrupt, 0, "fec(RXF)", dev) != 0)
-               printk("FEC: Could not allocate FEC(RXF) IRQ(%d+27)!\n", b);
-       if (request_irq(b+28, fec_enet_interrupt, 0, "fec(RXB)", dev) != 0)
-               printk("FEC: Could not allocate FEC(RXB) IRQ(%d+28)!\n", b);
-
-       if (request_irq(b+29, fec_enet_interrupt, 0, "fec(MII)", dev) != 0)
-               printk("FEC: Could not allocate FEC(MII) IRQ(%d+29)!\n", b);
-       if (request_irq(b+30, fec_enet_interrupt, 0, "fec(LC)", dev) != 0)
-               printk("FEC: Could not allocate FEC(LC) IRQ(%d+30)!\n", b);
-       if (request_irq(b+31, fec_enet_interrupt, 0, "fec(HBERR)", dev) != 0)
-               printk("FEC: Could not allocate FEC(HBERR) IRQ(%d+31)!\n", b);
-       if (request_irq(b+32, fec_enet_interrupt, 0, "fec(GRA)", dev) != 0)
-               printk("FEC: Could not allocate FEC(GRA) IRQ(%d+32)!\n", b);
-       if (request_irq(b+33, fec_enet_interrupt, 0, "fec(EBERR)", dev) != 0)
-               printk("FEC: Could not allocate FEC(EBERR) IRQ(%d+33)!\n", b);
-       if (request_irq(b+34, fec_enet_interrupt, 0, "fec(BABT)", dev) != 0)
-               printk("FEC: Could not allocate FEC(BABT) IRQ(%d+34)!\n", b);
-       if (request_irq(b+35, fec_enet_interrupt, 0, "fec(BABR)", dev) != 0)
-               printk("FEC: Could not allocate FEC(BABR) IRQ(%d+35)!\n", b);
+       for (idp = id; idp->name; idp++) {
+               if (request_irq(b+idp->irq, fec_enet_interrupt, 0, idp->name, dev) != 0)
+                       printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
+       }
 
        /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */
        {
@@ -1300,11 +1335,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
 #if defined(CONFIG_M528x)
        /* Set up gpio outputs for MII lines */
        {
-               volatile unsigned short *gpio_paspar;
+               volatile u16 *gpio_paspar;
+               volatile u8 *gpio_pehlpar;
   
-               gpio_paspar = (volatile unsigned short *) (MCF_IPSBAR +
-                       0x100056);
-               *gpio_paspar = 0x0f00;
+               gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056);
+               gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058);
+               *gpio_paspar |= 0x0f00;
+               *gpio_pehlpar = 0xc0;
        }
 #endif
 }
@@ -1331,17 +1368,16 @@ static void __inline__ fec_get_mac(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        volatile fec_t *fecp;
-       unsigned char *iap, tmpaddr[6];
-       int i;
+       unsigned char *iap, tmpaddr[ETH_ALEN];
 
        fecp = fep->hwp;
 
-       if (fec_flashmac) {
+       if (FEC_FLASHMAC) {
                /*
                 * Get MAC address from FLASH.
                 * If it is all 1's or 0's, use the default.
                 */
-               iap = fec_flashmac;
+               iap = FEC_FLASHMAC;
                if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
                    (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
                        iap = fec_mac_default;
@@ -1354,14 +1390,11 @@ static void __inline__ fec_get_mac(struct net_device *dev)
                iap = &tmpaddr[0];
        }
 
-       for (i=0; i<ETH_ALEN; i++)
-               dev->dev_addr[i] = fep->mac_addr[i] = *iap++;
+       memcpy(dev->dev_addr, iap, ETH_ALEN);
 
        /* Adjust MAC if using default MAC address */
-       if (iap == fec_mac_default) {
-               dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] =
-                       iap[ETH_ALEN-1] + fep->index;
-       }
+       if (iap == fec_mac_default)
+               dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
 }
 
 static void __inline__ fec_enable_phy_intr(void)
@@ -1392,7 +1425,7 @@ static void __inline__ fec_uncache(unsigned long addr)
 #else
 
 /*
- *     Code sepcific to the MPC860T setup.
+ *     Code specific to the MPC860T setup.
  */
 static void __inline__ fec_request_intrs(struct net_device *dev)
 {
@@ -1424,13 +1457,10 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
 
 static void __inline__ fec_get_mac(struct net_device *dev)
 {
-       struct fec_enet_private *fep = netdev_priv(dev);
-       unsigned char *iap, tmpaddr[6];
        bd_t *bd;
-       int i;
 
-       iap = bd->bi_enetaddr;
        bd = (bd_t *)__res;
+       memcpy(dev->dev_addr, bd->bi_enetaddr, ETH_ALEN);
 
 #ifdef CONFIG_RPXCLASSIC
        /* The Embedded Planet boards have only one MAC address in
@@ -1439,14 +1469,8 @@ static void __inline__ fec_get_mac(struct net_device *dev)
         * the address bits above something that would have (up to
         * now) been allocated.
         */
-       for (i=0; i<6; i++)
-               tmpaddr[i] = *iap++;
-       tmpaddr[3] |= 0x80;
-       iap = tmpaddr;
+       dev->dev_adrd[3] |= 0x80;
 #endif
-
-       for (i=0; i<6; i++)
-               dev->dev_addr[i] = fep->mac_addr[i] = *iap++;
 }
 
 static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
@@ -1556,7 +1580,7 @@ static void mii_display_status(struct net_device *dev)
 static void mii_display_config(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
+       uint status = fep->phy_status;
 
        /*
        ** When we get here, phy_task is already removed from
@@ -1565,23 +1589,23 @@ static void mii_display_config(struct net_device *dev)
        fep->mii_phy_task_queued = 0;
        printk("%s: config: auto-negotiation ", dev->name);
 
-       if (*s & PHY_CONF_ANE)
+       if (status & PHY_CONF_ANE)
                printk("on");
        else
                printk("off");
 
-       if (*s & PHY_CONF_100FDX)
+       if (status & PHY_CONF_100FDX)
                printk(", 100FDX");
-       if (*s & PHY_CONF_100HDX)
+       if (status & PHY_CONF_100HDX)
                printk(", 100HDX");
-       if (*s & PHY_CONF_10FDX)
+       if (status & PHY_CONF_10FDX)
                printk(", 10FDX");
-       if (*s & PHY_CONF_10HDX)
+       if (status & PHY_CONF_10HDX)
                printk(", 10HDX");
-       if (!(*s & PHY_CONF_SPMASK))
+       if (!(status & PHY_CONF_SPMASK))
                printk(", No speed/duplex selected?");
 
-       if (*s & PHY_CONF_LOOP)
+       if (status & PHY_CONF_LOOP)
                printk(", loopback enabled");
        
        printk(".\n");
@@ -1639,7 +1663,7 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev)
        schedule_work(&fep->phy_task);
 }
 
-/* mii_queue_config is called in user context from fec_enet_open */
+/* mii_queue_config is called in interrupt context from fec_enet_mii */
 static void mii_queue_config(uint mii_reg, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
@@ -1652,14 +1676,14 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev)
        schedule_work(&fep->phy_task);
 }
 
-
-
-phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink },
-                              { mk_mii_end, } };
-phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config },
-                              { mk_mii_end, } };
-
-
+phy_cmd_t const phy_cmd_relink[] = {
+       { mk_mii_read(MII_REG_CR), mii_queue_relink },
+       { mk_mii_end, }
+       };
+phy_cmd_t const phy_cmd_config[] = {
+       { mk_mii_read(MII_REG_CR), mii_queue_config },
+       { mk_mii_end, }
+       };
 
 /* Read remainder of PHY ID.
 */
@@ -1897,17 +1921,15 @@ static void set_multicast_list(struct net_device *dev)
 static void
 fec_set_mac_address(struct net_device *dev)
 {
-       struct fec_enet_private *fep;
        volatile fec_t *fecp;
 
-       fep = netdev_priv(dev);
-       fecp = fep->hwp;
+       fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp;
 
        /* Set station address. */
-       fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) |
-               (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24);
-       fecp->fec_addr_high = (fep->mac_addr[5] << 16) |
-               (fep->mac_addr[4] << 24);
+       fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
+               (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24);
+       fecp->fec_addr_high = (dev->dev_addr[5] << 16) |
+               (dev->dev_addr[4] << 24);
 
 }
 
@@ -1943,7 +1965,7 @@ int __init fec_enet_init(struct net_device *dev)
        udelay(10);
 
        /* Clear and enable interrupts */
-       fecp->fec_ievent = 0xffc0;
+       fecp->fec_ievent = 0xffc00000;
        fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
                FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
        fecp->fec_hash_table_high = 0;
@@ -2063,11 +2085,6 @@ int __init fec_enet_init(struct net_device *dev)
        /* setup MII interface */
        fec_set_mii(dev, fep);
 
-       printk("%s: FEC ENET Version 0.2, ", dev->name);
-       for (i=0; i<5; i++)
-               printk("%02x:", dev->dev_addr[i]);
-       printk("%02x\n", dev->dev_addr[5]);
-
        /* Queue up command to detect the PHY and initialize the
         * remainder of the interface.
         */
@@ -2106,18 +2123,12 @@ fec_restart(struct net_device *dev, int duplex)
 
        /* Clear any outstanding interrupt.
        */
-       fecp->fec_ievent = 0xffc0;
+       fecp->fec_ievent = 0xffc00000;
        fec_enable_phy_intr();
 
        /* Set station address.
        */
-       fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) |
-               (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24);
-       fecp->fec_addr_high = (fep->mac_addr[5] << 16) |
-               (fep->mac_addr[4] << 24);
-
-       for (i=0; i<ETH_ALEN; i++)
-               dev->dev_addr[i] = fep->mac_addr[i];
+       fec_set_mac_address(dev);
 
        /* Reset all multicast.
        */
@@ -2215,7 +2226,7 @@ fec_stop(struct net_device *dev)
 
        fecp->fec_x_cntrl = 0x01;       /* Graceful transmit stop */
 
-       while(!(fecp->fec_ievent & 0x10000000));
+       while(!(fecp->fec_ievent & FEC_ENET_GRA));
 
        /* Whack a reset.  We should wait for this.
        */
@@ -2234,7 +2245,9 @@ fec_stop(struct net_device *dev)
 static int __init fec_enet_module_init(void)
 {
        struct net_device *dev;
-       int i, err;
+       int i, j, err;
+
+       printk("FEC ENET Version 0.2\n");
 
        for (i = 0; (i < FEC_MAX_PORTS); i++) {
                dev = alloc_etherdev(sizeof(struct fec_enet_private));
@@ -2250,6 +2263,11 @@ static int __init fec_enet_module_init(void)
                        free_netdev(dev);
                        return -EIO;
                }
+
+               printk("%s: ethernet ", dev->name);
+               for (j = 0; (j < 5); j++)
+                       printk("%02x:", dev->dev_addr[j]);
+               printk("%02x\n", dev->dev_addr[5]);
        }
        return 0;
 }
index c6e4f979ff5d42a9942d3c1ab57182dfb7935bd1..045761b8a6004ab1f25c73bcd082d00573024589 100644 (file)
@@ -1,8 +1,9 @@
 /****************************************************************************/
 
 /*
- *     fec.h  --  Fast Ethernet Controller for Motorola ColdFire 5270,
-                  5271, 5272, 5274, 5275, 5280 and 5282.
+ *     fec.h  --  Fast Ethernet Controller for Motorola ColdFire 5230,
+ *                5231, 5232, 5234, 5235, 5270, 5271, 5272, 5274, 5275,
+ *                5280 and 5282.
  *
  *     (C) Copyright 2000-2003, Greg Ungerer (gerg@snapgear.com)
  *     (C) Copyright 2000-2001, Lineo (www.lineo.com)
@@ -13,7 +14,7 @@
 #define        FEC_H
 /****************************************************************************/
 
-#if defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
 /*
  *     Just figures, Motorola would have to change the offsets for
  *     registers in the same peripheral device on different models
index 0b230222bfeab592fa23ec7836accddc79df7a62..90999867a32c56fd6819acee43ef1934984b061d 100644 (file)
@@ -293,7 +293,7 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev,
 {
 #ifdef CONFIG_INET
        if (type != htons(ETH_P_AX25))
-               return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+               return ax25_hard_header(skb, dev, type, daddr, saddr, len);
 #endif
        return 0;
 }
index 5298096afbdb6efc7a9031ec2d746a0e3438772f..e4188d082f011f0e0fa56080db7d8f9ca9913fc0 100644 (file)
@@ -40,7 +40,7 @@
 
 /*****************************************************************************/
 
-#include <linux/config.h>
+#include <linux/crc-ccitt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/workqueue.h>
 #include <linux/fs.h>
 #include <linux/parport.h>
-#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
 #include <linux/if_arp.h>
-#include <linux/kmod.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
 #include <linux/jiffies.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-/* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h> 
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-#include <linux/crc-ccitt.h>
+#include <asm/uaccess.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -1177,13 +1171,8 @@ static void baycom_probe(struct net_device *dev)
        /* Fill in the fields of the device structure */
        bc->skb = NULL;
        
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header = ax25_encapsulate;
+       dev->hard_header = ax25_hard_header;
        dev->rebuild_header = ax25_rebuild_header;
-#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-       dev->hard_header = NULL;
-       dev->rebuild_header = NULL;
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
        dev->set_mac_address = baycom_set_mac_address;
        
        dev->type = ARPHRD_AX25;           /* AF_AX25 device */
index 2946e037a9b1f1e4bab304c2982a0575bf07c69d..1756f0ed54ccc7a43de7613896f090d38c98f365 100644 (file)
@@ -488,7 +488,7 @@ static void bpq_setup(struct net_device *dev)
        dev->flags      = 0;
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header     = ax25_encapsulate;
+       dev->hard_header     = ax25_hard_header;
        dev->rebuild_header  = ax25_rebuild_header;
 #endif
 
index f515245a3fd0997f049aaa626ba8af0300b2ad9d..3be3f916643a17fcb53574f83cf39d8c8ae5bb9e 100644 (file)
@@ -449,12 +449,12 @@ module_exit(dmascc_exit);
 static void dev_setup(struct net_device *dev)
 {
        dev->type = ARPHRD_AX25;
-       dev->hard_header_len = 73;
+       dev->hard_header_len = AX25_MAX_HEADER_LEN;
        dev->mtu = 1500;
-       dev->addr_len = 7;
+       dev->addr_len = AX25_ADDR_LEN;
        dev->tx_queue_len = 64;
-       memcpy(dev->broadcast, ax25_broadcast, 7);
-       memcpy(dev->dev_addr, ax25_test, 7);
+       memcpy(dev->broadcast, ax25_broadcast, AX25_ADDR_LEN);
+       memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
 }
 
 static int __init setup_adapter(int card_base, int type, int n)
@@ -600,7 +600,7 @@ static int __init setup_adapter(int card_base, int type, int n)
                dev->do_ioctl = scc_ioctl;
                dev->hard_start_xmit = scc_send_packet;
                dev->get_stats = scc_get_stats;
-               dev->hard_header = ax25_encapsulate;
+               dev->hard_header = ax25_hard_header;
                dev->rebuild_header = ax25_rebuild_header;
                dev->set_mac_address = scc_set_mac_address;
        }
index b4c836e4fe860d4a4e7fe0d82a52736dd7432f2c..dacc7687b97f8b2bfe3290ede1cd6137c5ed08d9 100644 (file)
@@ -42,7 +42,6 @@
 
 /*****************************************************************************/
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
-#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
-#include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/hdlcdrv.h>
-/* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h> 
+#include <asm/uaccess.h>
 
-/* make genksyms happy */
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/tcp.h>
 #include <linux/crc-ccitt.h>
 
 /* --------------------------------------------------------------------- */
@@ -708,13 +701,8 @@ static void hdlcdrv_setup(struct net_device *dev)
 
        s->skb = NULL;
        
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header = ax25_encapsulate;
+       dev->hard_header = ax25_hard_header;
        dev->rebuild_header = ax25_rebuild_header;
-#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-       dev->hard_header = NULL;
-       dev->rebuild_header = NULL;
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
        dev->set_mac_address = hdlcdrv_set_mac_address;
        
        dev->type = ARPHRD_AX25;           /* AF_AX25 device */
index 63b1a2b86acb19650fdee9e84efb2e86e7971bed..d9fe64b46f4bf4bc1505bee23f2e8e92c86fa772 100644 (file)
@@ -500,7 +500,7 @@ static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short
 {
 #ifdef CONFIG_INET
        if (type != htons(ETH_P_AX25))
-               return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+               return ax25_hard_header(skb, dev, type, daddr, saddr, len);
 #endif
        return 0;
 }
index c27e417f32bf5958e322d4277dc7a808c2777284..6ace0e914fd1f2705a00609d23df8e07f44941dd 100644 (file)
@@ -1557,7 +1557,7 @@ static void scc_net_setup(struct net_device *dev)
        dev->stop            = scc_net_close;
 
        dev->hard_start_xmit = scc_net_tx;
-       dev->hard_header     = ax25_encapsulate;
+       dev->hard_header     = ax25_hard_header;
        dev->rebuild_header  = ax25_rebuild_header;
        dev->set_mac_address = scc_net_set_mac_address;
        dev->get_stats       = scc_net_get_stats;
index f52ee3162c51dc29f2ac586be3dfc610fe3363ee..fe22479eb2028097213e5f987a1768e453477fc3 100644 (file)
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-/* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h>
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-
-/* make genksyms happy */
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/tcp.h>
 
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
@@ -1116,23 +1108,17 @@ static void yam_setup(struct net_device *dev)
 
        skb_queue_head_init(&yp->send_queue);
 
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header = ax25_encapsulate;
+       dev->hard_header = ax25_hard_header;
        dev->rebuild_header = ax25_rebuild_header;
-#else                                                  /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-       dev->hard_header = NULL;
-       dev->rebuild_header = NULL;
-#endif                                                 /* CONFIG_AX25 || CONFIG_AX25_MODULE */
 
        dev->set_mac_address = yam_set_mac_address;
 
-       dev->type = ARPHRD_AX25;        /* AF_AX25 device */
-       dev->hard_header_len = 73;      /* We do digipeaters now */
-       dev->mtu = 256;                         /* AX25 is the default */
-       dev->addr_len = 7;                      /* sizeof an ax.25 address */
-       memcpy(dev->broadcast, ax25_bcast, 7);
-       memcpy(dev->dev_addr, ax25_test, 7);
-
+       dev->type = ARPHRD_AX25;
+       dev->hard_header_len = AX25_MAX_HEADER_LEN;
+       dev->mtu = AX25_MTU;
+       dev->addr_len = AX25_ADDR_LEN;
+       memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
+       memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
 }
 
 static int __init yam_init_driver(void)
index dc57352e5a974e8f7c64433e71cda98728ac5d0b..7599f52e15b3ca65abd356ce4e13d424e064a21c 100644 (file)
@@ -6893,8 +6893,7 @@ static struct net_device_stats *tg3_get_stats(struct net_device *dev)
                get_stat64(&hw_stats->tx_octets);
 
        stats->rx_errors = old_stats->rx_errors +
-               get_stat64(&hw_stats->rx_errors) +
-               get_stat64(&hw_stats->rx_discards);
+               get_stat64(&hw_stats->rx_errors);
        stats->tx_errors = old_stats->tx_errors +
                get_stat64(&hw_stats->tx_errors) +
                get_stat64(&hw_stats->tx_mac_errors) +
@@ -6922,6 +6921,9 @@ static struct net_device_stats *tg3_get_stats(struct net_device *dev)
        stats->rx_crc_errors = old_stats->rx_crc_errors +
                calc_crc_errors(tp);
 
+       stats->rx_missed_errors = old_stats->rx_missed_errors +
+               get_stat64(&hw_stats->rx_discards);
+
        return stats;
 }
 
@@ -8303,6 +8305,7 @@ static struct ethtool_ops tg3_ethtool_ops = {
        .get_ethtool_stats      = tg3_get_ethtool_stats,
        .get_coalesce           = tg3_get_coalesce,
        .set_coalesce           = tg3_set_coalesce,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -9781,6 +9784,7 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
                if (prom_getproplen(node, "local-mac-address") == 6) {
                        prom_getproperty(node, "local-mac-address",
                                         dev->dev_addr, 6);
+                       memcpy(dev->perm_addr, dev->dev_addr, 6);
                        return 0;
                }
        }
@@ -9792,6 +9796,7 @@ static int __devinit tg3_get_default_macaddr_sparc(struct tg3 *tp)
        struct net_device *dev = tp->dev;
 
        memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+       memcpy(dev->perm_addr, idprom->id_ethaddr, 6);
        return 0;
 }
 #endif
@@ -9861,6 +9866,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
 #endif
                return -EINVAL;
        }
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        return 0;
 }
 
index d1fb1bab8aa879c2322398f493fba934355bb848..bedd7f9f23e48cd37201e79f6a3b4c3b35697bc6 100644 (file)
@@ -629,6 +629,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
+       PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
        PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
        PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
        PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
index 39ba6406fd54ef8b9a398eafb3c425a6706837f5..80969f7e7a0be4eddc31e675ab404e6f144593f3 100644 (file)
@@ -376,6 +376,7 @@ static int ds_open(struct inode *inode, struct file *file)
     socket_t i = iminor(inode);
     struct pcmcia_socket *s;
     user_info_t *user;
+    static int warning_printed = 0;
 
     ds_dbg(0, "ds_open(socket %d)\n", i);
 
@@ -407,6 +408,17 @@ static int ds_open(struct inode *inode, struct file *file)
     s->user = user;
     file->private_data = user;
 
+    if (!warning_printed) {
+           printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
+                       "usage.\n");
+           printk(KERN_INFO "pcmcia: This interface will soon be removed from "
+                       "the kernel; please expect breakage unless you upgrade "
+                       "to new tools.\n");
+           printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
+                       "utils/kernel/pcmcia/pcmcia.html for details.\n");
+           warning_printed = 1;
+    }
+
     if (s->pcmcia_state.present)
        queue_event(user, CS_EVENT_CARD_INSERTION);
     return 0;
index 87302fb1488545c94e8a5b58aa6822e7e668fb99..ccb20a6f5f36d7593b991d985cb8a478f704368f 100644 (file)
@@ -295,8 +295,7 @@ static unsigned short get_pins(unsigned minor)
 
 static void snooze(unsigned long snooze_time, unsigned minor)
 {
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(snooze_time + 1);
+       schedule_timeout_uninterruptible(snooze_time + 1);
 }
 
 static int wait_for(unsigned short set, unsigned short clr,
index dbad7f35eb0a2f7deb6ea878e64e64b518c390ae..24ed5893b4f047f3ca3f74c565afa59fa145555d 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/major.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
-#include <linux/ioport.h>              /* request_region, check_region */
+#include <linux/ioport.h>              /* request_region */
 #include <asm/atomic.h>
 #include <asm/ebus.h>                  /* EBus device                                  */
 #include <asm/oplib.h>                 /* OpenProm Library                     */
index 739cad9b19a1f55a98d9c4be5a5d3a08cf43a026..ceec30648f4f65edd8f336536a28f79bdd2c1d4d 100644 (file)
@@ -81,8 +81,7 @@ int vfc_pcf8584_init(struct vfc_dev *dev)
 
 void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs) 
 {
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(usecs_to_jiffies(usecs));
+       schedule_timeout_uninterruptible(usecs_to_jiffies(usecs));
 }
 
 void inline vfc_i2c_delay(struct vfc_dev *dev) 
index bc6e4627c7a1e450b097b9a117e01e03e667f293..a6ac61611f35296c2a1d4402940075d10e38dc0a 100644 (file)
@@ -59,6 +59,7 @@
                  Fix 'handled=1' ISR usage, remove bogus IRQ check.
                  Remove un-needed eh_abort handler.
                  Add support for embedded firmware error strings.
+   2.26.02.003 - Correctly handle single sgl's with use_sg=1.
 */
 
 #include <linux/module.h>
@@ -81,7 +82,7 @@
 #include "3w-9xxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.002"
+#define TW_DRIVER_VERSION "2.26.02.003"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
@@ -1805,6 +1806,8 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
                        if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) {
                                command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
                                command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+                               if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)
+                                       memcpy(tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
                        } else {
                                buffaddr = twa_map_scsi_single_data(tw_dev, request_id);
                                if (buffaddr == 0)
@@ -1823,6 +1826,12 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
 
                if (tw_dev->srb[request_id]->use_sg > 0) {
                        if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+                               if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) {
+                                       struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+                                       char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+                                       memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length);
+                                       kunmap_atomic(buf - sg->offset, KM_IRQ0);
+                               }
                                command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
                                command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
                        } else {
@@ -1888,11 +1897,20 @@ out:
 /* This function completes an execute scsi operation */
 static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
 {
-       /* Copy the response if too small */
-       if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
-               memcpy(tw_dev->srb[request_id]->request_buffer,
-                      tw_dev->generic_buffer_virt[request_id],
-                      tw_dev->srb[request_id]->request_bufflen);
+       if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH &&
+           (tw_dev->srb[request_id]->sc_data_direction == DMA_FROM_DEVICE ||
+            tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)) {
+               if (tw_dev->srb[request_id]->use_sg == 0) {
+                       memcpy(tw_dev->srb[request_id]->request_buffer,
+                              tw_dev->generic_buffer_virt[request_id],
+                              tw_dev->srb[request_id]->request_bufflen);
+               }
+               if (tw_dev->srb[request_id]->use_sg == 1) {
+                       struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+                       char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+                       memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length);
+                       kunmap_atomic(buf - sg->offset, KM_IRQ0);
+               }
        }
 } /* End twa_scsiop_execute_scsi_complete() */
 
index 2d21265e650b2abc0d79bd1f2c50ef212d9b977b..20019b82b4a85f70a13b4a7edb26862c182180dd 100644 (file)
@@ -235,6 +235,13 @@ config SCSI_ISCSI_ATTRS
          each attached iSCSI device to sysfs, say Y.
          Otherwise, say N.
 
+config SCSI_SAS_ATTRS
+       tristate "SAS Transport Attributes"
+       depends on SCSI
+       help
+         If you wish to export transport-specific information about
+         each attached SAS device to sysfs, say Y.
+
 endmenu
 
 menu "SCSI low-level drivers"
index 4b4fd94c2674cf6f3ac0b6c727ef2cd52f3d7be1..1e4edbdf27304bc80a28f8b05d08f21580936b63 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_RAID_ATTRS)      += raid_class.o
 obj-$(CONFIG_SCSI_SPI_ATTRS)   += scsi_transport_spi.o
 obj-$(CONFIG_SCSI_FC_ATTRS)    += scsi_transport_fc.o
 obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
+obj-$(CONFIG_SCSI_SAS_ATTRS)   += scsi_transport_sas.o
 
 obj-$(CONFIG_SCSI_AMIGA7XX)    += amiga7xx.o   53c7xx.o
 obj-$(CONFIG_A3000_SCSI)       += a3000.o      wd33c93.o
index 0e089a42c03ad310b000f2369633beb5d13f31a3..86eaf6d408d5770aa77befca6da6b784bb8c4328 100644 (file)
@@ -966,21 +966,21 @@ static void
 lpfc_get_host_fabric_name (struct Scsi_Host *shost)
 {
        struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
-       u64 nodename;
+       u64 node_name;
 
        spin_lock_irq(shost->host_lock);
 
        if ((phba->fc_flag & FC_FABRIC) ||
            ((phba->fc_topology == TOPOLOGY_LOOP) &&
             (phba->fc_flag & FC_PUBLIC_LOOP)))
-               memcpy(&nodename, &phba->fc_fabparam.nodeName, sizeof(u64));
+               node_name = wwn_to_u64(phba->fc_fabparam.nodeName.wwn);
        else
                /* fabric is local port if there is no F/FL_Port */
-               memcpy(&nodename, &phba->fc_nodename, sizeof(u64));
+               node_name = wwn_to_u64(phba->fc_nodename.wwn);
 
        spin_unlock_irq(shost->host_lock);
 
-       fc_host_fabric_name(shost) = be64_to_cpu(nodename);
+       fc_host_fabric_name(shost) = node_name;
 }
 
 
@@ -1103,21 +1103,20 @@ lpfc_get_starget_node_name(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0];
-       uint64_t node_name = 0;
+       u64 node_name = 0;
        struct lpfc_nodelist *ndlp = NULL;
 
        spin_lock_irq(shost->host_lock);
        /* Search the mapped list for this target ID */
        list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
                if (starget->id == ndlp->nlp_sid) {
-                       memcpy(&node_name, &ndlp->nlp_nodename,
-                                               sizeof(struct lpfc_name));
+                       node_name = wwn_to_u64(ndlp->nlp_nodename.wwn);
                        break;
                }
        }
        spin_unlock_irq(shost->host_lock);
 
-       fc_starget_node_name(starget) = be64_to_cpu(node_name);
+       fc_starget_node_name(starget) = node_name;
 }
 
 static void
@@ -1125,21 +1124,20 @@ lpfc_get_starget_port_name(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0];
-       uint64_t port_name = 0;
+       u64 port_name = 0;
        struct lpfc_nodelist *ndlp = NULL;
 
        spin_lock_irq(shost->host_lock);
        /* Search the mapped list for this target ID */
        list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
                if (starget->id == ndlp->nlp_sid) {
-                       memcpy(&port_name, &ndlp->nlp_portname,
-                                               sizeof(struct lpfc_name));
+                       port_name = wwn_to_u64(ndlp->nlp_portname.wwn);
                        break;
                }
        }
        spin_unlock_irq(shost->host_lock);
 
-       fc_starget_port_name(starget) = be64_to_cpu(port_name);
+       fc_starget_port_name(starget) = port_name;
 }
 
 static void
index 0a8269d6b130c0a4982f50eee6e8509985dca176..4fb8eb0c84cfc0773c7f2115f95d350db2b22edd 100644 (file)
@@ -1017,13 +1017,10 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
        struct fc_rport *rport;
        struct lpfc_rport_data *rdata;
        struct fc_rport_identifiers rport_ids;
-       uint64_t wwn;
 
        /* Remote port has reappeared. Re-register w/ FC transport */
-       memcpy(&wwn, &ndlp->nlp_nodename, sizeof(uint64_t));
-       rport_ids.node_name = be64_to_cpu(wwn);
-       memcpy(&wwn, &ndlp->nlp_portname, sizeof(uint64_t));
-       rport_ids.port_name = be64_to_cpu(wwn);
+       rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.wwn);
+       rport_ids.port_name = wwn_to_u64(ndlp->nlp_portname.wwn);
        rport_ids.port_id = ndlp->nlp_DID;
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
        if (ndlp->nlp_type & NLP_FCP_TARGET)
index 21591cb9f551ada28b04da49bd0d0e3016008ce8..047a87c26cc0825e72235573325ac4dc2f60092e 100644 (file)
@@ -262,12 +262,14 @@ struct lpfc_sli_ct_request {
 #define FF_FRAME_SIZE     2048
 
 struct lpfc_name {
+       union {
+               struct {
 #ifdef __BIG_ENDIAN_BITFIELD
-       uint8_t nameType:4;     /* FC Word 0, bit 28:31 */
-       uint8_t IEEEextMsn:4;   /* FC Word 0, bit 24:27, bit 8:11 of IEEE ext */
+                       uint8_t nameType:4;     /* FC Word 0, bit 28:31 */
+                       uint8_t IEEEextMsn:4;   /* FC Word 0, bit 24:27, bit 8:11 of IEEE ext */
 #else  /*  __LITTLE_ENDIAN_BITFIELD */
-       uint8_t IEEEextMsn:4;   /* FC Word 0, bit 24:27, bit 8:11 of IEEE ext */
-       uint8_t nameType:4;     /* FC Word 0, bit 28:31 */
+                       uint8_t IEEEextMsn:4;   /* FC Word 0, bit 24:27, bit 8:11 of IEEE ext */
+                       uint8_t nameType:4;     /* FC Word 0, bit 28:31 */
 #endif
 
 #define NAME_IEEE           0x1        /* IEEE name - nameType */
@@ -276,8 +278,11 @@ struct lpfc_name {
 #define NAME_IP_TYPE        0x4        /* IP address */
 #define NAME_CCITT_TYPE     0xC
 #define NAME_CCITT_GR_TYPE  0xE
-       uint8_t IEEEextLsb;     /* FC Word 0, bit 16:23, IEEE extended Lsb */
-       uint8_t IEEE[6];        /* FC IEEE address */
+                       uint8_t IEEEextLsb;     /* FC Word 0, bit 16:23, IEEE extended Lsb */
+                       uint8_t IEEE[6];        /* FC IEEE address */
+               };
+               uint8_t wwn[8];
+       };
 };
 
 struct csp {
index 6f3cb59bf9e0a6b52b9778cdbd8b98e1ca97df74..454058f655db6b056a1f1f123d13efc6448e7b5e 100644 (file)
@@ -1333,7 +1333,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        unsigned long bar0map_len, bar2map_len;
        int error = -ENODEV, retval;
        int i;
-       u64 wwname;
 
        if (pci_enable_device(pdev))
                goto out;
@@ -1524,10 +1523,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
         * Must done after lpfc_sli_hba_setup()
         */
 
-       memcpy(&wwname, &phba->fc_nodename, sizeof(u64));
-       fc_host_node_name(host) = be64_to_cpu(wwname);
-       memcpy(&wwname, &phba->fc_portname, sizeof(u64));
-       fc_host_port_name(host) = be64_to_cpu(wwname);
+       fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.wwn);
+       fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.wwn);
        fc_host_supported_classes(host) = FC_COS_CLASS3;
 
        memset(fc_host_supported_fc4s(host), 0,
index fe0fce71adc70153d17abaa0851b15b3a102b862..fc25cd834668246d7ebd4ab3069f696cd92acd52 100644 (file)
@@ -360,16 +360,16 @@ qla2x00_get_starget_node_name(struct scsi_target *starget)
        struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
        scsi_qla_host_t *ha = to_qla_host(host);
        fc_port_t *fcport;
-       uint64_t node_name = 0;
+       u64 node_name = 0;
 
        list_for_each_entry(fcport, &ha->fcports, list) {
                if (starget->id == fcport->os_target_id) {
-                       node_name = *(uint64_t *)fcport->node_name;
+                       node_name = wwn_to_u64(fcport->node_name);
                        break;
                }
        }
 
-       fc_starget_node_name(starget) = be64_to_cpu(node_name);
+       fc_starget_node_name(starget) = node_name;
 }
 
 static void
@@ -378,16 +378,16 @@ qla2x00_get_starget_port_name(struct scsi_target *starget)
        struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
        scsi_qla_host_t *ha = to_qla_host(host);
        fc_port_t *fcport;
-       uint64_t port_name = 0;
+       u64 port_name = 0;
 
        list_for_each_entry(fcport, &ha->fcports, list) {
                if (starget->id == fcport->os_target_id) {
-                       port_name = *(uint64_t *)fcport->port_name;
+                       port_name = wwn_to_u64(fcport->port_name);
                        break;
                }
        }
 
-       fc_starget_port_name(starget) = be64_to_cpu(port_name);
+       fc_starget_port_name(starget) = port_name;
 }
 
 static void
@@ -460,9 +460,7 @@ struct fc_function_template qla2xxx_transport_functions = {
 void
 qla2x00_init_host_attr(scsi_qla_host_t *ha)
 {
-       fc_host_node_name(ha->host) =
-           be64_to_cpu(*(uint64_t *)ha->init_cb->node_name);
-       fc_host_port_name(ha->host) =
-           be64_to_cpu(*(uint64_t *)ha->init_cb->port_name);
+       fc_host_node_name(ha->host) = wwn_to_u64(ha->init_cb->node_name);
+       fc_host_port_name(ha->host) = wwn_to_u64(ha->init_cb->port_name);
        fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
 }
index c619583e646be32e7bf0c8d44f1b107c275549ed..3e9b64137873574acd5144a35097ade5eaa84808 100644 (file)
@@ -2066,8 +2066,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
                return;
        }
 
-       rport_ids.node_name = be64_to_cpu(*(uint64_t *)fcport->node_name);
-       rport_ids.port_name = be64_to_cpu(*(uint64_t *)fcport->port_name);
+       rport_ids.node_name = wwn_to_u64(fcport->node_name);
+       rport_ids.port_name = wwn_to_u64(fcport->port_name);
        rport_ids.port_id = fcport->d_id.b.domain << 16 |
            fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
index 77f2d444f7e0c7b6d297db390fcc2561d14ec36b..863bb6495daaeb6bd6fcdb1a00c7721507e6fb8d 100644 (file)
@@ -97,6 +97,30 @@ int scsi_insert_special_req(struct scsi_request *sreq, int at_head)
 }
 
 static void scsi_run_queue(struct request_queue *q);
+static void scsi_release_buffers(struct scsi_cmnd *cmd);
+
+/*
+ * Function:   scsi_unprep_request()
+ *
+ * Purpose:    Remove all preparation done for a request, including its
+ *             associated scsi_cmnd, so that it can be requeued.
+ *
+ * Arguments:  req     - request to unprepare
+ *
+ * Lock status:        Assumed that no locks are held upon entry.
+ *
+ * Returns:    Nothing.
+ */
+static void scsi_unprep_request(struct request *req)
+{
+       struct scsi_cmnd *cmd = req->special;
+
+       req->flags &= ~REQ_DONTPREP;
+       req->special = (req->flags & REQ_SPECIAL) ? cmd->sc_request : NULL;
+
+       scsi_release_buffers(cmd);
+       scsi_put_command(cmd);
+}
 
 /*
  * Function:    scsi_queue_insert()
@@ -116,12 +140,14 @@ static void scsi_run_queue(struct request_queue *q);
  *              commands.
  * Notes:       This could be called either from an interrupt context or a
  *              normal process context.
+ * Notes:      Upon return, cmd is a stale pointer.
  */
 int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
 {
        struct Scsi_Host *host = cmd->device->host;
        struct scsi_device *device = cmd->device;
        struct request_queue *q = device->request_queue;
+       struct request *req = cmd->request;
        unsigned long flags;
 
        SCSI_LOG_MLQUEUE(1,
@@ -162,8 +188,9 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
         * function.  The SCSI request function detects the blocked condition
         * and plugs the queue appropriately.
          */
+       scsi_unprep_request(req);
        spin_lock_irqsave(q->queue_lock, flags);
-       blk_requeue_request(q, cmd->request);
+       blk_requeue_request(q, req);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
        scsi_run_queue(q);
@@ -339,7 +366,7 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
        int result;
        
        if (sshdr) {
-               sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
+               sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
                if (!sense)
                        return DRIVER_ERROR << 24;
                memset(sense, 0, SCSI_SENSE_BUFFERSIZE);
@@ -552,15 +579,16 @@ static void scsi_run_queue(struct request_queue *q)
  *             I/O errors in the middle of the request, in which case
  *             we need to request the blocks that come after the bad
  *             sector.
+ * Notes:      Upon return, cmd is a stale pointer.
  */
 static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
 {
+       struct request *req = cmd->request;
        unsigned long flags;
 
-       cmd->request->flags &= ~REQ_DONTPREP;
-
+       scsi_unprep_request(req);
        spin_lock_irqsave(q->queue_lock, flags);
-       blk_requeue_request(q, cmd->request);
+       blk_requeue_request(q, req);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
        scsi_run_queue(q);
@@ -595,13 +623,14 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
  *
  * Lock status: Assumed that lock is not held upon entry.
  *
- * Returns:     cmd if requeue done or required, NULL otherwise
+ * Returns:     cmd if requeue required, NULL otherwise.
  *
  * Notes:       This is called for block device requests in order to
  *              mark some number of sectors as complete.
  * 
  *             We are guaranteeing that the request queue will be goosed
  *             at some point during this call.
+ * Notes:      If cmd was requeued, upon return it will be a stale pointer.
  */
 static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
                                          int bytes, int requeue)
@@ -624,14 +653,15 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
                if (!uptodate && blk_noretry_request(req))
                        end_that_request_chunk(req, 0, leftover);
                else {
-                       if (requeue)
+                       if (requeue) {
                                /*
                                 * Bleah.  Leftovers again.  Stick the
                                 * leftovers in the front of the
                                 * queue, and goose the queue again.
                                 */
                                scsi_requeue_command(q, cmd);
-
+                               cmd = NULL;
+                       }
                        return cmd;
                }
        }
@@ -857,15 +887,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
                 * requeueing right here - we will requeue down below
                 * when we handle the bad sectors.
                 */
-               cmd = scsi_end_request(cmd, 1, good_bytes, result == 0);
 
                /*
-                * If the command completed without error, then either finish off the
-                * rest of the command, or start a new one.
+                * If the command completed without error, then either
+                * finish off the rest of the command, or start a new one.
                 */
-               if (result == 0 || cmd == NULL ) {
+               if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL)
                        return;
-               }
        }
        /*
         * Now, if we were good little boys and girls, Santa left us a request
@@ -880,7 +908,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
                                 * and quietly refuse further access.
                                 */
                                cmd->device->changed = 1;
-                               cmd = scsi_end_request(cmd, 0,
+                               scsi_end_request(cmd, 0,
                                                this_count, 1);
                                return;
                        } else {
@@ -914,7 +942,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
                                scsi_requeue_command(q, cmd);
                                result = 0;
                        } else {
-                               cmd = scsi_end_request(cmd, 0, this_count, 1);
+                               scsi_end_request(cmd, 0, this_count, 1);
                                return;
                        }
                        break;
@@ -931,7 +959,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
                                dev_printk(KERN_INFO,
                                           &cmd->device->sdev_gendev,
                                           "Device not ready.\n");
-                       cmd = scsi_end_request(cmd, 0, this_count, 1);
+                       scsi_end_request(cmd, 0, this_count, 1);
                        return;
                case VOLUME_OVERFLOW:
                        if (!(req->flags & REQ_QUIET)) {
@@ -941,7 +969,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
                                __scsi_print_command(cmd->data_cmnd);
                                scsi_print_sense("", cmd);
                        }
-                       cmd = scsi_end_request(cmd, 0, block_bytes, 1);
+                       scsi_end_request(cmd, 0, block_bytes, 1);
                        return;
                default:
                        break;
@@ -972,7 +1000,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
                block_bytes = req->hard_cur_sectors << 9;
                if (!block_bytes)
                        block_bytes = req->data_len;
-               cmd = scsi_end_request(cmd, 0, block_bytes, 1);
+               scsi_end_request(cmd, 0, block_bytes, 1);
        }
 }
 EXPORT_SYMBOL(scsi_io_completion);
@@ -1118,7 +1146,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
        if (unlikely(!scsi_device_online(sdev))) {
                printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n",
                       sdev->host->host_no, sdev->id, sdev->lun);
-               return BLKPREP_KILL;
+               goto kill;
        }
        if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
                /* OK, we're not in a running state don't prep
@@ -1128,7 +1156,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
                         * at all allowed down */
                        printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to dead device\n",
                               sdev->host->host_no, sdev->id, sdev->lun);
-                       return BLKPREP_KILL;
+                       goto kill;
                }
                /* OK, we only allow special commands (i.e. not
                 * user initiated ones */
@@ -1160,11 +1188,11 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
                if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) {
                        if(specials_only == SDEV_QUIESCE ||
                                        specials_only == SDEV_BLOCK)
-                               return BLKPREP_DEFER;
+                               goto defer;
                        
                        printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n",
                               sdev->host->host_no, sdev->id, sdev->lun);
-                       return BLKPREP_KILL;
+                       goto kill;
                }
                        
                        
@@ -1182,7 +1210,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
                cmd->tag = req->tag;
        } else {
                blk_dump_rq_flags(req, "SCSI bad req");
-               return BLKPREP_KILL;
+               goto kill;
        }
        
        /* note the overloading of req->special.  When the tag
@@ -1220,8 +1248,13 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
                 * required).
                 */
                ret = scsi_init_io(cmd);
-               if (ret)        /* BLKPREP_KILL return also releases the command */
-                       return ret;
+               switch(ret) {
+               case BLKPREP_KILL:
+                       /* BLKPREP_KILL return also releases the command */
+                       goto kill;
+               case BLKPREP_DEFER:
+                       goto defer;
+               }
                
                /*
                 * Initialize the actual SCSI command for this request.
@@ -1231,7 +1264,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
                        if (unlikely(!drv->init_command(cmd))) {
                                scsi_release_buffers(cmd);
                                scsi_put_command(cmd);
-                               return BLKPREP_KILL;
+                               goto kill;
                        }
                } else {
                        memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
@@ -1262,6 +1295,9 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
        if (sdev->device_busy == 0)
                blk_plug_device(q);
        return BLKPREP_DEFER;
+ kill:
+       req->errors = DID_NO_CONNECT << 16;
+       return BLKPREP_KILL;
 }
 
 /*
@@ -1336,19 +1372,24 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
 }
 
 /*
- * Kill requests for a dead device
+ * Kill a request for a dead device
  */
-static void scsi_kill_requests(request_queue_t *q)
+static void scsi_kill_request(struct request *req, request_queue_t *q)
 {
-       struct request *req;
+       struct scsi_cmnd *cmd = req->special;
+
+       blkdev_dequeue_request(req);
 
-       while ((req = elv_next_request(q)) != NULL) {
-               blkdev_dequeue_request(req);
-               req->flags |= REQ_QUIET;
-               while (end_that_request_first(req, 0, req->nr_sectors))
-                       ;
-               end_that_request_last(req);
+       if (unlikely(cmd == NULL)) {
+               printk(KERN_CRIT "impossible request in %s.\n",
+                                __FUNCTION__);
+               BUG();
        }
+
+       scsi_init_cmd_errh(cmd);
+       cmd->result = DID_NO_CONNECT << 16;
+       atomic_inc(&cmd->device->iorequest_cnt);
+       __scsi_done(cmd);
 }
 
 /*
@@ -1371,7 +1412,8 @@ static void scsi_request_fn(struct request_queue *q)
 
        if (!sdev) {
                printk("scsi: killing requests for dead queue\n");
-               scsi_kill_requests(q);
+               while ((req = elv_next_request(q)) != NULL)
+                       scsi_kill_request(req, q);
                return;
        }
 
@@ -1398,11 +1440,7 @@ static void scsi_request_fn(struct request_queue *q)
                if (unlikely(!scsi_device_online(sdev))) {
                        printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n",
                               sdev->host->host_no, sdev->id, sdev->lun);
-                       blkdev_dequeue_request(req);
-                       req->flags |= REQ_QUIET;
-                       while (end_that_request_first(req, 0, req->nr_sectors))
-                               ;
-                       end_that_request_last(req);
+                       scsi_kill_request(req, q);
                        continue;
                }
 
@@ -1415,6 +1453,14 @@ static void scsi_request_fn(struct request_queue *q)
                sdev->device_busy++;
 
                spin_unlock(q->queue_lock);
+               cmd = req->special;
+               if (unlikely(cmd == NULL)) {
+                       printk(KERN_CRIT "impossible request in %s.\n"
+                                        "please mail a stack trace to "
+                                        "linux-scsi@vger.kernel.org",
+                                        __FUNCTION__);
+                       BUG();
+               }
                spin_lock(shost->host_lock);
 
                if (!scsi_host_queue_ready(q, shost, sdev))
@@ -1433,15 +1479,6 @@ static void scsi_request_fn(struct request_queue *q)
                 */
                spin_unlock_irq(shost->host_lock);
 
-               cmd = req->special;
-               if (unlikely(cmd == NULL)) {
-                       printk(KERN_CRIT "impossible request in %s.\n"
-                                        "please mail a stack trace to "
-                                        "linux-scsi@vger.kernel.org",
-                                        __FUNCTION__);
-                       BUG();
-               }
-
                /*
                 * Finally, initialize any error handling parameters, and set up
                 * the timers for timeouts.
@@ -1477,6 +1514,7 @@ static void scsi_request_fn(struct request_queue *q)
         * cases (host limits or settings) should run the queue at some
         * later time.
         */
+       scsi_unprep_request(req);
        spin_lock_irq(q->queue_lock);
        blk_requeue_request(q, req);
        sdev->device_busy--;
index ee6de1768e534f5c8514eca4abc8641638f215ca..d05f778d31a8b42b7b44aca4c507a016bdec4477 100644 (file)
@@ -124,6 +124,7 @@ extern void scsi_sysfs_unregister(void);
 extern void scsi_sysfs_device_initialize(struct scsi_device *);
 extern int scsi_sysfs_target_initialize(struct scsi_device *);
 extern struct scsi_transport_template blank_transport_template;
+extern void __scsi_remove_device(struct scsi_device *);
 
 extern struct bus_type scsi_bus_type;
 
index 19c9a232a754b2d039352767dd71f3225633420d..b86f170fa8ed5a4dafbbd65bb1b3293ea9de21e8 100644 (file)
@@ -870,8 +870,12 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
  out_free_sdev:
        if (res == SCSI_SCAN_LUN_PRESENT) {
                if (sdevp) {
-                       scsi_device_get(sdev);
-                       *sdevp = sdev;
+                       if (scsi_device_get(sdev) == 0) {
+                               *sdevp = sdev;
+                       } else {
+                               __scsi_remove_device(sdev);
+                               res = SCSI_SCAN_NO_RESPONSE;
+                       }
                }
        } else {
                if (sdev->host->hostt->slave_destroy)
@@ -1260,6 +1264,19 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
 }
 EXPORT_SYMBOL(__scsi_add_device);
 
+int scsi_add_device(struct Scsi_Host *host, uint channel,
+                   uint target, uint lun)
+{
+       struct scsi_device *sdev = 
+               __scsi_add_device(host, channel, target, lun, NULL);
+       if (IS_ERR(sdev))
+               return PTR_ERR(sdev);
+
+       scsi_device_put(sdev);
+       return 0;
+}
+EXPORT_SYMBOL(scsi_add_device);
+
 void scsi_rescan_device(struct device *dev)
 {
        struct scsi_driver *drv;
@@ -1276,27 +1293,8 @@ void scsi_rescan_device(struct device *dev)
 }
 EXPORT_SYMBOL(scsi_rescan_device);
 
-/**
- * scsi_scan_target - scan a target id, possibly including all LUNs on the
- *     target.
- * @sdevsca:   Scsi_Device handle for scanning
- * @shost:     host to scan
- * @channel:   channel to scan
- * @id:                target id to scan
- *
- * Description:
- *     Scan the target id on @shost, @channel, and @id. Scan at least LUN
- *     0, and possibly all LUNs on the target id.
- *
- *     Use the pre-allocated @sdevscan as a handle for the scanning. This
- *     function sets sdevscan->host, sdevscan->id and sdevscan->lun; the
- *     scanning functions modify sdevscan->lun.
- *
- *     First try a REPORT LUN scan, if that does not scan the target, do a
- *     sequential scan of LUNs on the target id.
- **/
-void scsi_scan_target(struct device *parent, unsigned int channel,
-                     unsigned int id, unsigned int lun, int rescan)
+static void __scsi_scan_target(struct device *parent, unsigned int channel,
+               unsigned int id, unsigned int lun, int rescan)
 {
        struct Scsi_Host *shost = dev_to_shost(parent);
        int bflags = 0;
@@ -1310,9 +1308,7 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
                 */
                return;
 
-
        starget = scsi_alloc_target(parent, channel, id);
-
        if (!starget)
                return;
 
@@ -1358,6 +1354,33 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
 
        put_device(&starget->dev);
 }
+
+/**
+ * scsi_scan_target - scan a target id, possibly including all LUNs on the
+ *     target.
+ * @parent:    host to scan
+ * @channel:   channel to scan
+ * @id:                target id to scan
+ * @lun:       Specific LUN to scan or SCAN_WILD_CARD
+ * @rescan:    passed to LUN scanning routines
+ *
+ * Description:
+ *     Scan the target id on @parent, @channel, and @id. Scan at least LUN 0,
+ *     and possibly all LUNs on the target id.
+ *
+ *     First try a REPORT LUN scan, if that does not scan the target, do a
+ *     sequential scan of LUNs on the target id.
+ **/
+void scsi_scan_target(struct device *parent, unsigned int channel,
+                     unsigned int id, unsigned int lun, int rescan)
+{
+       struct Scsi_Host *shost = dev_to_shost(parent);
+
+       down(&shost->scan_mutex);
+       if (scsi_host_scan_allowed(shost))
+               __scsi_scan_target(parent, channel, id, lun, rescan);
+       up(&shost->scan_mutex);
+}
 EXPORT_SYMBOL(scsi_scan_target);
 
 static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
@@ -1383,10 +1406,12 @@ static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
                                order_id = shost->max_id - id - 1;
                        else
                                order_id = id;
-                       scsi_scan_target(&shost->shost_gendev, channel, order_id, lun, rescan);
+                       __scsi_scan_target(&shost->shost_gendev, channel,
+                                       order_id, lun, rescan);
                }
        else
-               scsi_scan_target(&shost->shost_gendev, channel, id, lun, rescan);
+               __scsi_scan_target(&shost->shost_gendev, channel,
+                               id, lun, rescan);
 }
 
 int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
@@ -1484,12 +1509,15 @@ void scsi_forget_host(struct Scsi_Host *shost)
  */
 struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
 {
-       struct scsi_device *sdev;
+       struct scsi_device *sdev = NULL;
        struct scsi_target *starget;
 
+       down(&shost->scan_mutex);
+       if (!scsi_host_scan_allowed(shost))
+               goto out;
        starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id);
        if (!starget)
-               return NULL;
+               goto out;
 
        sdev = scsi_alloc_sdev(starget, 0, NULL);
        if (sdev) {
@@ -1497,6 +1525,8 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
                sdev->borken = 0;
        }
        put_device(&starget->dev);
+ out:
+       up(&shost->scan_mutex);
        return sdev;
 }
 EXPORT_SYMBOL(scsi_get_host_dev);
index dae59d1da07a720b11f2f74b5696263a8d863e3b..b8052d5206cca22f03a782044b9ca5b7d78f605f 100644 (file)
@@ -653,7 +653,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
                        error = attr_add(&sdev->sdev_gendev,
                                        sdev->host->hostt->sdev_attrs[i]);
                        if (error) {
-                               scsi_remove_device(sdev);
+                               __scsi_remove_device(sdev);
                                goto out;
                        }
                }
@@ -667,7 +667,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
                                                        scsi_sysfs_sdev_attrs[i]);
                        error = device_create_file(&sdev->sdev_gendev, attr);
                        if (error) {
-                               scsi_remove_device(sdev);
+                               __scsi_remove_device(sdev);
                                goto out;
                        }
                }
@@ -687,17 +687,10 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
        return error;
 }
 
-/**
- * scsi_remove_device - unregister a device from the scsi bus
- * @sdev:      scsi_device to unregister
- **/
-void scsi_remove_device(struct scsi_device *sdev)
+void __scsi_remove_device(struct scsi_device *sdev)
 {
-       struct Scsi_Host *shost = sdev->host;
-
-       down(&shost->scan_mutex);
        if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
-               goto out;
+               return;
 
        class_device_unregister(&sdev->sdev_classdev);
        device_del(&sdev->sdev_gendev);
@@ -706,8 +699,17 @@ void scsi_remove_device(struct scsi_device *sdev)
                sdev->host->hostt->slave_destroy(sdev);
        transport_unregister_device(&sdev->sdev_gendev);
        put_device(&sdev->sdev_gendev);
-out:
-       up(&shost->scan_mutex);
+}
+
+/**
+ * scsi_remove_device - unregister a device from the scsi bus
+ * @sdev:      scsi_device to unregister
+ **/
+void scsi_remove_device(struct scsi_device *sdev)
+{
+       down(&sdev->host->scan_mutex);
+       __scsi_remove_device(sdev);
+       up(&sdev->host->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_remove_device);
 
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
new file mode 100644 (file)
index 0000000..ff724bb
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ * Copyright (C) 2005 Dell Inc.
+ *     Released under GPL v2.
+ *
+ * Serial Attached SCSI (SAS) transport class.
+ *
+ * The SAS transport class contains common code to deal with SAS HBAs,
+ * an aproximated representation of SAS topologies in the driver model,
+ * and various sysfs attributes to expose these topologies and managment
+ * interfaces to userspace.
+ *
+ * In addition to the basic SCSI core objects this transport class
+ * introduces two additional intermediate objects:  The SAS PHY
+ * as represented by struct sas_phy defines an "outgoing" PHY on
+ * a SAS HBA or Expander, and the SAS remote PHY represented by
+ * struct sas_rphy defines an "incoming" PHY on a SAS Expander or
+ * end device.  Note that this is purely a software concept, the
+ * underlying hardware for a PHY and a remote PHY is the exactly
+ * the same.
+ *
+ * There is no concept of a SAS port in this code, users can see
+ * what PHYs form a wide port based on the port_identifier attribute,
+ * which is the same for all PHYs in a port.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+
+
+#define SAS_HOST_ATTRS         0
+#define SAS_PORT_ATTRS         11
+#define SAS_RPORT_ATTRS                5
+
+struct sas_internal {
+       struct scsi_transport_template t;
+       struct sas_function_template *f;
+
+       struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
+       struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
+       struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
+
+       struct transport_container phy_attr_cont;
+       struct transport_container rphy_attr_cont;
+
+       /*
+        * The array of null terminated pointers to attributes
+        * needed by scsi_sysfs.c
+        */
+       struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
+       struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
+       struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
+};
+#define to_sas_internal(tmpl)  container_of(tmpl, struct sas_internal, t)
+
+struct sas_host_attrs {
+       struct list_head rphy_list;
+       spinlock_t lock;
+       u32 next_target_id;
+};
+#define to_sas_host_attrs(host)        ((struct sas_host_attrs *)(host)->shost_data)
+
+
+/*
+ * Hack to allow attributes of the same name in different objects.
+ */
+#define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
+       struct class_device_attribute class_device_attr_##_prefix##_##_name = \
+       __ATTR(_name,_mode,_show,_store)
+
+
+/*
+ * Pretty printing helpers
+ */
+
+#define sas_bitfield_name_match(title, table)                  \
+static ssize_t                                                 \
+get_sas_##title##_names(u32 table_key, char *buf)              \
+{                                                              \
+       char *prefix = "";                                      \
+       ssize_t len = 0;                                        \
+       int i;                                                  \
+                                                               \
+       for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {  \
+               if (table[i].value & table_key) {               \
+                       len += sprintf(buf + len, "%s%s",       \
+                               prefix, table[i].name);         \
+                       prefix = ", ";                          \
+               }                                               \
+       }                                                       \
+       len += sprintf(buf + len, "\n");                        \
+       return len;                                             \
+}
+
+#define sas_bitfield_name_search(title, table)                 \
+static ssize_t                                                 \
+get_sas_##title##_names(u32 table_key, char *buf)              \
+{                                                              \
+       ssize_t len = 0;                                        \
+       int i;                                                  \
+                                                               \
+       for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {  \
+               if (table[i].value == table_key) {              \
+                       len += sprintf(buf + len, "%s",         \
+                               table[i].name);                 \
+                       break;                                  \
+               }                                               \
+       }                                                       \
+       len += sprintf(buf + len, "\n");                        \
+       return len;                                             \
+}
+
+static struct {
+       u32             value;
+       char            *name;
+} sas_device_type_names[] = {
+       { SAS_PHY_UNUSED,               "unused" },
+       { SAS_END_DEVICE,               "end device" },
+       { SAS_EDGE_EXPANDER_DEVICE,     "edge expander" },
+       { SAS_FANOUT_EXPANDER_DEVICE,   "fanout expander" },
+};
+sas_bitfield_name_search(device_type, sas_device_type_names)
+
+
+static struct {
+       u32             value;
+       char            *name;
+} sas_protocol_names[] = {
+       { SAS_PROTOCOL_SATA,            "sata" },
+       { SAS_PROTOCOL_SMP,             "smp" },
+       { SAS_PROTOCOL_STP,             "stp" },
+       { SAS_PROTOCOL_SSP,             "ssp" },
+};
+sas_bitfield_name_match(protocol, sas_protocol_names)
+
+static struct {
+       u32             value;
+       char            *name;
+} sas_linkspeed_names[] = {
+       { SAS_LINK_RATE_UNKNOWN,        "Unknown" },
+       { SAS_PHY_DISABLED,             "Phy disabled" },
+       { SAS_LINK_RATE_FAILED,         "Link Rate failed" },
+       { SAS_SATA_SPINUP_HOLD,         "Spin-up hold" },
+       { SAS_LINK_RATE_1_5_GBPS,       "1.5 Gbit" },
+       { SAS_LINK_RATE_3_0_GBPS,       "3.0 Gbit" },
+};
+sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
+
+
+/*
+ * SAS host attributes
+ */
+
+static int sas_host_setup(struct transport_container *tc, struct device *dev,
+                         struct class_device *cdev)
+{
+       struct Scsi_Host *shost = dev_to_shost(dev);
+       struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+       INIT_LIST_HEAD(&sas_host->rphy_list);
+       spin_lock_init(&sas_host->lock);
+       sas_host->next_target_id = 0;
+       return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(sas_host_class,
+               "sas_host", sas_host_setup, NULL, NULL);
+
+static int sas_host_match(struct attribute_container *cont,
+                           struct device *dev)
+{
+       struct Scsi_Host *shost;
+       struct sas_internal *i;
+
+       if (!scsi_is_host_device(dev))
+               return 0;
+       shost = dev_to_shost(dev);
+
+       if (!shost->transportt)
+               return 0;
+       if (shost->transportt->host_attrs.ac.class !=
+                       &sas_host_class.class)
+               return 0;
+
+       i = to_sas_internal(shost->transportt);
+       return &i->t.host_attrs.ac == cont;
+}
+
+static int do_sas_phy_delete(struct device *dev, void *data)
+{
+       if (scsi_is_sas_phy(dev))
+               sas_phy_delete(dev_to_phy(dev));
+       return 0;
+}
+
+/**
+ * sas_remove_host  --  tear down a Scsi_Host's SAS data structures
+ * @shost:     Scsi Host that is torn down
+ *
+ * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
+ * Must be called just before scsi_remove_host for SAS HBAs.
+ */
+void sas_remove_host(struct Scsi_Host *shost)
+{
+       device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete);
+}
+EXPORT_SYMBOL(sas_remove_host);
+
+
+/*
+ * SAS Port attributes
+ */
+
+#define sas_phy_show_simple(field, name, format_string, cast)          \
+static ssize_t                                                         \
+show_sas_phy_##name(struct class_device *cdev, char *buf)              \
+{                                                                      \
+       struct sas_phy *phy = transport_class_to_phy(cdev);             \
+                                                                       \
+       return snprintf(buf, 20, format_string, cast phy->field);       \
+}
+
+#define sas_phy_simple_attr(field, name, format_string, type)          \
+       sas_phy_show_simple(field, name, format_string, (type)) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
+
+#define sas_phy_show_protocol(field, name)                             \
+static ssize_t                                                         \
+show_sas_phy_##name(struct class_device *cdev, char *buf)              \
+{                                                                      \
+       struct sas_phy *phy = transport_class_to_phy(cdev);             \
+                                                                       \
+       if (!phy->field)                                                \
+               return snprintf(buf, 20, "none\n");                     \
+       return get_sas_protocol_names(phy->field, buf);         \
+}
+
+#define sas_phy_protocol_attr(field, name)                             \
+       sas_phy_show_protocol(field, name)                              \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
+
+#define sas_phy_show_linkspeed(field)                                  \
+static ssize_t                                                         \
+show_sas_phy_##field(struct class_device *cdev, char *buf)             \
+{                                                                      \
+       struct sas_phy *phy = transport_class_to_phy(cdev);             \
+                                                                       \
+       return get_sas_linkspeed_names(phy->field, buf);                \
+}
+
+#define sas_phy_linkspeed_attr(field)                                  \
+       sas_phy_show_linkspeed(field)                                   \
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
+
+static ssize_t
+show_sas_device_type(struct class_device *cdev, char *buf)
+{
+       struct sas_phy *phy = transport_class_to_phy(cdev);
+
+       if (!phy->identify.device_type)
+               return snprintf(buf, 20, "none\n");
+       return get_sas_device_type_names(phy->identify.device_type, buf);
+}
+
+static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
+
+sas_phy_protocol_attr(identify.initiator_port_protocols,
+               initiator_port_protocols);
+sas_phy_protocol_attr(identify.target_port_protocols,
+               target_port_protocols);
+sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
+               unsigned long long);
+sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
+sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
+sas_phy_linkspeed_attr(negotiated_linkrate);
+sas_phy_linkspeed_attr(minimum_linkrate_hw);
+sas_phy_linkspeed_attr(minimum_linkrate);
+sas_phy_linkspeed_attr(maximum_linkrate_hw);
+sas_phy_linkspeed_attr(maximum_linkrate);
+
+
+static DECLARE_TRANSPORT_CLASS(sas_phy_class,
+               "sas_phy", NULL, NULL, NULL);
+
+static int sas_phy_match(struct attribute_container *cont, struct device *dev)
+{
+       struct Scsi_Host *shost;
+       struct sas_internal *i;
+
+       if (!scsi_is_sas_phy(dev))
+               return 0;
+       shost = dev_to_shost(dev->parent);
+
+       if (!shost->transportt)
+               return 0;
+       if (shost->transportt->host_attrs.ac.class !=
+                       &sas_host_class.class)
+               return 0;
+
+       i = to_sas_internal(shost->transportt);
+       return &i->phy_attr_cont.ac == cont;
+}
+
+static void sas_phy_release(struct device *dev)
+{
+       struct sas_phy *phy = dev_to_phy(dev);
+
+       put_device(dev->parent);
+       kfree(phy);
+}
+
+/**
+ * sas_phy_alloc  --  allocates and initialize a SAS PHY structure
+ * @parent:    Parent device
+ * @number:    Port number
+ *
+ * Allocates an SAS PHY structure.  It will be added in the device tree
+ * below the device specified by @parent, which has to be either a Scsi_Host
+ * or sas_rphy.
+ *
+ * Returns:
+ *     SAS PHY allocated or %NULL if the allocation failed.
+ */
+struct sas_phy *sas_phy_alloc(struct device *parent, int number)
+{
+       struct Scsi_Host *shost = dev_to_shost(parent);
+       struct sas_phy *phy;
+
+       phy = kmalloc(sizeof(*phy), GFP_KERNEL);
+       if (!phy)
+               return NULL;
+       memset(phy, 0, sizeof(*phy));
+
+       get_device(parent);
+
+       phy->number = number;
+
+       device_initialize(&phy->dev);
+       phy->dev.parent = get_device(parent);
+       phy->dev.release = sas_phy_release;
+       sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
+
+       transport_setup_device(&phy->dev);
+
+       return phy;
+}
+EXPORT_SYMBOL(sas_phy_alloc);
+
+/**
+ * sas_phy_add  --  add a SAS PHY to the device hierachy
+ * @phy:       The PHY to be added
+ *
+ * Publishes a SAS PHY to the rest of the system.
+ */
+int sas_phy_add(struct sas_phy *phy)
+{
+       int error;
+
+       error = device_add(&phy->dev);
+       if (!error) {
+               transport_add_device(&phy->dev);
+               transport_configure_device(&phy->dev);
+       }
+
+       return error;
+}
+EXPORT_SYMBOL(sas_phy_add);
+
+/**
+ * sas_phy_free  --  free a SAS PHY
+ * @phy:       SAS PHY to free
+ *
+ * Frees the specified SAS PHY.
+ *
+ * Note:
+ *   This function must only be called on a PHY that has not
+ *   sucessfully been added using sas_phy_add().
+ */
+void sas_phy_free(struct sas_phy *phy)
+{
+       transport_destroy_device(&phy->dev);
+       put_device(phy->dev.parent);
+       put_device(phy->dev.parent);
+       put_device(phy->dev.parent);
+       kfree(phy);
+}
+EXPORT_SYMBOL(sas_phy_free);
+
+/**
+ * sas_phy_delete  --  remove SAS PHY
+ * @phy:       SAS PHY to remove
+ *
+ * Removes the specified SAS PHY.  If the SAS PHY has an
+ * associated remote PHY it is removed before.
+ */
+void
+sas_phy_delete(struct sas_phy *phy)
+{
+       struct device *dev = &phy->dev;
+
+       if (phy->rphy)
+               sas_rphy_delete(phy->rphy);
+
+       transport_remove_device(dev);
+       device_del(dev);
+       transport_destroy_device(dev);
+       put_device(dev->parent);
+}
+EXPORT_SYMBOL(sas_phy_delete);
+
+/**
+ * scsi_is_sas_phy  --  check if a struct device represents a SAS PHY
+ * @dev:       device to check
+ *
+ * Returns:
+ *     %1 if the device represents a SAS PHY, %0 else
+ */
+int scsi_is_sas_phy(const struct device *dev)
+{
+       return dev->release == sas_phy_release;
+}
+EXPORT_SYMBOL(scsi_is_sas_phy);
+
+/*
+ * SAS remote PHY attributes.
+ */
+
+#define sas_rphy_show_simple(field, name, format_string, cast)         \
+static ssize_t                                                         \
+show_sas_rphy_##name(struct class_device *cdev, char *buf)             \
+{                                                                      \
+       struct sas_rphy *rphy = transport_class_to_rphy(cdev);  \
+                                                                       \
+       return snprintf(buf, 20, format_string, cast rphy->field);      \
+}
+
+#define sas_rphy_simple_attr(field, name, format_string, type)         \
+       sas_rphy_show_simple(field, name, format_string, (type))        \
+static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO,                      \
+               show_sas_rphy_##name, NULL)
+
+#define sas_rphy_show_protocol(field, name)                            \
+static ssize_t                                                         \
+show_sas_rphy_##name(struct class_device *cdev, char *buf)             \
+{                                                                      \
+       struct sas_rphy *rphy = transport_class_to_rphy(cdev);  \
+                                                                       \
+       if (!rphy->field)                                       \
+               return snprintf(buf, 20, "none\n");                     \
+       return get_sas_protocol_names(rphy->field, buf);        \
+}
+
+#define sas_rphy_protocol_attr(field, name)                            \
+       sas_rphy_show_protocol(field, name)                             \
+static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO,                      \
+               show_sas_rphy_##name, NULL)
+
+static ssize_t
+show_sas_rphy_device_type(struct class_device *cdev, char *buf)
+{
+       struct sas_rphy *rphy = transport_class_to_rphy(cdev);
+
+       if (!rphy->identify.device_type)
+               return snprintf(buf, 20, "none\n");
+       return get_sas_device_type_names(
+                       rphy->identify.device_type, buf);
+}
+
+static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
+               show_sas_rphy_device_type, NULL);
+
+sas_rphy_protocol_attr(identify.initiator_port_protocols,
+               initiator_port_protocols);
+sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
+sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
+               unsigned long long);
+sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
+
+static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
+               "sas_rphy", NULL, NULL, NULL);
+
+static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
+{
+       struct Scsi_Host *shost;
+       struct sas_internal *i;
+
+       if (!scsi_is_sas_rphy(dev))
+               return 0;
+       shost = dev_to_shost(dev->parent->parent);
+
+       if (!shost->transportt)
+               return 0;
+       if (shost->transportt->host_attrs.ac.class !=
+                       &sas_host_class.class)
+               return 0;
+
+       i = to_sas_internal(shost->transportt);
+       return &i->rphy_attr_cont.ac == cont;
+}
+
+static void sas_rphy_release(struct device *dev)
+{
+       struct sas_rphy *rphy = dev_to_rphy(dev);
+
+       put_device(dev->parent);
+       kfree(rphy);
+}
+
+/**
+ * sas_rphy_alloc  --  allocates and initialize a SAS remote PHY structure
+ * @parent:            SAS PHY this remote PHY is conneted to
+ *
+ * Allocates an SAS remote PHY structure, connected to @parent.
+ *
+ * Returns:
+ *     SAS PHY allocated or %NULL if the allocation failed.
+ */
+struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent)
+{
+       struct Scsi_Host *shost = dev_to_shost(&parent->dev);
+       struct sas_rphy *rphy;
+
+       rphy = kmalloc(sizeof(*rphy), GFP_KERNEL);
+       if (!rphy) {
+               put_device(&parent->dev);
+               return NULL;
+       }
+       memset(rphy, 0, sizeof(*rphy));
+
+       device_initialize(&rphy->dev);
+       rphy->dev.parent = get_device(&parent->dev);
+       rphy->dev.release = sas_rphy_release;
+       sprintf(rphy->dev.bus_id, "rphy-%d:%d",
+               shost->host_no, parent->number);
+       transport_setup_device(&rphy->dev);
+
+       return rphy;
+}
+EXPORT_SYMBOL(sas_rphy_alloc);
+
+/**
+ * sas_rphy_add  --  add a SAS remote PHY to the device hierachy
+ * @rphy:      The remote PHY to be added
+ *
+ * Publishes a SAS remote PHY to the rest of the system.
+ */
+int sas_rphy_add(struct sas_rphy *rphy)
+{
+       struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
+       struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
+       struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+       struct sas_identify *identify = &rphy->identify;
+       int error;
+
+       if (parent->rphy)
+               return -ENXIO;
+       parent->rphy = rphy;
+
+       error = device_add(&rphy->dev);
+       if (error)
+               return error;
+       transport_add_device(&rphy->dev);
+       transport_configure_device(&rphy->dev);
+
+       spin_lock(&sas_host->lock);
+       list_add_tail(&rphy->list, &sas_host->rphy_list);
+       if (identify->device_type == SAS_END_DEVICE &&
+           (identify->target_port_protocols &
+            (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
+               rphy->scsi_target_id = sas_host->next_target_id++;
+       else
+               rphy->scsi_target_id = -1;
+       spin_unlock(&sas_host->lock);
+
+       if (rphy->scsi_target_id != -1) {
+               scsi_scan_target(&rphy->dev, parent->number,
+                               rphy->scsi_target_id, ~0, 0);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(sas_rphy_add);
+
+/**
+ * sas_rphy_free  --  free a SAS remote PHY
+ * @rphy       SAS remote PHY to free
+ *
+ * Frees the specified SAS remote PHY.
+ *
+ * Note:
+ *   This function must only be called on a remote
+ *   PHY that has not sucessfully been added using
+ *   sas_rphy_add().
+ */
+void sas_rphy_free(struct sas_rphy *rphy)
+{
+       struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
+       struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+       spin_lock(&sas_host->lock);
+       list_del(&rphy->list);
+       spin_unlock(&sas_host->lock);
+
+       transport_destroy_device(&rphy->dev);
+       put_device(rphy->dev.parent);
+       put_device(rphy->dev.parent);
+       put_device(rphy->dev.parent);
+       kfree(rphy);
+}
+EXPORT_SYMBOL(sas_rphy_free);
+
+/**
+ * sas_rphy_delete  --  remove SAS remote PHY
+ * @rphy:      SAS remote PHY to remove
+ *
+ * Removes the specified SAS remote PHY.
+ */
+void
+sas_rphy_delete(struct sas_rphy *rphy)
+{
+       struct device *dev = &rphy->dev;
+       struct sas_phy *parent = dev_to_phy(dev->parent);
+       struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
+       struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+       transport_destroy_device(&rphy->dev);
+
+       scsi_remove_target(&rphy->dev);
+
+       spin_lock(&sas_host->lock);
+       list_del(&rphy->list);
+       spin_unlock(&sas_host->lock);
+
+       transport_remove_device(dev);
+       device_del(dev);
+       transport_destroy_device(dev);
+       put_device(&parent->dev);
+}
+EXPORT_SYMBOL(sas_rphy_delete);
+
+/**
+ * scsi_is_sas_rphy  --  check if a struct device represents a SAS remote PHY
+ * @dev:       device to check
+ *
+ * Returns:
+ *     %1 if the device represents a SAS remote PHY, %0 else
+ */
+int scsi_is_sas_rphy(const struct device *dev)
+{
+       return dev->release == sas_rphy_release;
+}
+EXPORT_SYMBOL(scsi_is_sas_rphy);
+
+
+/*
+ * SCSI scan helper
+ */
+
+static struct device *sas_target_parent(struct Scsi_Host *shost,
+                                       int channel, uint id)
+{
+       struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+       struct sas_rphy *rphy;
+       struct device *dev = NULL;
+
+       spin_lock(&sas_host->lock);
+       list_for_each_entry(rphy, &sas_host->rphy_list, list) {
+               struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
+               if (parent->number == channel &&
+                   rphy->scsi_target_id == id)
+                       dev = &rphy->dev;
+       }
+       spin_unlock(&sas_host->lock);
+
+       return dev;
+}
+
+
+/*
+ * Setup / Teardown code
+ */
+
+#define SETUP_RPORT_ATTRIBUTE(field)                                   \
+       i->private_rphy_attrs[count] = class_device_attr_##field;       \
+       i->private_rphy_attrs[count].attr.mode = S_IRUGO;               \
+       i->private_rphy_attrs[count].store = NULL;                      \
+       i->rphy_attrs[count] = &i->private_rphy_attrs[count];   \
+       count++
+
+#define SETUP_PORT_ATTRIBUTE(field)                                    \
+       i->private_phy_attrs[count] = class_device_attr_##field;        \
+        i->private_phy_attrs[count].attr.mode = S_IRUGO;               \
+        i->private_phy_attrs[count].store = NULL;                      \
+        i->phy_attrs[count] = &i->private_phy_attrs[count];            \
+       count++
+
+
+/**
+ * sas_attach_transport  --  instantiate SAS transport template
+ * @ft:                SAS transport class function template
+ */
+struct scsi_transport_template *
+sas_attach_transport(struct sas_function_template *ft)
+{
+       struct sas_internal *i;
+       int count;
+
+       i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL);
+       if (!i)
+               return NULL;
+       memset(i, 0, sizeof(struct sas_internal));
+
+       i->t.target_parent = sas_target_parent;
+
+       i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+       i->t.host_attrs.ac.class = &sas_host_class.class;
+       i->t.host_attrs.ac.match = sas_host_match;
+       transport_container_register(&i->t.host_attrs);
+       i->t.host_size = sizeof(struct sas_host_attrs);
+
+       i->phy_attr_cont.ac.class = &sas_phy_class.class;
+       i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
+       i->phy_attr_cont.ac.match = sas_phy_match;
+       transport_container_register(&i->phy_attr_cont);
+
+       i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
+       i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
+       i->rphy_attr_cont.ac.match = sas_rphy_match;
+       transport_container_register(&i->rphy_attr_cont);
+
+       i->f = ft;
+
+       count = 0;
+       i->host_attrs[count] = NULL;
+
+       count = 0;
+       SETUP_PORT_ATTRIBUTE(initiator_port_protocols);
+       SETUP_PORT_ATTRIBUTE(target_port_protocols);
+       SETUP_PORT_ATTRIBUTE(device_type);
+       SETUP_PORT_ATTRIBUTE(sas_address);
+       SETUP_PORT_ATTRIBUTE(phy_identifier);
+       SETUP_PORT_ATTRIBUTE(port_identifier);
+       SETUP_PORT_ATTRIBUTE(negotiated_linkrate);
+       SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw);
+       SETUP_PORT_ATTRIBUTE(minimum_linkrate);
+       SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw);
+       SETUP_PORT_ATTRIBUTE(maximum_linkrate);
+       i->phy_attrs[count] = NULL;
+
+       count = 0;
+       SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
+       SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
+       SETUP_RPORT_ATTRIBUTE(rphy_device_type);
+       SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
+       SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
+       i->rphy_attrs[count] = NULL;
+
+       return &i->t;
+}
+EXPORT_SYMBOL(sas_attach_transport);
+
+/**
+ * sas_release_transport  --  release SAS transport template instance
+ * @t:         transport template instance
+ */
+void sas_release_transport(struct scsi_transport_template *t)
+{
+       struct sas_internal *i = to_sas_internal(t);
+
+       transport_container_unregister(&i->t.host_attrs);
+       transport_container_unregister(&i->phy_attr_cont);
+       transport_container_unregister(&i->rphy_attr_cont);
+
+       kfree(i);
+}
+EXPORT_SYMBOL(sas_release_transport);
+
+static __init int sas_transport_init(void)
+{
+       int error;
+
+       error = transport_class_register(&sas_host_class);
+       if (error)
+               goto out;
+       error = transport_class_register(&sas_phy_class);
+       if (error)
+               goto out_unregister_transport;
+       error = transport_class_register(&sas_rphy_class);
+       if (error)
+               goto out_unregister_phy;
+
+       return 0;
+
+ out_unregister_phy:
+       transport_class_unregister(&sas_phy_class);
+ out_unregister_transport:
+       transport_class_unregister(&sas_host_class);
+ out:
+       return error;
+
+}
+
+static void __exit sas_transport_exit(void)
+{
+       transport_class_unregister(&sas_host_class);
+       transport_class_unregister(&sas_phy_class);
+       transport_class_unregister(&sas_rphy_class);
+}
+
+MODULE_AUTHOR("Christoph Hellwig");
+MODULE_DESCRIPTION("SAS Transphy Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(sas_transport_init);
+module_exit(sas_transport_exit);
index b1b69d738d085a0ca211381d13a34bcbedde9ff9..9ea4765d1d12cc3884417fdbda92814163f42960 100644 (file)
@@ -61,7 +61,7 @@ static int sg_version_num = 30533;    /* 2 digits for each component */
 
 #ifdef CONFIG_SCSI_PROC_FS
 #include <linux/proc_fs.h>
-static char *sg_version_date = "20050901";
+static char *sg_version_date = "20050908";
 
 static int sg_proc_init(void);
 static void sg_proc_cleanup(void);
@@ -1299,7 +1299,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
                sg_rb_correct4mmap(rsv_schp, 1);        /* do only once per fd lifetime */
                sfp->mmap_called = 1;
        }
-       vma->vm_flags |= (VM_RESERVED | VM_IO);
+       vma->vm_flags |= VM_RESERVED;
        vma->vm_private_data = sfp;
        vma->vm_ops = &sg_mmap_vm_ops;
        return 0;
index 43b03c55f453859a2902c7dc50d72f741b508e20..e2ebdcad553c405b012a83c7674fe69472b42a1f 100644 (file)
@@ -63,8 +63,13 @@ struct timer_list mcfrs_timer_struct;
 #endif
 
 #if defined(CONFIG_HW_FEITH)
-  #define      CONSOLE_BAUD_RATE       38400
-  #define      DEFAULT_CBAUD           B38400
+#define        CONSOLE_BAUD_RATE       38400
+#define        DEFAULT_CBAUD           B38400
+#endif
+
+#if defined(CONFIG_MOD5272)
+#define CONSOLE_BAUD_RATE      115200
+#define DEFAULT_CBAUD          B115200
 #endif
 
 #ifndef CONSOLE_BAUD_RATE
@@ -90,7 +95,7 @@ static struct tty_driver *mcfrs_serial_driver;
 #undef SERIAL_DEBUG_OPEN
 #undef SERIAL_DEBUG_FLOW
 
-#if defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
 #define        IRQBASE (MCFINT_VECBASE+MCFINT_UART0)
 #else
 #define        IRQBASE 73
@@ -1510,7 +1515,7 @@ static void mcfrs_irqinit(struct mcf_serial *info)
        *portp = (*portp & ~0x000000ff) | 0x00000055;
        portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);
        *portp = (*portp & ~0x000003fc) | 0x000002a8;
-#elif defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
        volatile unsigned char *icrp, *uartp;
        volatile unsigned long *imrp;
 
index 4382ee60b6a85d89d9de4b94ef54ae69c2464257..6bed8713897e86a615c1f6df1a60fa45030bfc54 100644 (file)
@@ -1683,7 +1683,7 @@ static void __init probe_sccs(void)
 #ifndef CONFIG_SERIAL_DEC_CONSOLE
                        /*
                         * We're called early and memory managment isn't up, yet.
-                        * Thus check_region would fail.
+                        * Thus request_region would fail.
                         */
                        if (!request_region((unsigned long)
                                         zs_channels[n_channels].control,
index f8f21567cc22489c505d104851c80ab03fe8e47f..50858273f8d3e980ea1651f6b47b51ff2656623c 100644 (file)
@@ -631,8 +631,10 @@ static void usbin_stop(struct usb_audiodev *as)
        i = u->flags;
        spin_unlock_irqrestore(&as->lock, flags);
        while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-               set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
+               if (notkilled)
+                       schedule_timeout_interruptible(1);
+               else
+                       schedule_timeout_uninterruptible(1);
                spin_lock_irqsave(&as->lock, flags);
                i = u->flags;
                spin_unlock_irqrestore(&as->lock, flags);
@@ -1102,8 +1104,10 @@ static void usbout_stop(struct usb_audiodev *as)
        i = u->flags;
        spin_unlock_irqrestore(&as->lock, flags);
        while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-               set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
+               if (notkilled)
+                       schedule_timeout_interruptible(1);
+               else
+                       schedule_timeout_uninterruptible(1);
                spin_lock_irqsave(&as->lock, flags);
                i = u->flags;
                spin_unlock_irqrestore(&as->lock, flags);
index 12ecdb03ee5f20afd3bcef220e8aded0bb30857c..1017a97a418b110e7e5d6a55b56727d2bf17e79f 100644 (file)
@@ -1606,7 +1606,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
                return IRQ_NONE;
 
        hcd->saw_irq = 1;
-       if (hcd->state != start && hcd->state == HC_STATE_HALT)
+       if (hcd->state == HC_STATE_HALT)
                usb_hc_died (hcd);
        return IRQ_HANDLED;
 }
@@ -1630,7 +1630,6 @@ void usb_hc_died (struct usb_hcd *hcd)
        spin_lock_irqsave (&hcd_root_hub_lock, flags);
        if (hcd->rh_registered) {
                hcd->poll_rh = 0;
-               del_timer(&hcd->rh_timer);
 
                /* make khubd clean up old urbs and devices */
                usb_set_device_state (hcd->self.root_hub,
index 758c7f0ed1597d7a5b40028fd60df841236c6423..a12cab5314e98720fb87b78c05a542789c53f395 100644 (file)
@@ -435,6 +435,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
 static void hub_power_on(struct usb_hub *hub)
 {
        int port1;
+       unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
 
        /* if hub supports power switching, enable power on each port */
        if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
@@ -444,8 +445,8 @@ static void hub_power_on(struct usb_hub *hub)
                                        USB_PORT_FEAT_POWER);
        }
 
-       /* Wait for power to be enabled */
-       msleep(hub->descriptor->bPwrOn2PwrGood * 2);
+       /* Wait at least 100 msec for power to become stable */
+       msleep(max(pgood_delay, (unsigned) 100));
 }
 
 static void hub_quiesce(struct usb_hub *hub)
@@ -1460,7 +1461,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                                        port1, status);
                else {
                        status = hub_port_wait_reset(hub, port1, udev, delay);
-                       if (status)
+                       if (status && status != -ENOTCONN)
                                dev_dbg(hub->intfdev,
                                                "port_wait_reset: err = %d\n",
                                                status);
@@ -1469,8 +1470,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                /* return on disconnect or reset */
                switch (status) {
                case 0:
-                       /* TRSTRCY = 10 ms */
-                       msleep(10);
+                       /* TRSTRCY = 10 ms; plus some extra */
+                       msleep(10 + 40);
                        /* FALL THROUGH */
                case -ENOTCONN:
                case -ENODEV:
index 020815397a49ddf59743ecb1d4d0ce9443856adc..5c40980a5bd94f263e3f7618dff22a96896fa9c1 100644 (file)
@@ -483,6 +483,7 @@ ep_release (struct inode *inode, struct file *fd)
                data->state = STATE_EP_DISABLED;
                data->desc.bDescriptorType = 0;
                data->hs_desc.bDescriptorType = 0;
+               usb_ep_disable(data->ep);
        }
        put_ep (data);
        return 0;
index 2507e898af09b3cc591826d95fb562e32d1af6de..b948ffd94f4587ab3d07e6ccf1743a18a89e9ebd 100644 (file)
@@ -400,6 +400,23 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
                                return -EIO;
                        }
                        break;
+               case PCI_VENDOR_ID_NVIDIA:
+                       /* NVidia reports that certain chips don't handle
+                        * QH, ITD, or SITD addresses above 2GB.  (But TD,
+                        * data buffer, and periodic schedule are normal.)
+                        */
+                       switch (pdev->device) {
+                       case 0x003c:    /* MCP04 */
+                       case 0x005b:    /* CK804 */
+                       case 0x00d8:    /* CK8 */
+                       case 0x00e8:    /* CK8S */
+                               if (pci_set_consistent_dma_mask(pdev,
+                                                       DMA_31BIT_MASK) < 0)
+                                       ehci_warn (ehci, "can't enable NVidia "
+                                               "workaround for >2GB RAM\n");
+                               break;
+                       }
+                       break;
                }
 
                /* optional debug port, normally in the first BAR */
@@ -759,12 +776,16 @@ static int ehci_resume (struct usb_hcd *hcd)
        if (time_before (jiffies, ehci->next_statechange))
                msleep (100);
 
-       /* If any port is suspended, we know we can/must resume the HC. */
+       /* If any port is suspended (or owned by the companion),
+        * we know we can/must resume the HC (and mustn't reset it).
+        */
        for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
                u32     status;
                port--;
                status = readl (&ehci->regs->port_status [port]);
-               if (status & PORT_SUSPEND) {
+               if (!(status & PORT_POWER))
+                       continue;
+               if (status & (PORT_SUSPEND | PORT_OWNER)) {
                        down (&hcd->self.root_hub->serialize);
                        retval = ehci_hub_resume (hcd);
                        up (&hcd->self.root_hub->serialize);
@@ -1126,8 +1147,7 @@ rescan:
        case QH_STATE_UNLINK:           /* wait for hw to finish? */
 idle_timeout:
                spin_unlock_irqrestore (&ehci->lock, flags);
-               set_current_state (TASK_UNINTERRUPTIBLE);
-               schedule_timeout (1);
+               schedule_timeout_uninterruptible(1);
                goto rescan;
        case QH_STATE_IDLE:             /* fully unlinked */
                if (list_empty (&qh->qtd_list)) {
index 36cc1f2218d55d203434aafb0698773291b48e4b..18d3f22703160af0c8ac55fd8f425a5d20e8c369 100644 (file)
@@ -54,7 +54,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
        /* suspend any active/unsuspended ports, maybe allow wakeup */
        while (port--) {
                u32 __iomem     *reg = &ehci->regs->port_status [port];
-               u32             t1 = readl (reg);
+               u32             t1 = readl (reg) & ~PORT_RWC_BITS;
                u32             t2 = t1;
 
                if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
@@ -115,7 +115,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
        i = HCS_N_PORTS (ehci->hcs_params);
        while (i--) {
                temp = readl (&ehci->regs->port_status [i]);
-               temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+               temp &= ~(PORT_RWC_BITS
+                       | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
                if (temp & PORT_SUSPEND) {
                        ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
                        temp |= PORT_RESUME;
@@ -128,7 +129,7 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
                temp = readl (&ehci->regs->port_status [i]);
                if ((temp & PORT_SUSPEND) == 0)
                        continue;
-               temp &= ~PORT_RESUME;
+               temp &= ~(PORT_RWC_BITS | PORT_RESUME);
                writel (temp, &ehci->regs->port_status [i]);
                ehci_vdbg (ehci, "resumed port %d\n", i + 1);
        }
@@ -191,6 +192,7 @@ static int check_reset_complete (
 
                // what happens if HCS_N_CC(params) == 0 ?
                port_status |= PORT_OWNER;
+               port_status &= ~PORT_RWC_BITS;
                writel (port_status, &ehci->regs->port_status [index]);
 
        } else
@@ -233,7 +235,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
                if (temp & PORT_OWNER) {
                        /* don't report this in GetPortStatus */
                        if (temp & PORT_CSC) {
-                               temp &= ~PORT_CSC;
+                               temp &= ~PORT_RWC_BITS;
+                               temp |= PORT_CSC;
                                writel (temp, &ehci->regs->port_status [i]);
                        }
                        continue;
@@ -343,7 +346,7 @@ static int ehci_hub_control (
                                &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_C_ENABLE:
-                       writel (temp | PORT_PEC,
+                       writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
                                &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_SUSPEND:
@@ -353,7 +356,8 @@ static int ehci_hub_control (
                                if ((temp & PORT_PE) == 0)
                                        goto error;
                                /* resume signaling for 20 msec */
-                               writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME,
+                               temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+                               writel (temp | PORT_RESUME,
                                        &ehci->regs->port_status [wIndex]);
                                ehci->reset_done [wIndex] = jiffies
                                                + msecs_to_jiffies (20);
@@ -364,15 +368,15 @@ static int ehci_hub_control (
                        break;
                case USB_PORT_FEAT_POWER:
                        if (HCS_PPC (ehci->hcs_params))
-                               writel (temp & ~PORT_POWER,
+                               writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
                                        &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_C_CONNECTION:
-                       writel (temp | PORT_CSC,
+                       writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
                                &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_C_OVER_CURRENT:
-                       writel (temp | PORT_OCC,
+                       writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
                                &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_C_RESET:
@@ -416,7 +420,7 @@ static int ehci_hub_control (
 
                        /* stop resume signaling */
                        temp = readl (&ehci->regs->port_status [wIndex]);
-                       writel (temp & ~PORT_RESUME,
+                       writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
                                &ehci->regs->port_status [wIndex]);
                        retval = handshake (
                                        &ehci->regs->port_status [wIndex],
@@ -437,7 +441,7 @@ static int ehci_hub_control (
                        ehci->reset_done [wIndex] = 0;
 
                        /* force reset to complete */
-                       writel (temp & ~PORT_RESET,
+                       writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
                                        &ehci->regs->port_status [wIndex]);
                        /* REVISIT:  some hardware needs 550+ usec to clear
                         * this bit; seems too long to spin routinely...
@@ -500,6 +504,7 @@ static int ehci_hub_control (
                if (temp & PORT_OWNER)
                        break;
 
+               temp &= ~PORT_RWC_BITS;
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
                        if ((temp & PORT_PE) == 0
index 20c9b550097dc70e0bb3b326f144aa9628059b79..f34a0516d35ff2b63ae0355080db4016b91343a8 100644 (file)
@@ -263,6 +263,7 @@ struct ehci_regs {
 #define PORT_PE                (1<<2)          /* port enable */
 #define PORT_CSC       (1<<1)          /* connect status change */
 #define PORT_CONNECT   (1<<0)          /* device connected */
+#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
 } __attribute__ ((packed));
 
 /* Appendix C, Debug port ... intended for use with special "debug devices"
index 447f488f5d937f85de1e7c75348e04bf8400a040..7924c74f958eb28dc833de2059a1f269e0a040fb 100644 (file)
@@ -228,23 +228,22 @@ ohci_dump_roothub (
        char **next,
        unsigned *size)
 {
-       u32                     temp, ndp, i;
+       u32                     temp, i;
 
        temp = roothub_a (controller);
        if (temp == ~(u32)0)
                return;
-       ndp = (temp & RH_A_NDP);
 
        if (verbose) {
                ohci_dbg_sw (controller, next, size,
-                       "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp,
+                       "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d(%d)\n", temp,
                        ((temp & RH_A_POTPGT) >> 24) & 0xff,
                        (temp & RH_A_NOCP) ? " NOCP" : "",
                        (temp & RH_A_OCPM) ? " OCPM" : "",
                        (temp & RH_A_DT) ? " DT" : "",
                        (temp & RH_A_NPS) ? " NPS" : "",
                        (temp & RH_A_PSM) ? " PSM" : "",
-                       ndp
+                       (temp & RH_A_NDP), controller->num_ports
                        );
                temp = roothub_b (controller);
                ohci_dbg_sw (controller, next, size,
@@ -266,7 +265,7 @@ ohci_dump_roothub (
                        );
        }
 
-       for (i = 0; i < ndp; i++) {
+       for (i = 0; i < controller->num_ports; i++) {
                temp = roothub_portstatus (controller, i);
                dbg_port_sw (controller, i, temp, next, size);
        }
index 56b43f2a0e52c3eaaa750bebd7fb94e27f16d2bd..67c1aa5eb1c175994faa6593a33b009d496164cb 100644 (file)
@@ -382,8 +382,7 @@ sanitize:
                        goto sanitize;
                }
                spin_unlock_irqrestore (&ohci->lock, flags);
-               set_current_state (TASK_UNINTERRUPTIBLE);
-               schedule_timeout (1);
+               schedule_timeout_uninterruptible(1);
                goto rescan;
        case ED_IDLE:           /* fully unlinked */
                if (list_empty (&ed->td_list)) {
@@ -485,6 +484,10 @@ static int ohci_init (struct ohci_hcd *ohci)
        // flush the writes
        (void) ohci_readl (ohci, &ohci->regs->control);
 
+       /* Read the number of ports unless overridden */
+       if (ohci->num_ports == 0)
+               ohci->num_ports = roothub_a(ohci) & RH_A_NDP;
+
        if (ohci->hcca)
                return 0;
 
@@ -561,10 +564,8 @@ static int ohci_run (struct ohci_hcd *ohci)
        msleep(temp);
        temp = roothub_a (ohci);
        if (!(temp & RH_A_NPS)) {
-               unsigned ports = temp & RH_A_NDP; 
-
                /* power down each port */
-               for (temp = 0; temp < ports; temp++)
+               for (temp = 0; temp < ohci->num_ports; temp++)
                        ohci_writel (ohci, RH_PS_LSDA,
                                &ohci->regs->roothub.portstatus [temp]);
        }
@@ -720,6 +721,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
 
        if (ints & OHCI_INTR_RD) {
                ohci_vdbg (ohci, "resume detect\n");
+               ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
                if (hcd->state != HC_STATE_QUIESCING)
                        schedule_work(&ohci->rh_resume);
        }
@@ -861,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
                 * and that if we try to turn them back on the root hub
                 * will respond to CSC processing.
                 */
-               i = roothub_a (ohci) & RH_A_NDP;
+               i = ohci->num_ports;
                while (i--)
                        ohci_writel (ohci, RH_PS_PSS,
                                &ohci->regs->roothub.portstatus [temp]);
index 83ca4549a50ecac5f82504ba375419ad3c9b6d0a..ce7b28da7a1540c0e00c7f8e95b030d5191fd89e 100644 (file)
@@ -184,7 +184,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
        if (status != -EINPROGRESS)
                return status;
 
-       temp = roothub_a (ohci) & RH_A_NDP;
+       temp = ohci->num_ports;
        enables = 0;
        while (temp--) {
                u32 stat = ohci_readl (ohci,
@@ -304,7 +304,7 @@ static int
 ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-       int             ports, i, changed = 0, length = 1;
+       int             i, changed = 0, length = 1;
        int             can_suspend = hcd->can_wakeup;
        unsigned long   flags;
 
@@ -319,9 +319,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
                goto done;
        }
 
-       ports = roothub_a (ohci) & RH_A_NDP; 
-       if (ports > MAX_ROOT_PORTS) {
-               ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports,
+       /* undocumented erratum seen on at least rev D */
+       if ((ohci->flags & OHCI_QUIRK_AMD756)
+                       && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) {
+               ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n",
                          ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
                /* retry later; "should not happen" */
                goto done;
@@ -332,13 +333,13 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
                buf [0] = changed = 1;
        else
                buf [0] = 0;
-       if (ports > 7) {
+       if (ohci->num_ports > 7) {
                buf [1] = 0;
                length++;
        }
 
        /* look at each port */
-       for (i = 0; i < ports; i++) {
+       for (i = 0; i < ohci->num_ports; i++) {
                u32     status = roothub_portstatus (ohci, i);
 
                if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
@@ -395,15 +396,14 @@ ohci_hub_descriptor (
        struct usb_hub_descriptor       *desc
 ) {
        u32             rh = roothub_a (ohci);
-       int             ports = rh & RH_A_NDP; 
        u16             temp;
 
        desc->bDescriptorType = 0x29;
        desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
        desc->bHubContrCurrent = 0;
 
-       desc->bNbrPorts = ports;
-       temp = 1 + (ports / 8);
+       desc->bNbrPorts = ohci->num_ports;
+       temp = 1 + (ohci->num_ports / 8);
        desc->bDescLength = 7 + 2 * temp;
 
        temp = 0;
@@ -421,7 +421,7 @@ ohci_hub_descriptor (
        rh = roothub_b (ohci);
        memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
        desc->bitmap [0] = rh & RH_B_DR;
-       if (ports > 7) {
+       if (ohci->num_ports > 7) {
                desc->bitmap [1] = (rh & RH_B_DR) >> 8;
                desc->bitmap [2] = 0xff;
        } else
index e5bc1789d18a6532b13cdaf1e367e8002c9d9b49..2fdb262d47260afb3d3b37cb25306b0f21df3168 100644 (file)
@@ -75,33 +75,6 @@ static int pxa27x_ohci_select_pmm( int mode )
        return 0;
 }
 
-/*
-  If you select PMM_PERPORT_MODE, you should set the port power
- */
-static int pxa27x_ohci_set_port_power( int port )
-{
-       if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE)
-            && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
-               UHCRHPS(port) |= 0x100;
-               return 0;
-       }
-       return -1;
-}
-
-/*
-  If you select PMM_PERPORT_MODE, you should set the port power
- */
-static int pxa27x_ohci_clear_port_power( int port )
-{
-       if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE) 
-            && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
-               UHCRHPS(port) |= 0x200;
-               return 0;
-       }
-        
-       return -1;
-}
-
 extern int usb_disabled(void);
 
 /*-------------------------------------------------------------------------*/
@@ -130,11 +103,17 @@ static void pxa27x_start_hc(struct platform_device *dev)
                   Polarity Low to active low. Supply power to USB ports. */
                UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
                        ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
+
+               pxa27x_ohci_pmm_state = PMM_PERPORT_MODE;
        }
 
        UHCHR &= ~UHCHR_SSE;
 
        UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE);
+
+       /* Clear any OTG Pin Hold */
+       if (PSSR & PSSR_OTGPH)
+               PSSR |= PSSR_OTGPH;
 }
 
 static void pxa27x_stop_hc(struct platform_device *dev)
@@ -198,17 +177,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
        pxa27x_start_hc(dev);
 
        /* Select Power Management Mode */
-       pxa27x_ohci_select_pmm( PMM_PERPORT_MODE );
-
-       /* If choosing PMM_PERPORT_MODE, we should set the port power before we use it. */
-       if (pxa27x_ohci_set_port_power(1) < 0)
-               printk(KERN_ERR "Setting port 1 power failed.\n");
-
-       if (pxa27x_ohci_clear_port_power(2) < 0)
-               printk(KERN_ERR "Setting port 2 power failed.\n");
-
-       if (pxa27x_ohci_clear_port_power(3) < 0)
-               printk(KERN_ERR "Setting port 3 power failed.\n");
+       pxa27x_ohci_select_pmm(pxa27x_ohci_pmm_state);
 
        ohci_hcd_init(hcd_to_ohci(hcd));
 
@@ -258,6 +227,9 @@ ohci_pxa27x_start (struct usb_hcd *hcd)
 
        ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci);
 
+       /* The value of NDP in roothub_a is incorrect on this hardware */
+       ohci->num_ports = 3;
+
        if ((ret = ohci_init(ohci)) < 0)
                return ret;
 
index 71cdd2262860d129fc1776179b561f3f0ff5dcb4..8a9b9d9209e9276213a51fbc717d5c7aea0de85c 100644 (file)
@@ -383,6 +383,7 @@ struct ohci_hcd {
        /*
         * driver state
         */
+       int                     num_ports;
        int                     load [NUM_INTS];
        u32                     hc_control;     /* copy of hc control reg */
        unsigned long           next_statechange;       /* suspend/resume */
index 0d5d2545bf07ba151a40e617e52583a2a096f62b..0c024898cbea0dcdea54c7c80a24740aac79d277 100644 (file)
@@ -97,14 +97,9 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 /* to make sure it doesn't hog all of the bandwidth */
 #define DEPTH_INTERVAL 5
 
-static inline void restart_timer(struct uhci_hcd *uhci)
-{
-       mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100));
-}
-
-#include "uhci-hub.c"
 #include "uhci-debug.c"
 #include "uhci-q.c"
+#include "uhci-hub.c"
 
 /*
  * Make sure the controller is completely inactive, unable to
@@ -160,7 +155,6 @@ static void hc_died(struct uhci_hcd *uhci)
 {
        reset_hc(uhci);
        uhci->hc_inaccessible = 1;
-       del_timer(&uhci->stall_timer);
 }
 
 /*
@@ -287,8 +281,11 @@ __acquires(uhci->lock)
        /* Enable resume-detect interrupts if they work.
         * Then enter Global Suspend mode, still configured.
         */
-       int_enable = (resume_detect_interrupts_are_broken(uhci) ?
-                       0 : USBINTR_RESUME);
+       uhci->working_RD = 1;
+       int_enable = USBINTR_RESUME;
+       if (resume_detect_interrupts_are_broken(uhci)) {
+               uhci->working_RD = int_enable = 0;
+       }
        outw(int_enable, uhci->io_addr + USBINTR);
        outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
        mb();
@@ -315,7 +312,6 @@ __acquires(uhci->lock)
 
        uhci->rh_state = new_state;
        uhci->is_stopped = UHCI_IS_STOPPED;
-       del_timer(&uhci->stall_timer);
        uhci_to_hcd(uhci)->poll_rh = !int_enable;
 
        uhci_scan_schedule(uhci, NULL);
@@ -335,7 +331,6 @@ static void start_rh(struct uhci_hcd *uhci)
        mb();
        uhci->rh_state = UHCI_RH_RUNNING;
        uhci_to_hcd(uhci)->poll_rh = 1;
-       restart_timer(uhci);
 }
 
 static void wakeup_rh(struct uhci_hcd *uhci)
@@ -374,20 +369,6 @@ __acquires(uhci->lock)
        mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
 }
 
-static void stall_callback(unsigned long _uhci)
-{
-       struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
-       unsigned long flags;
-
-       spin_lock_irqsave(&uhci->lock, flags);
-       uhci_scan_schedule(uhci, NULL);
-       check_fsbr(uhci);
-
-       if (!uhci->is_stopped)
-               restart_timer(uhci);
-       spin_unlock_irqrestore(&uhci->lock, flags);
-}
-
 static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
@@ -418,8 +399,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
                                        "host controller halted, "
                                        "very bad!\n");
                                hc_died(uhci);
-                               spin_unlock_irqrestore(&uhci->lock, flags);
-                               return IRQ_HANDLED;
+
+                               /* Force a callback in case there are
+                                * pending unlinks */
+                               mod_timer(&hcd->rh_timer, jiffies);
                        }
                        spin_unlock_irqrestore(&uhci->lock, flags);
                }
@@ -427,10 +410,11 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 
        if (status & USBSTS_RD)
                usb_hcd_poll_rh_status(hcd);
-
-       spin_lock_irqsave(&uhci->lock, flags);
-       uhci_scan_schedule(uhci, regs);
-       spin_unlock_irqrestore(&uhci->lock, flags);
+       else {
+               spin_lock_irqsave(&uhci->lock, flags);
+               uhci_scan_schedule(uhci, regs);
+               spin_unlock_irqrestore(&uhci->lock, flags);
+       }
 
        return IRQ_HANDLED;
 }
@@ -595,10 +579,6 @@ static int uhci_start(struct usb_hcd *hcd)
 
        init_waitqueue_head(&uhci->waitqh);
 
-       init_timer(&uhci->stall_timer);
-       uhci->stall_timer.function = stall_callback;
-       uhci->stall_timer.data = (unsigned long) uhci;
-
        uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
                        &dma_handle, 0);
        if (!uhci->fl) {
@@ -745,11 +725,11 @@ static void uhci_stop(struct usb_hcd *hcd)
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
        spin_lock_irq(&uhci->lock);
-       reset_hc(uhci);
+       if (!uhci->hc_inaccessible)
+               reset_hc(uhci);
        uhci_scan_schedule(uhci, NULL);
        spin_unlock_irq(&uhci->lock);
 
-       del_timer_sync(&uhci->stall_timer);
        release_uhci(uhci);
 }
 
@@ -811,13 +791,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
         */
        pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
        uhci->hc_inaccessible = 1;
+       hcd->poll_rh = 0;
 
        /* FIXME: Enable non-PME# remote wakeup? */
 
 done:
        spin_unlock_irq(&uhci->lock);
-       if (rc == 0)
-               del_timer_sync(&hcd->rh_timer);
        return rc;
 }
 
@@ -850,8 +829,11 @@ static int uhci_resume(struct usb_hcd *hcd)
 
        spin_unlock_irq(&uhci->lock);
 
-       if (hcd->poll_rh)
+       if (!uhci->working_RD) {
+               /* Suspended root hub needs to be polled */
+               hcd->poll_rh = 1;
                usb_hcd_poll_rh_status(hcd);
+       }
        return 0;
 }
 #endif
index bf9c5f9b508b9eb4e8d8eef7fbab0a94454eb158..282f40b75881a98e3e77e45051d52c4cf3237791 100644 (file)
@@ -345,9 +345,6 @@ enum uhci_rh_state {
 
 /*
  * This describes the full uhci information.
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs.
  */
 struct uhci_hcd {
 
@@ -360,8 +357,6 @@ struct uhci_hcd {
        struct dma_pool *qh_pool;
        struct dma_pool *td_pool;
 
-       struct usb_bus *bus;
-
        struct uhci_td *term_td;        /* Terminating TD, see UHCI bug */
        struct uhci_qh *skelqh[UHCI_NUM_SKELQH];        /* Skeleton QH's */
 
@@ -380,6 +375,8 @@ struct uhci_hcd {
        unsigned int scan_in_progress:1;        /* Schedule scan is running */
        unsigned int need_rescan:1;             /* Redo the schedule scan */
        unsigned int hc_inaccessible:1;         /* HC is suspended or dead */
+       unsigned int working_RD:1;              /* Suspended root hub doesn't
+                                                  need to be polled */
 
        /* Support for port suspend/resume/reset */
        unsigned long port_c_suspend;           /* Bit-arrays of ports */
@@ -405,9 +402,7 @@ struct uhci_hcd {
        /* List of URB's awaiting completion callback */
        struct list_head complete_list;         /* P: uhci->lock */
 
-       int rh_numports;
-
-       struct timer_list stall_timer;
+       int rh_numports;                        /* Number of root-hub ports */
 
        wait_queue_head_t waitqh;               /* endpoint_disable waiters */
 };
index 4eace2b19ddb830602b339059e7a953633a73d39..a71e48a668050874481a69ac89cd080a300cde3a 100644 (file)
@@ -145,15 +145,16 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned long flags;
-       int status;
+       int status = 0;
 
        spin_lock_irqsave(&uhci->lock, flags);
-       if (uhci->hc_inaccessible) {
-               status = 0;
-               goto done;
-       }
 
+       uhci_scan_schedule(uhci, NULL);
+       if (uhci->hc_inaccessible)
+               goto done;
+       check_fsbr(uhci);
        uhci_check_ports(uhci);
+
        status = get_hub_status_data(uhci, buf);
 
        switch (uhci->rh_state) {
index bbb36cd6ed6106587b5d20ef827c038f837ab444..ea0d168a8c676a520b9309227db4b1b8960bc8a5 100644 (file)
@@ -33,7 +33,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
 static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
 {
        if (uhci->is_stopped)
-               mod_timer(&uhci->stall_timer, jiffies);
+               mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
        uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); 
 }
 
index 482c4be521f55424a68efe4cc328e93cd595c1cd..1e53934907c089b0067d13142e4c4356ee9ff3cc 100644 (file)
@@ -286,3 +286,23 @@ config USB_KEYSPAN_REMOTE
 
          To compile this driver as a module, choose M here: the module will
          be called keyspan_remote.
+
+config USB_APPLETOUCH
+       tristate "Apple USB Touchpad support"
+       depends on USB && INPUT
+       ---help---
+         Say Y here if you want to use an Apple USB Touchpad.
+
+         These are the touchpads that can be found on post-February 2005
+         Apple Powerbooks (prior models have a Synaptics touchpad connected
+         to the ADB bus).
+
+         This driver provides a basic mouse driver but can be interfaced
+         with the synaptics X11 driver to provide acceleration and
+         scrolling in X11.
+
+         For further information, see
+         <file:Documentation/input/appletouch.txt>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called appletouch.
index 43b2f999edfeb448bccb7bf5f73962b1e3ad66da..5e03b93f29f66a8dd42278f3c1941bee5d0c2e96 100644 (file)
@@ -41,3 +41,4 @@ obj-$(CONFIG_USB_WACOM)               += wacom.o
 obj-$(CONFIG_USB_ACECAD)       += acecad.o
 obj-$(CONFIG_USB_YEALINK)      += yealink.o
 obj-$(CONFIG_USB_XPAD)         += xpad.o
+obj-$(CONFIG_USB_APPLETOUCH)   += appletouch.o
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
new file mode 100644 (file)
index 0000000..e03c1c5
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Apple USB Touchpad (for post-February 2005 PowerBooks) driver
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
+ * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
+ * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
+ * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
+ *
+ * Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/input.h>
+#include <linux/usb_input.h>
+
+/* Apple has powerbooks which have the keyboard with different Product IDs */
+#define APPLE_VENDOR_ID                0x05AC
+
+#define ATP_DEVICE(prod)                                       \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |             \
+                      USB_DEVICE_ID_MATCH_INT_CLASS |          \
+                      USB_DEVICE_ID_MATCH_INT_PROTOCOL,        \
+       .idVendor = APPLE_VENDOR_ID,                            \
+       .idProduct = (prod),                                    \
+       .bInterfaceClass = 0x03,                                \
+       .bInterfaceProtocol = 0x02
+
+/* table of devices that work with this driver */
+static struct usb_device_id atp_table [] = {
+       { ATP_DEVICE(0x020E) },
+       { ATP_DEVICE(0x020F) },
+       { ATP_DEVICE(0x030A) },
+       { ATP_DEVICE(0x030B) },
+       { }                                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, atp_table);
+
+/* size of a USB urb transfer */
+#define ATP_DATASIZE   81
+
+/*
+ * number of sensors. Note that only 16 instead of 26 X (horizontal)
+ * sensors exist on 12" and 15" PowerBooks. All models have 16 Y
+ * (vertical) sensors.
+ */
+#define ATP_XSENSORS   26
+#define ATP_YSENSORS   16
+
+/* amount of fuzz this touchpad generates */
+#define ATP_FUZZ       16
+
+/* maximum pressure this driver will report */
+#define ATP_PRESSURE   300
+/*
+ * multiplication factor for the X and Y coordinates.
+ * We try to keep the touchpad aspect ratio while still doing only simple
+ * arithmetics.
+ * The factors below give coordinates like:
+ *     0 <= x <  960 on 12" and 15" Powerbooks
+ *     0 <= x < 1600 on 17" Powerbooks
+ *     0 <= y <  646
+ */
+#define ATP_XFACT      64
+#define ATP_YFACT      43
+
+/*
+ * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
+ * ignored.
+ */
+#define ATP_THRESHOLD   5
+
+/* Structure to hold all of our device specific stuff */
+struct atp {
+       struct usb_device *     udev;           /* usb device */
+       struct urb *            urb;            /* usb request block */
+       signed char *           data;           /* transferred data */
+       int                     open;           /* non-zero if opened */
+       struct input_dev        input;          /* input dev */
+       int                     valid;          /* are the sensors valid ? */
+       int                     x_old;          /* last reported x/y, */
+       int                     y_old;          /* used for smoothing */
+                                               /* current value of the sensors */
+       signed char             xy_cur[ATP_XSENSORS + ATP_YSENSORS];
+                                               /* last value of the sensors */
+       signed char             xy_old[ATP_XSENSORS + ATP_YSENSORS];
+                                               /* accumulated sensors */
+       int                     xy_acc[ATP_XSENSORS + ATP_YSENSORS];
+};
+
+#define dbg_dump(msg, tab) \
+       if (debug > 1) {                                                \
+               int i;                                                  \
+               printk("appletouch: %s %lld", msg, (long long)jiffies); \
+               for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++)       \
+                       printk(" %02x", tab[i]);                        \
+               printk("\n");                                           \
+       }
+
+#define dprintk(format, a...)                                          \
+       do {                                                            \
+               if (debug) printk(format, ##a);                         \
+       } while (0)
+
+MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold");
+MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver");
+MODULE_LICENSE("GPL");
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activate debugging output");
+
+static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
+                            int *z, int *fingers)
+{
+       int i;
+       /* values to calculate mean */
+       int pcum = 0, psum = 0;
+
+       *fingers = 0;
+
+       for (i = 0; i < nb_sensors; i++) {
+               if (xy_sensors[i] < ATP_THRESHOLD)
+                       continue;
+               if ((i - 1 < 0) || (xy_sensors[i - 1] < ATP_THRESHOLD))
+                       (*fingers)++;
+               pcum += xy_sensors[i] * i;
+               psum += xy_sensors[i];
+       }
+
+       if (psum > 0) {
+               *z = psum;
+               return pcum * fact / psum;
+       }
+
+       return 0;
+}
+
+static inline void atp_report_fingers(struct input_dev *input, int fingers)
+{
+       input_report_key(input, BTN_TOOL_FINGER, fingers == 1);
+       input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2);
+       input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
+}
+
+static void atp_complete(struct urb* urb, struct pt_regs* regs)
+{
+       int x, y, x_z, y_z, x_f, y_f;
+       int retval, i;
+       struct atp *dev = urb->context;
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* This urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d",
+                   __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d",
+                   __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       /* drop incomplete datasets */
+       if (dev->urb->actual_length != ATP_DATASIZE) {
+               dprintk("appletouch: incomplete data package.\n");
+               goto exit;
+       }
+
+       /* reorder the sensors values */
+       for (i = 0; i < 8; i++) {
+               /* X values */
+               dev->xy_cur[i     ] = dev->data[5 * i +  2];
+               dev->xy_cur[i +  8] = dev->data[5 * i +  4];
+               dev->xy_cur[i + 16] = dev->data[5 * i + 42];
+               if (i < 2)
+                       dev->xy_cur[i + 24] = dev->data[5 * i + 44];
+
+               /* Y values */
+               dev->xy_cur[i + 26] = dev->data[5 * i +  1];
+               dev->xy_cur[i + 34] = dev->data[5 * i +  3];
+       }
+
+       dbg_dump("sample", dev->xy_cur);
+
+       if (!dev->valid) {
+               /* first sample */
+               dev->valid = 1;
+               dev->x_old = dev->y_old = -1;
+               memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
+
+               /* 17" Powerbooks have 10 extra X sensors */
+               for (i = 16; i < ATP_XSENSORS; i++)
+                       if (dev->xy_cur[i]) {
+                               printk("appletouch: 17\" model detected.\n");
+                               input_set_abs_params(&dev->input, ABS_X, 0,
+                                                    (ATP_XSENSORS - 1) *
+                                                    ATP_XFACT - 1,
+                                                    ATP_FUZZ, 0);
+                               break;
+                       }
+
+               goto exit;
+       }
+
+       for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
+               /* accumulate the change */
+               signed char change = dev->xy_old[i] - dev->xy_cur[i];
+               dev->xy_acc[i] -= change;
+
+               /* prevent down drifting */
+               if (dev->xy_acc[i] < 0)
+                       dev->xy_acc[i] = 0;
+       }
+
+       memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
+
+       dbg_dump("accumulator", dev->xy_acc);
+
+       x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+                             ATP_XFACT, &x_z, &x_f);
+       y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+                             ATP_YFACT, &y_z, &y_f);
+
+       if (x && y) {
+               if (dev->x_old != -1) {
+                       x = (dev->x_old * 3 + x) >> 2;
+                       y = (dev->y_old * 3 + y) >> 2;
+                       dev->x_old = x;
+                       dev->y_old = y;
+
+                       if (debug > 1)
+                               printk("appletouch: X: %3d Y: %3d "
+                                      "Xz: %3d Yz: %3d\n",
+                                      x, y, x_z, y_z);
+
+                       input_report_key(&dev->input, BTN_TOUCH, 1);
+                       input_report_abs(&dev->input, ABS_X, x);
+                       input_report_abs(&dev->input, ABS_Y, y);
+                       input_report_abs(&dev->input, ABS_PRESSURE,
+                                        min(ATP_PRESSURE, x_z + y_z));
+                       atp_report_fingers(&dev->input, max(x_f, y_f));
+               }
+               dev->x_old = x;
+               dev->y_old = y;
+       }
+       else if (!x && !y) {
+
+               dev->x_old = dev->y_old = -1;
+               input_report_key(&dev->input, BTN_TOUCH, 0);
+               input_report_abs(&dev->input, ABS_PRESSURE, 0);
+               atp_report_fingers(&dev->input, 0);
+
+               /* reset the accumulator on release */
+               memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
+       }
+
+       input_report_key(&dev->input, BTN_LEFT, !!dev->data[80]);
+
+       input_sync(&dev->input);
+
+exit:
+       retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
+       if (retval) {
+               err("%s - usb_submit_urb failed with result %d",
+                   __FUNCTION__, retval);
+       }
+}
+
+static int atp_open(struct input_dev *input)
+{
+       struct atp *dev = input->private;
+
+       if (usb_submit_urb(dev->urb, GFP_ATOMIC))
+               return -EIO;
+
+       dev->open = 1;
+       return 0;
+}
+
+static void atp_close(struct input_dev *input)
+{
+       struct atp *dev = input->private;
+
+       usb_kill_urb(dev->urb);
+       dev->open = 0;
+}
+
+static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+       struct atp *dev = NULL;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       int int_in_endpointAddr = 0;
+       int i, retval = -ENOMEM;
+
+       /* allocate memory for our device state and initialize it */
+       dev = kmalloc(sizeof(struct atp), GFP_KERNEL);
+       if (dev == NULL) {
+               err("Out of memory");
+               goto err_kmalloc;
+       }
+       memset(dev, 0, sizeof(struct atp));
+
+       dev->udev = interface_to_usbdev(iface);
+
+       /* set up the endpoint information */
+       /* use only the first interrupt-in endpoint */
+       iface_desc = iface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+               endpoint = &iface_desc->endpoint[i].desc;
+               if (!int_in_endpointAddr &&
+                   (endpoint->bEndpointAddress & USB_DIR_IN) &&
+                   ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                                       == USB_ENDPOINT_XFER_INT)) {
+                       /* we found an interrupt in endpoint */
+                       int_in_endpointAddr = endpoint->bEndpointAddress;
+                       break;
+               }
+       }
+       if (!int_in_endpointAddr) {
+               retval = -EIO;
+               err("Could not find int-in endpoint");
+               goto err_endpoint;
+       }
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(iface, dev);
+
+       dev->urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->urb) {
+               retval = -ENOMEM;
+               goto err_usballoc;
+       }
+       dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL,
+                                    &dev->urb->transfer_dma);
+       if (!dev->data) {
+               retval = -ENOMEM;
+               goto err_usbbufalloc;
+       }
+       usb_fill_int_urb(dev->urb, dev->udev,
+                        usb_rcvintpipe(dev->udev, int_in_endpointAddr),
+                        dev->data, ATP_DATASIZE, atp_complete, dev, 1);
+
+       init_input_dev(&dev->input);
+       dev->input.name = "appletouch";
+       dev->input.dev = &iface->dev;
+       dev->input.private = dev;
+       dev->input.open = atp_open;
+       dev->input.close = atp_close;
+
+       usb_to_input_id(dev->udev, &dev->input.id);
+
+       set_bit(EV_ABS, dev->input.evbit);
+
+       /*
+        * 12" and 15" Powerbooks only have 16 x sensors,
+        * 17" models are detected later.
+        */
+       input_set_abs_params(&dev->input, ABS_X, 0,
+                            (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0);
+       input_set_abs_params(&dev->input, ABS_Y, 0,
+                            (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0);
+       input_set_abs_params(&dev->input, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
+
+       set_bit(EV_KEY, dev->input.evbit);
+       set_bit(BTN_TOUCH, dev->input.keybit);
+       set_bit(BTN_TOOL_FINGER, dev->input.keybit);
+       set_bit(BTN_TOOL_DOUBLETAP, dev->input.keybit);
+       set_bit(BTN_TOOL_TRIPLETAP, dev->input.keybit);
+       set_bit(BTN_LEFT, dev->input.keybit);
+
+       input_register_device(&dev->input);
+
+       printk(KERN_INFO "input: appletouch connected\n");
+
+       return 0;
+
+err_usbbufalloc:
+       usb_free_urb(dev->urb);
+err_usballoc:
+       usb_set_intfdata(iface, NULL);
+err_endpoint:
+       kfree(dev);
+err_kmalloc:
+       return retval;
+}
+
+static void atp_disconnect(struct usb_interface *iface)
+{
+       struct atp *dev = usb_get_intfdata(iface);
+
+       usb_set_intfdata(iface, NULL);
+       if (dev) {
+               usb_kill_urb(dev->urb);
+               input_unregister_device(&dev->input);
+               usb_free_urb(dev->urb);
+               usb_buffer_free(dev->udev, ATP_DATASIZE,
+                               dev->data, dev->urb->transfer_dma);
+               kfree(dev);
+       }
+       printk(KERN_INFO "input: appletouch disconnected\n");
+}
+
+static int atp_suspend(struct usb_interface *iface, pm_message_t message)
+{
+       struct atp *dev = usb_get_intfdata(iface);
+       usb_kill_urb(dev->urb);
+       dev->valid = 0;
+       return 0;
+}
+
+static int atp_resume(struct usb_interface *iface)
+{
+       struct atp *dev = usb_get_intfdata(iface);
+       if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
+               return -EIO;
+
+       return 0;
+}
+
+static struct usb_driver atp_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "appletouch",
+       .probe          = atp_probe,
+       .disconnect     = atp_disconnect,
+       .suspend        = atp_suspend,
+       .resume         = atp_resume,
+       .id_table       = atp_table,
+};
+
+static int __init atp_init(void)
+{
+       return usb_register(&atp_driver);
+}
+
+static void __exit atp_exit(void)
+{
+       usb_deregister(&atp_driver);
+}
+
+module_init(atp_init);
+module_exit(atp_exit);
index e108e0a36b743fd88c191a7e96c8339dbe39f451..a99865c689c57535b2d1215f1c6df8c4e3a3d81b 100644 (file)
@@ -1446,7 +1446,6 @@ void hid_init_reports(struct hid_device *hid)
 
 #define USB_VENDOR_ID_APPLE            0x05ac
 #define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304
-#define USB_DEVICE_ID_APPLE_BLUETOOTH  0x1000
 
 /*
  * Alphabetically sorted blacklist by quirk type.
@@ -1465,7 +1464,6 @@ static struct hid_blacklist {
        { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_BLUETOOTH, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
index 3957e144caf7343e2af800653a822d51617c2d08..7603cbe0865d1268811c717dcaadb0eb7224ce09 100644 (file)
@@ -4,11 +4,43 @@ config USB_SISUSBVGA
        depends on USB && USB_EHCI_HCD
         ---help---
          Say Y here if you intend to attach a USB2VGA dongle based on a
-         Net2280 and a SiS315 chip. 
-         
-         Note that this device requires a USB 2.0 host controller. It will not 
+         Net2280 and a SiS315 chip.
+
+         Note that this device requires a USB 2.0 host controller. It will not
          work with USB 1.x controllers.
 
-         To compile this driver as a module, choose M here: the module will be
-         called sisusb.  If unsure, say N.
+         To compile this driver as a module, choose M here; the module will be
+         called sisusbvga. If unsure, say N.
+
+config USB_SISUSBVGA_CON
+       bool "Text console and mode switching support" if USB_SISUSBVGA
+       depends on VT
+       select FONT_8x16
+       ---help---
+         Say Y here if you want a VGA text console via the USB dongle or
+         want to support userland applications that utilize the driver's
+         display mode switching capabilities.
+
+         Note that this console supports VGA/EGA text mode only.
+
+         By default, the console part of the driver will not kick in when
+         the driver is initialized. If you want the driver to take over
+         one or more of the consoles, you need to specify the number of
+         the first and last consoles (starting at 1) as driver parameters.
+
+         For example, if the driver is compiled as a module:
+
+            modprobe sisusbvga first=1 last=5
+
+         If you use hotplug, add this to your modutils config files with
+         the "options" keyword, such as eg.
+
+            options sisusbvga first=1 last=5
+
+         If the driver is compiled into the kernel image, the parameters
+         must be given in the kernel command like, such as
+
+            sisusbvga.first=1 sisusbvga.last=5
+
+
 
index 76f1643ceaf8e96bd634d4ca577d8fd73e3818ab..7f934cfc906c4f503fa7c36a75006ad74cc8deb4 100644 (file)
@@ -2,5 +2,7 @@
 # Makefile for the sisusb driver (if driver is inside kernel tree).
 #
 
-obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o
+obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o
+
+sisusbvga-objs := sisusb.o sisusb_init.o sisusb_con.o
 
index d63ce6c030f39d442d98bb16e04b6569ca19457e..39db3155723a567ee21e777d455904305c1f1497 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
  *
+ * Main part
+ *
  * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
  *
  * If distributed as part of the Linux kernel, this code is licensed under the
 #include <linux/kref.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
 
 #include "sisusb.h"
 
+#ifdef INCL_SISUSB_CON
+#include <linux/font.h>
+#endif
+
 #define SISUSB_DONTSYNC
 
 /* Forward declarations / clean-up routines */
 
+#ifdef INCL_SISUSB_CON
+int    sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+int    sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
+int    sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data);
+int    sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data);
+int    sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor);
+int    sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor);
+int    sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand);
+
+int    sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
+int    sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int    sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
+int    sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
+int    sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
+                       u32 dest, int length, size_t *bytes_written);
+
+int    sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
+
+extern int  SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+extern int  SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+
+extern void sisusb_init_concode(void);
+extern int  sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
+extern void sisusb_console_exit(struct sisusb_usb_data *sisusb);
+
+extern void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
+
+extern int  sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
+               u8 *arg, int cmapsz, int ch512, int dorecalc,
+               struct vc_data *c, int fh, int uplock);
+
+static int sisusb_first_vc = 0;
+static int sisusb_last_vc = 0;
+module_param_named(first, sisusb_first_vc, int, 0);
+module_param_named(last, sisusb_last_vc, int, 0);
+MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
+MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
+#endif
+
 static struct usb_driver sisusb_driver;
 
-static DECLARE_MUTEX(disconnect_sem);
+DECLARE_MUTEX(disconnect_sem);
 
 static void
 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
@@ -639,7 +685,10 @@ static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
 
 /* The following routines assume being used to transfer byte, word,
  * long etc.
- * This means that they assume "data" in machine endianness format.
+ * This means that
+ *   - the write routines expect "data" in machine endianness format.
+ *     The data will be converted to leXX in sisusb_xxx_packet.
+ *   - the read routines can expect read data in machine-endianess.
  */
 
 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
@@ -839,7 +888,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                                if (get_user(swap16, (u16 __user *)userbuffer))
                                        return -EFAULT;
                        } else
-                               swap16 = (kernbuffer[0] << 8) | kernbuffer[1];
+                               swap16 = *((u16 *)kernbuffer);
 
                        ret = sisusb_write_memio_word(sisusb,
                                                        SISUSB_TYPE_MEM,
@@ -855,14 +904,25 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                        if (userbuffer) {
                                if (copy_from_user(&buf, userbuffer, 3))
                                        return -EFAULT;
-
+#ifdef __BIG_ENDIAN
                                swap32 = (buf[0] << 16) |
                                         (buf[1] <<  8) |
                                         buf[2];
+#else
+                               swap32 = (buf[2] << 16) |
+                                        (buf[1] <<  8) |
+                                        buf[0];
+#endif
                        } else
+#ifdef __BIG_ENDIAN
                                swap32 = (kernbuffer[0] << 16) |
                                         (kernbuffer[1] <<  8) |
                                         kernbuffer[2];
+#else
+                               swap32 = (kernbuffer[2] << 16) |
+                                        (kernbuffer[1] <<  8) |
+                                        kernbuffer[0];
+#endif
 
                        ret = sisusb_write_memio_24bit(sisusb,
                                                        SISUSB_TYPE_MEM,
@@ -879,10 +939,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                                if (get_user(swap32, (u32 __user *)userbuffer))
                                        return -EFAULT;
                        } else
-                               swap32 = (kernbuffer[0] << 24) |
-                                        (kernbuffer[1] << 16) |
-                                        (kernbuffer[2] <<  8) |
-                                        kernbuffer[3];
+                               swap32 = *((u32 *)kernbuffer);
 
                        ret = sisusb_write_memio_long(sisusb,
                                                        SISUSB_TYPE_MEM,
@@ -1005,6 +1062,10 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
        return ret ? -EIO : 0;
 }
 
+/* Remember: Read data in packet is in machine-endianess! So for
+ * byte, word, 24bit, long no endian correction is necessary.
+ */
+
 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
                                                        u32 addr, u8 *data)
 {
@@ -1191,8 +1252,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                                                (u16 __user *)userbuffer))
                                                return -EFAULT;
                                } else {
-                                       kernbuffer[0] = swap16 >> 8;
-                                       kernbuffer[1] = swap16 & 0xff;
+                                       *((u16 *)kernbuffer) = swap16;
                                }
                        }
                        return ret;
@@ -1202,9 +1262,15 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                                                                addr, &swap32);
                        if (!ret) {
                                (*bytes_read) += 3;
+#ifdef __BIG_ENDIAN
                                buf[0] = (swap32 >> 16) & 0xff;
                                buf[1] = (swap32 >> 8) & 0xff;
                                buf[2] = swap32 & 0xff;
+#else
+                               buf[2] = (swap32 >> 16) & 0xff;
+                               buf[1] = (swap32 >> 8) & 0xff;
+                               buf[0] = swap32 & 0xff;
+#endif
                                if (userbuffer) {
                                        if (copy_to_user(userbuffer, &buf[0], 3))
                                                return -EFAULT;
@@ -1228,10 +1294,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
 
                                        userbuffer += 4;
                                } else {
-                                       kernbuffer[0] = (swap32 >> 24) & 0xff;
-                                       kernbuffer[1] = (swap32 >> 16) & 0xff;
-                                       kernbuffer[2] = (swap32 >> 8) & 0xff;
-                                       kernbuffer[3] = swap32 & 0xff;
+                                       *((u32 *)kernbuffer) = swap32;
                                        kernbuffer += 4;
                                }
                                addr += 4;
@@ -1289,7 +1352,24 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
 
 /* High level: Gfx (indexed) register access */
 
-static int
+#ifdef INCL_SISUSB_CON
+int
+sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
+{
+       return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
+}
+
+int
+sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
+{
+       return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
+}
+#endif
+
+#ifndef INCL_SISUSB_CON
+static
+#endif
+int
 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
 {
        int ret;
@@ -1298,7 +1378,10 @@ sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
        return ret;
 }
 
-static int
+#ifndef INCL_SISUSB_CON
+static
+#endif
+int
 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
 {
        int ret;
@@ -1307,7 +1390,10 @@ sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
        return ret;
 }
 
-static int
+#ifndef INCL_SISUSB_CON
+static
+#endif
+int
 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
                                                        u8 myand, u8 myor)
 {
@@ -1336,18 +1422,89 @@ sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
        return ret;
 }
 
-static int
+#ifndef INCL_SISUSB_CON
+static
+#endif
+int
 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
 {
        return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
 }
 
-static int
+#ifndef INCL_SISUSB_CON
+static
+#endif
+int
 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
 {
        return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
 }
 
+/* Write/read video ram */
+
+#ifdef INCL_SISUSB_CON
+int
+sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
+{
+       return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
+}
+
+int
+sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
+{
+       return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
+}
+
+int
+sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
+{
+       return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
+}
+
+int
+sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
+{
+       return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
+}
+
+int
+sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
+                       u32 dest, int length, size_t *bytes_written)
+{
+       return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
+}
+
+#ifdef SISUSBENDIANTEST
+int
+sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
+                       u32 src, int length, size_t *bytes_written)
+{
+       return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
+}
+#endif
+#endif
+
+#ifdef SISUSBENDIANTEST
+static void
+sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
+{
+    static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
+    char destbuffer[10];
+    size_t dummy;
+    int i,j;
+
+    sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
+
+    for(i = 1; i <= 7; i++) {
+        printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+       sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
+       for(j = 0; j < i; j++) {
+            printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+       }
+    }
+}
+#endif
+
 /* access pci config registers (reg numbers 0, 4, 8, etc) */
 
 static int
@@ -2270,6 +2427,129 @@ sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
        return ret;
 }
 
+
+#ifdef INCL_SISUSB_CON
+
+/* Set up default text mode:
+   - Set text mode (0x03)
+   - Upload default font
+   - Upload user font (if available)
+*/
+
+int
+sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
+{
+       int ret = 0, slot = sisusb->font_slot, i;
+       struct font_desc *myfont;
+       u8 *tempbuf;
+       u16 *tempbufb;
+       size_t written;
+       static char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
+       static char bootlogo[] = "(o_ //\\ V_/_";
+
+       /* sisusb->lock is down */
+
+       if (!sisusb->SiS_Pr)
+               return 1;
+
+       sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
+       sisusb->SiS_Pr->sisusb = (void *)sisusb;
+
+       /* Set mode 0x03 */
+       SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
+
+       if (!(myfont = find_font("VGA8x16")))
+               return 1;
+
+       if (!(tempbuf = vmalloc(8192)))
+               return 1;
+
+       for (i = 0; i < 256; i++)
+               memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
+
+       /* Upload default font */
+       ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
+
+       vfree(tempbuf);
+
+       /* Upload user font (and reset current slot) */
+       if (sisusb->font_backup) {
+               ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
+                               8192, sisusb->font_backup_512, 1, NULL,
+                               sisusb->font_backup_height, 0);
+               if (slot != 2)
+                       sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
+                                       NULL, 16, 0);
+       }
+
+       if (init && !sisusb->scrbuf) {
+
+               if ((tempbuf = vmalloc(8192))) {
+
+                       i = 4096;
+                       tempbufb = (u16 *)tempbuf;
+                       while (i--)
+                               *(tempbufb++) = 0x0720;
+
+                       i = 0;
+                       tempbufb = (u16 *)tempbuf;
+                       while (bootlogo[i]) {
+                               *(tempbufb++) = 0x0700 | bootlogo[i++];
+                               if (!(i % 4))
+                                       tempbufb += 76;
+                       }
+
+                       i = 0;
+                       tempbufb = (u16 *)tempbuf + 6;
+                       while (bootstring[i])
+                               *(tempbufb++) = 0x0700 | bootstring[i++];
+
+                       ret |= sisusb_copy_memory(sisusb, tempbuf,
+                               sisusb->vrambase, 8192, &written);
+
+                       vfree(tempbuf);
+
+               }
+
+       } else if (sisusb->scrbuf) {
+
+               ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
+                               sisusb->vrambase, sisusb->scrbuf_size, &written);
+
+       }
+
+       if (sisusb->sisusb_cursor_size_from >= 0 &&
+           sisusb->sisusb_cursor_size_to >= 0) {
+               sisusb_setidxreg(sisusb, SISCR, 0x0a,
+                               sisusb->sisusb_cursor_size_from);
+               sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
+                               sisusb->sisusb_cursor_size_to);
+       } else {
+               sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
+               sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
+               sisusb->sisusb_cursor_size_to = -1;
+       }
+
+       slot = sisusb->sisusb_cursor_loc;
+       if(slot < 0) slot = 0;
+
+       sisusb->sisusb_cursor_loc = -1;
+       sisusb->bad_cursor_pos = 1;
+
+       sisusb_set_cursor(sisusb, slot);
+
+       sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
+       sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
+
+       sisusb->textmodedestroyed = 0;
+
+       /* sisusb->lock is down */
+
+       return ret;
+}
+
+#endif
+
 /* fops */
 
 static int
@@ -2329,7 +2609,7 @@ sisusb_open(struct inode *inode, struct file *file)
                }
        }
 
-       /* increment usage count for the device */
+       /* Increment usage count for our sisusb */
        kref_get(&sisusb->kref);
 
        sisusb->isopen = 1;
@@ -2340,12 +2620,10 @@ sisusb_open(struct inode *inode, struct file *file)
 
        up(&disconnect_sem);
 
-       printk(KERN_DEBUG "sisusbvga[%d]: opened", sisusb->minor);
-
        return 0;
 }
 
-static void
+void
 sisusb_delete(struct kref *kref)
 {
        struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
@@ -2359,6 +2637,9 @@ sisusb_delete(struct kref *kref)
        sisusb->sisusb_dev = NULL;
        sisusb_free_buffers(sisusb);
        sisusb_free_urbs(sisusb);
+#ifdef INCL_SISUSB_CON
+       kfree(sisusb->SiS_Pr);
+#endif
        kfree(sisusb);
 }
 
@@ -2395,8 +2676,6 @@ sisusb_release(struct inode *inode, struct file *file)
 
        up(&disconnect_sem);
 
-       printk(KERN_DEBUG "sisusbvga[%d]: released", myminor);
-
        return 0;
 }
 
@@ -2733,6 +3012,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
        int     retval, port, length;
        u32     address;
 
+       /* All our commands require the device
+        * to be initialized.
+        */
+       if (!sisusb->devinit)
+               return -ENODEV;
+
        port = y->data3 -
                SISUSB_PCI_PSEUDO_IOPORTBASE +
                SISUSB_PCI_IOPORTBASE;
@@ -2774,6 +3059,10 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
                        break;
 
                case SUCMD_CLRSCR:
+                       /* Gfx core must be initialized */
+                       if (!sisusb->gfxinit)
+                               return -ENODEV;
+
                        length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
                        address = y->data3 -
                                SISUSB_PCI_PSEUDO_MEMBASE +
@@ -2781,11 +3070,61 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
                        retval = sisusb_clear_vram(sisusb, address, length);
                        break;
 
+               case SUCMD_HANDLETEXTMODE:
+                       retval = 0;
+#ifdef INCL_SISUSB_CON
+                       /* Gfx core must be initialized, SiS_Pr must exist */
+                       if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+                               return -ENODEV;
+
+                       switch (y->data0) {
+                       case 0:
+                               retval = sisusb_reset_text_mode(sisusb, 0);
+                               break;
+                       case 1:
+                               sisusb->textmodedestroyed = 1;
+                               break;
+                       }
+#endif
+                       break;
+
+#ifdef INCL_SISUSB_CON
+               case SUCMD_SETMODE:
+                       /* Gfx core must be initialized, SiS_Pr must exist */
+                       if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+                               return -ENODEV;
+
+                       retval = 0;
+
+                       sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
+                       sisusb->SiS_Pr->sisusb = (void *)sisusb;
+
+                       if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
+                               retval = -EINVAL;
+
+                       break;
+
+               case SUCMD_SETVESAMODE:
+                       /* Gfx core must be initialized, SiS_Pr must exist */
+                       if (!sisusb->gfxinit || !sisusb->SiS_Pr)
+                               return -ENODEV;
+
+                       retval = 0;
+
+                       sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
+                       sisusb->SiS_Pr->sisusb = (void *)sisusb;
+
+                       if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
+                               retval = -EINVAL;
+
+                       break;
+#endif
+
                default:
                        retval = -EINVAL;
        }
 
-       if(retval > 0)
+       if (retval > 0)
                retval = -EIO;
 
        return retval;
@@ -2835,6 +3174,11 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        x.sisusb_vramsize   = sisusb->vramsize;
                        x.sisusb_minor      = sisusb->minor;
                        x.sisusb_fbdevactive= 0;
+#ifdef INCL_SISUSB_CON
+                       x.sisusb_conactive  = sisusb->haveconsole ? 1 : 0;
+#else
+                       x.sisusb_conactive  = 0;
+#endif
 
                        if (copy_to_user((void __user *)arg, &x, sizeof(x)))
                                retval = -EFAULT;
@@ -2895,9 +3239,13 @@ static struct file_operations usb_sisusb_fops = {
 };
 
 static struct usb_class_driver usb_sisusb_class = {
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
        .name =         "usb/sisusbvga%d",
-       .fops =         &usb_sisusb_fops,
        .mode =         S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+#else
+       .name =         "sisusbvga%d",
+#endif
+       .fops =         &usb_sisusb_fops,
        .minor_base =   SISUSB_MINOR
 };
 
@@ -2994,12 +3342,25 @@ static int sisusb_probe(struct usb_interface *intf,
        printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
                                        sisusb->minor, sisusb->numobufs);
 
+#ifdef INCL_SISUSB_CON
+       /* Allocate our SiS_Pr */
+       if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
+               printk(KERN_ERR
+                       "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
+                       sisusb->minor);
+       }
+#endif
+
        /* Do remaining init stuff */
 
        init_waitqueue_head(&sisusb->wait_q);
 
        usb_set_intfdata(intf, sisusb);
 
+       usb_get_dev(sisusb->sisusb_dev);
+
+       sisusb->present = 1;
+
 #ifdef SISUSB_OLD_CONFIG_COMPAT
        {
        int ret;
@@ -3014,14 +3375,19 @@ static int sisusb_probe(struct usb_interface *intf,
                        sisusb->minor);
        else
                sisusb->ioctl32registered = 1;
-
        }
 #endif
 
-       sisusb->present = 1;
-
        if (dev->speed == USB_SPEED_HIGH) {
-               if (sisusb_init_gfxdevice(sisusb, 1))
+               int initscreen = 1;
+#ifdef INCL_SISUSB_CON
+               if (sisusb_first_vc > 0 &&
+                   sisusb_last_vc > 0 &&
+                   sisusb_first_vc <= sisusb_last_vc &&
+                   sisusb_last_vc <= MAX_NR_CONSOLES)
+                       initscreen = 0;
+#endif
+               if (sisusb_init_gfxdevice(sisusb, initscreen))
                        printk(KERN_ERR
                                "sisusbvga[%d]: Failed to early "
                                "initialize device\n",
@@ -3035,6 +3401,16 @@ static int sisusb_probe(struct usb_interface *intf,
 
        sisusb->ready = 1;
 
+#ifdef SISUSBENDIANTEST
+       printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+       sisusb_testreadwrite(sisusb);
+       printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+#endif
+
+#ifdef INCL_SISUSB_CON
+       sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
+#endif
+
        return 0;
 
 error_4:
@@ -3053,13 +3429,20 @@ static void sisusb_disconnect(struct usb_interface *intf)
        struct sisusb_usb_data *sisusb;
        int minor;
 
-       down(&disconnect_sem);
-
        /* This should *not* happen */
-       if (!(sisusb = usb_get_intfdata(intf))) {
-               up(&disconnect_sem);
+       if (!(sisusb = usb_get_intfdata(intf)))
                return;
-       }
+
+#ifdef INCL_SISUSB_CON
+       sisusb_console_exit(sisusb);
+#endif
+
+       /* The above code doesn't need the disconnect
+        * semaphore to be down; its meaning is to
+        * protect all other routines from the disconnect
+        * case, not the other way round.
+        */
+       down(&disconnect_sem);
 
        down(&sisusb->lock);
 
@@ -3123,11 +3506,17 @@ static int __init usb_sisusb_init(void)
 {
        int retval;
 
+#ifdef INCL_SISUSB_CON
+       sisusb_init_concode();
+#endif
+
        if (!(retval = usb_register(&sisusb_driver))) {
+
                printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
                        SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
                printk(KERN_INFO
                        "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
+
        }
 
        return retval;
@@ -3142,6 +3531,6 @@ module_init(usb_sisusb_init);
 module_exit(usb_sisusb_exit);
 
 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
-MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles");
+MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
 MODULE_LICENSE("GPL");
 
index 1306d006a25aba059d6f14cca240ae962df478d8..401ff21d7881c2a0a0c7383b102f1527f6abc77b 100644 (file)
 #endif
 #endif
 
+/* For older kernels, support for text consoles is by default
+ * off. To ensable text console support, change the following:
+ */
+#if 0
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
+#define CONFIG_USB_SISUSBVGA_CON
+#endif
+#endif
+
 /* Version Information */
 
 #define SISUSB_VERSION         0
 #define SISUSB_REVISION        0
-#define SISUSB_PATCHLEVEL      7
+#define SISUSB_PATCHLEVEL      8
+
+/* Include console and mode switching code? */
+
+#ifdef CONFIG_USB_SISUSBVGA_CON
+#define INCL_SISUSB_CON                1
+#endif
+
+#ifdef INCL_SISUSB_CON
+#include <linux/console.h>
+#include <linux/vt_kern.h>
+#include "sisusb_struct.h"
+#endif
 
 /* USB related */
 
-#define SISUSB_MINOR   133             /* FIXME */
+#define SISUSB_MINOR           133     /* official */
 
 /* Size of the sisusb input/output buffers */
 #define SISUSB_IBUF_SIZE  0x01000
@@ -131,6 +152,26 @@ struct sisusb_usb_data {
        unsigned char gfxinit;          /* graphics core initialized? */
        unsigned short chipid, chipvendor;
        unsigned short chiprevision;
+#ifdef INCL_SISUSB_CON
+       struct SiS_Private *SiS_Pr;
+       unsigned long scrbuf;
+       unsigned int scrbuf_size;
+       int haveconsole, con_first, con_last;
+       int havethisconsole[MAX_NR_CONSOLES];
+       int textmodedestroyed;
+       unsigned int sisusb_num_columns; /* real number, not vt's idea */
+       int cur_start_addr, con_rolled_over;
+       int sisusb_cursor_loc, bad_cursor_pos;
+       int sisusb_cursor_size_from;
+       int sisusb_cursor_size_to;
+       int current_font_height, current_font_512;
+       int font_backup_size, font_backup_height, font_backup_512;
+       char *font_backup;
+       int font_slot;
+       struct vc_data *sisusb_display_fg;
+       int is_gfx;
+       int con_blanked;
+#endif
 };
 
 #define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref)
@@ -249,7 +290,9 @@ struct sisusb_info {
 
        __u32   sisusb_fbdevactive;     /* != 0 if framebuffer device active */
 
-       __u8    sisusb_reserved[32];    /* for future use */
+       __u32   sisusb_conactive;       /* != 0 if console driver active */
+
+       __u8    sisusb_reserved[28];    /* for future use */
 };
 
 struct sisusb_command {
@@ -261,18 +304,24 @@ struct sisusb_command {
        __u32  data4;           /* for future use */
 };
 
-#define SUCMD_GET      0x01    /* for all: data0 = index, data3 = port */
-#define SUCMD_SET      0x02    /* data1 = value */
-#define SUCMD_SETOR    0x03    /* data1 = or */
-#define SUCMD_SETAND   0x04    /* data1 = and */
-#define SUCMD_SETANDOR 0x05    /* data1 = and, data2 = or */
-#define SUCMD_SETMASK  0x06    /* data1 = data, data2 = mask */
+#define SUCMD_GET      0x01    /* for all: data0 = index, data3 = port */
+#define SUCMD_SET      0x02    /* data1 = value */
+#define SUCMD_SETOR    0x03    /* data1 = or */
+#define SUCMD_SETAND   0x04    /* data1 = and */
+#define SUCMD_SETANDOR 0x05    /* data1 = and, data2 = or */
+#define SUCMD_SETMASK  0x06    /* data1 = data, data2 = mask */
 
-#define SUCMD_CLRSCR   0x07    /* data0:1:2 = length, data3 = address */
+#define SUCMD_CLRSCR   0x07    /* data0:1:2 = length, data3 = address */
+
+#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+
+#define SUCMD_SETMODE  0x09    /* Set a display mode (data3 = SiS mode) */
+#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
 
 #define SISUSB_COMMAND         _IOWR(0xF3,0x3D,struct sisusb_command)
-#define SISUSB_GET_CONFIG_SIZE         _IOR(0xF3,0x3E,__u32)
-#define SISUSB_GET_CONFIG      _IOR(0xF3,0x3F,struct sisusb_info)
+#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
+#define SISUSB_GET_CONFIG      _IOR(0xF3,0x3F,struct sisusb_info)
+
 
 #endif /* SISUSB_H */
 
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
new file mode 100644 (file)
index 0000000..2458446
--- /dev/null
@@ -0,0 +1,1658 @@
+/*
+ * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
+ *
+ * VGA text mode console part
+ *
+ * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific psisusbr written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Portions based on vgacon.c which are
+ *     Created 28 Sep 1997 by Geert Uytterhoeven
+ *      Rewritten by Martin Mares <mj@ucw.cz>, July 1998
+ *      based on code Copyright (C) 1991, 1992  Linus Torvalds
+ *                         1995  Jay Estabrook
+ *
+ * A note on using in_atomic() in here: We can't handle console
+ * calls from non-schedulable context due to our USB-dependend
+ * nature. For now, this driver just ignores any calls if it
+ * detects this state.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/kd.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+#include <linux/smp_lock.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+
+#include "sisusb.h"
+
+#ifdef INCL_SISUSB_CON
+extern int sisusb_setreg(struct sisusb_usb_data *, int, u8);
+extern int sisusb_getreg(struct sisusb_usb_data *, int, u8 *);
+extern int sisusb_setidxreg(struct sisusb_usb_data *, int, u8, u8);
+extern int sisusb_getidxreg(struct sisusb_usb_data *, int, u8, u8 *);
+extern int sisusb_setidxregor(struct sisusb_usb_data *, int, u8, u8);
+extern int sisusb_setidxregand(struct sisusb_usb_data *, int, u8, u8);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *, int, u8, u8, u8);
+
+extern int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
+extern int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+extern int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
+extern int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
+extern int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
+                       u32 dest, int length, size_t *bytes_written);
+
+extern void sisusb_delete(struct kref *kref);
+extern int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
+
+extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+
+#define sisusbcon_writew(val, addr)    (*(addr) = (val))
+#define sisusbcon_readw(addr)          (*(addr))
+#define sisusbcon_memmovew(d, s, c)    memmove(d, s, c)
+#define sisusbcon_memcpyw(d, s, c)     memcpy(d, s, c)
+
+/* vc_data -> sisusb conversion table */
+static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES];
+
+/* Forward declaration */
+static const struct consw sisusb_con;
+
+extern struct semaphore disconnect_sem;
+
+static inline void
+sisusbcon_memsetw(u16 *s, u16 c, unsigned int count)
+{
+       count /= 2;
+       while (count--)
+               sisusbcon_writew(c, s++);
+}
+
+static inline void
+sisusb_initialize(struct sisusb_usb_data *sisusb)
+{
+       /* Reset cursor and start address */
+       if (sisusb_setidxreg(sisusb, SISCR, 0x0c, 0x00))
+               return;
+       if (sisusb_setidxreg(sisusb, SISCR, 0x0d, 0x00))
+               return;
+       if (sisusb_setidxreg(sisusb, SISCR, 0x0e, 0x00))
+               return;
+       sisusb_setidxreg(sisusb, SISCR, 0x0f, 0x00);
+}
+
+static inline void
+sisusbcon_set_start_address(struct sisusb_usb_data *sisusb, struct vc_data *c)
+{
+       sisusb->cur_start_addr = (c->vc_visible_origin - sisusb->scrbuf) / 2;
+
+       sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
+       sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
+}
+
+void
+sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location)
+{
+       if (sisusb->sisusb_cursor_loc == location)
+               return;
+
+       sisusb->sisusb_cursor_loc = location;
+
+       /* Hardware bug: Text cursor appears twice or not at all
+        * at some positions. Work around it with the cursor skew
+        * bits.
+        */
+
+       if ((location & 0x0007) == 0x0007) {
+               sisusb->bad_cursor_pos = 1;
+               location--;
+               if (sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0x1f, 0x20))
+                       return;
+       } else if (sisusb->bad_cursor_pos) {
+               if (sisusb_setidxregand(sisusb, SISCR, 0x0b, 0x1f))
+                       return;
+               sisusb->bad_cursor_pos = 0;
+       }
+
+       if (sisusb_setidxreg(sisusb, SISCR, 0x0e, (location >> 8)))
+               return;
+       sisusb_setidxreg(sisusb, SISCR, 0x0f, (location & 0xff));
+}
+
+static inline struct sisusb_usb_data *
+sisusb_get_sisusb(unsigned short console)
+{
+       return mysisusbs[console];
+}
+
+static inline int
+sisusb_sisusb_valid(struct sisusb_usb_data *sisusb)
+{
+       if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev)
+               return 0;
+
+       return 1;
+}
+
+static struct sisusb_usb_data *
+sisusb_get_sisusb_lock_and_check(unsigned short console)
+{
+       struct sisusb_usb_data *sisusb;
+
+       /* We can't handle console calls in non-schedulable
+        * context due to our locks and the USB transport.
+        * So we simply ignore them. This should only affect
+        * some calls to printk.
+        */
+       if (in_atomic())
+               return NULL;
+
+       if (!(sisusb = sisusb_get_sisusb(console)))
+               return NULL;
+
+       down(&sisusb->lock);
+
+       if (!sisusb_sisusb_valid(sisusb) ||
+           !sisusb->havethisconsole[console]) {
+               up(&sisusb->lock);
+               return NULL;
+       }
+
+       return sisusb;
+}
+
+static int
+sisusb_is_inactive(struct vc_data *c, struct sisusb_usb_data *sisusb)
+{
+       if (sisusb->is_gfx ||
+           sisusb->textmodedestroyed ||
+           c->vc_mode != KD_TEXT)
+               return 1;
+
+       return 0;
+}
+
+/* con_startup console interface routine */
+static const char *
+sisusbcon_startup(void)
+{
+       return "SISUSBCON";
+}
+
+/* con_init console interface routine */
+static void
+sisusbcon_init(struct vc_data *c, int init)
+{
+       struct sisusb_usb_data *sisusb;
+       int cols, rows;
+
+       /* This is called by take_over_console(),
+        * ie by us/under our control. It is
+        * only called after text mode and fonts
+        * are set up/restored.
+        */
+
+       down(&disconnect_sem);
+
+       if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
+               up(&disconnect_sem);
+               return;
+       }
+
+       down(&sisusb->lock);
+
+       if (!sisusb_sisusb_valid(sisusb)) {
+               up(&sisusb->lock);
+               up(&disconnect_sem);
+               return;
+       }
+
+       c->vc_can_do_color = 1;
+
+       c->vc_complement_mask = 0x7700;
+
+       c->vc_hi_font_mask = sisusb->current_font_512 ? 0x0800 : 0;
+
+       sisusb->haveconsole = 1;
+
+       sisusb->havethisconsole[c->vc_num] = 1;
+
+       /* We only support 640x400 */
+       c->vc_scan_lines = 400;
+
+       c->vc_font.height = sisusb->current_font_height;
+
+       /* We only support width = 8 */
+       cols = 80;
+       rows = c->vc_scan_lines / c->vc_font.height;
+
+       /* Increment usage count for our sisusb.
+        * Doing so saves us from upping/downing
+        * the disconnect semaphore; we can't
+        * lose our sisusb until this is undone
+        * in con_deinit. For all other console
+        * interface functions, it suffices to
+        * use sisusb->lock and do a quick check
+        * of sisusb for device disconnection.
+        */
+       kref_get(&sisusb->kref);
+
+       if (!*c->vc_uni_pagedir_loc)
+               con_set_default_unimap(c);
+
+       up(&sisusb->lock);
+
+       up(&disconnect_sem);
+
+       if (init) {
+               c->vc_cols = cols;
+               c->vc_rows = rows;
+       } else
+               vc_resize(c, cols, rows);
+}
+
+/* con_deinit console interface routine */
+static void
+sisusbcon_deinit(struct vc_data *c)
+{
+       struct sisusb_usb_data *sisusb;
+       int i;
+
+       /* This is called by take_over_console()
+        * and others, ie not under our control.
+        */
+
+       down(&disconnect_sem);
+
+       if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
+               up(&disconnect_sem);
+               return;
+       }
+
+       down(&sisusb->lock);
+
+       /* Clear ourselves in mysisusbs */
+       mysisusbs[c->vc_num] = NULL;
+
+       sisusb->havethisconsole[c->vc_num] = 0;
+
+       /* Free our font buffer if all consoles are gone */
+       if (sisusb->font_backup) {
+               for(i = 0; i < MAX_NR_CONSOLES; i++) {
+                       if (sisusb->havethisconsole[c->vc_num])
+                               break;
+               }
+               if (i == MAX_NR_CONSOLES) {
+                       vfree(sisusb->font_backup);
+                       sisusb->font_backup = NULL;
+               }
+       }
+
+       up(&sisusb->lock);
+
+       /* decrement the usage count on our sisusb */
+       kref_put(&sisusb->kref, sisusb_delete);
+
+       up(&disconnect_sem);
+}
+
+/* interface routine */
+static u8
+sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity,
+                           u8 blink, u8 underline, u8 reverse)
+{
+       u8 attr = color;
+
+       if (underline)
+               attr = (attr & 0xf0) | c->vc_ulcolor;
+       else if (intensity == 0)
+               attr = (attr & 0xf0) | c->vc_halfcolor;
+
+       if (reverse)
+               attr = ((attr) & 0x88) |
+                      ((((attr) >> 4) |
+                      ((attr) << 4)) & 0x77);
+
+       if (blink)
+               attr ^= 0x80;
+
+       if (intensity == 2)
+               attr ^= 0x08;
+
+       return attr;
+}
+
+/* Interface routine */
+static void
+sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count)
+{
+       /* Invert a region. This is called with a pointer
+        * to the console's internal screen buffer. So we
+        * simply do the inversion there and rely on
+        * a call to putc(s) to update the real screen.
+        */
+
+       while (count--) {
+               u16 a = sisusbcon_readw(p);
+
+               a = ((a) & 0x88ff)        |
+                   (((a) & 0x7000) >> 4) |
+                   (((a) & 0x0700) << 4);
+
+               sisusbcon_writew(a, p++);
+       }
+}
+
+#define SISUSB_VADDR(x,y) \
+       ((u16 *)c->vc_origin + \
+       (y) * sisusb->sisusb_num_columns + \
+       (x))
+
+#define SISUSB_HADDR(x,y) \
+       ((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \
+       (y) * sisusb->sisusb_num_columns + \
+       (x))
+
+/* Interface routine */
+static void
+sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
+{
+       struct sisusb_usb_data *sisusb;
+       ssize_t written;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return;
+
+       /* sisusb->lock is down */
+
+       /* Don't need to put the character into buffer ourselves,
+        * because the vt does this BEFORE calling us.
+        */
+#if 0
+       sisusbcon_writew(ch, SISUSB_VADDR(x, y));
+#endif
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return;
+       }
+
+
+       sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
+                               (u32)SISUSB_HADDR(x, y), 2, &written);
+
+       up(&sisusb->lock);
+}
+
+/* Interface routine */
+static void
+sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
+                        int count, int y, int x)
+{
+       struct sisusb_usb_data *sisusb;
+       ssize_t written;
+       u16 *dest;
+       int i;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return;
+
+       /* sisusb->lock is down */
+
+       /* Need to put the characters into the buffer ourselves,
+        * because the vt does this AFTER calling us.
+        */
+
+       dest = SISUSB_VADDR(x, y);
+
+       for (i = count; i > 0; i--)
+               sisusbcon_writew(sisusbcon_readw(s++), dest++);
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return;
+       }
+
+       sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
+                               (u32)SISUSB_HADDR(x, y), count * 2, &written);
+
+       up(&sisusb->lock);
+}
+
+/* Interface routine */
+static void
+sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
+{
+       struct sisusb_usb_data *sisusb;
+       u16 eattr = c->vc_video_erase_char;
+       ssize_t written;
+       int i, length, cols;
+       u16 *dest;
+
+       if (width <= 0 || height <= 0)
+               return;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return;
+
+       /* sisusb->lock is down */
+
+       /* Need to clear buffer ourselves, because the vt does
+        * this AFTER calling us.
+        */
+
+       dest = SISUSB_VADDR(x, y);
+
+       cols = sisusb->sisusb_num_columns;
+
+       if (width > cols)
+               width = cols;
+
+       if (x == 0 && width >= c->vc_cols) {
+
+               sisusbcon_memsetw(dest, eattr, height * cols * 2);
+
+       } else {
+
+               for (i = height; i > 0; i--, dest += cols)
+                       sisusbcon_memsetw(dest, eattr, width * 2);
+
+       }
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return;
+       }
+
+       length = ((height * cols) - x - (cols - width - x)) * 2;
+
+
+       sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
+                               (u32)SISUSB_HADDR(x, y), length, &written);
+
+       up(&sisusb->lock);
+}
+
+/* Interface routine */
+static void
+sisusbcon_bmove(struct vc_data *c, int sy, int sx,
+                        int dy, int dx, int height, int width)
+{
+       struct sisusb_usb_data *sisusb;
+       ssize_t written;
+       int cols, length;
+#if 0
+       u16 *src, *dest;
+       int i;
+#endif
+
+       if (width <= 0 || height <= 0)
+               return;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return;
+
+       /* sisusb->lock is down */
+
+       cols = sisusb->sisusb_num_columns;
+
+       /* Don't need to move data outselves, because
+        * vt does this BEFORE calling us.
+        * This is only used by vt's insert/deletechar.
+        */
+#if 0
+       if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
+
+               sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
+                                       height * width * 2);
+
+       } else if (dy < sy || (dy == sy && dx < sx)) {
+
+               src  = SISUSB_VADDR(sx, sy);
+               dest = SISUSB_VADDR(dx, dy);
+
+               for (i = height; i > 0; i--) {
+                       sisusbcon_memmovew(dest, src, width * 2);
+                       src  += cols;
+                       dest += cols;
+               }
+
+       } else {
+
+               src  = SISUSB_VADDR(sx, sy + height - 1);
+               dest = SISUSB_VADDR(dx, dy + height - 1);
+
+               for (i = height; i > 0; i--) {
+                       sisusbcon_memmovew(dest, src, width * 2);
+                       src  -= cols;
+                       dest -= cols;
+               }
+
+       }
+#endif
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return;
+       }
+
+       length = ((height * cols) - dx - (cols - width - dx)) * 2;
+
+
+       sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy),
+                               (u32)SISUSB_HADDR(dx, dy), length, &written);
+
+       up(&sisusb->lock);
+}
+
+/* interface routine */
+static int
+sisusbcon_switch(struct vc_data *c)
+{
+       struct sisusb_usb_data *sisusb;
+       ssize_t written;
+       int length;
+
+       /* Returnvalue 0 means we have fully restored screen,
+        *      and vt doesn't need to call do_update_region().
+        * Returnvalue != 0 naturally means the opposite.
+        */
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return 0;
+
+       /* sisusb->lock is down */
+
+       /* Don't write to screen if in gfx mode */
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return 0;
+       }
+
+       /* That really should not happen. It would mean we are
+        * being called while the vc is using its private buffer
+        * as origin.
+        */
+       if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
+               up(&sisusb->lock);
+               printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+               return 0;
+       }
+
+       /* Check that we don't copy too much */
+       length = min((int)c->vc_screenbuf_size,
+                       (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
+
+       /* Restore the screen contents */
+       sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf,
+                                                               length);
+
+       sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin,
+                               (u32)SISUSB_HADDR(0, 0),
+                               length, &written);
+
+       up(&sisusb->lock);
+
+       return 0;
+}
+
+/* interface routine */
+static void
+sisusbcon_save_screen(struct vc_data *c)
+{
+       struct sisusb_usb_data *sisusb;
+       int length;
+
+       /* Save the current screen contents to vc's private
+        * buffer.
+        */
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return;
+
+       /* sisusb->lock is down */
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return;
+       }
+
+       /* Check that we don't copy too much */
+       length = min((int)c->vc_screenbuf_size,
+                       (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
+
+       /* Save the screen contents to vc's private buffer */
+       sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin,
+                                                               length);
+
+       up(&sisusb->lock);
+}
+
+/* interface routine */
+static int
+sisusbcon_set_palette(struct vc_data *c, unsigned char *table)
+{
+       struct sisusb_usb_data *sisusb;
+       int i, j;
+
+       /* Return value not used by vt */
+
+       if (!CON_IS_VISIBLE(c))
+               return -EINVAL;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return -EINVAL;
+
+       /* sisusb->lock is down */
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return -EINVAL;
+       }
+
+       for (i = j = 0; i < 16; i++) {
+               if (sisusb_setreg(sisusb, SISCOLIDX, table[i]))
+                       break;
+               if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
+                       break;
+               if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
+                       break;
+               if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
+                       break;
+       }
+
+       up(&sisusb->lock);
+
+       return 0;
+}
+
+/* interface routine */
+static int
+sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
+{
+       struct sisusb_usb_data *sisusb;
+       u8 sr1, cr17, pmreg, cr63;
+       ssize_t written;
+       int ret = 0;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return 0;
+
+       /* sisusb->lock is down */
+
+       if (mode_switch)
+               sisusb->is_gfx = blank ? 1 : 0;
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return 0;
+       }
+
+       switch (blank) {
+
+       case 1:         /* Normal blanking: Clear screen */
+       case -1:
+               sisusbcon_memsetw((u16 *)c->vc_origin,
+                               c->vc_video_erase_char,
+                               c->vc_screenbuf_size);
+               sisusb_copy_memory(sisusb,
+                               (unsigned char *)c->vc_origin,
+                               (u32)(sisusb->vrambase +
+                                       (c->vc_origin - sisusb->scrbuf)),
+                               c->vc_screenbuf_size, &written);
+               sisusb->con_blanked = 1;
+               ret = 1;
+               break;
+
+       default:        /* VESA blanking */
+               switch (blank) {
+               case 0: /* Unblank */
+                       sr1   = 0x00;
+                       cr17  = 0x80;
+                       pmreg = 0x00;
+                       cr63  = 0x00;
+                       ret = 1;
+                       sisusb->con_blanked = 0;
+                       break;
+               case VESA_VSYNC_SUSPEND + 1:
+                       sr1   = 0x20;
+                       cr17  = 0x80;
+                       pmreg = 0x80;
+                       cr63  = 0x40;
+                       break;
+               case VESA_HSYNC_SUSPEND + 1:
+                       sr1   = 0x20;
+                       cr17  = 0x80;
+                       pmreg = 0x40;
+                       cr63  = 0x40;
+                       break;
+               case VESA_POWERDOWN + 1:
+                       sr1   = 0x20;
+                       cr17  = 0x00;
+                       pmreg = 0xc0;
+                       cr63  = 0x40;
+                       break;
+               default:
+                       up(&sisusb->lock);
+                       return -EINVAL;
+               }
+
+               sisusb_setidxregandor(sisusb, SISSR, 0x01, ~0x20, sr1);
+               sisusb_setidxregandor(sisusb, SISCR, 0x17, 0x7f, cr17);
+               sisusb_setidxregandor(sisusb, SISSR, 0x1f, 0x3f, pmreg);
+               sisusb_setidxregandor(sisusb, SISCR, 0x63, 0xbf, cr63);
+
+       }
+
+       up(&sisusb->lock);
+
+       return ret;
+}
+
+/* interface routine */
+static int
+sisusbcon_scrolldelta(struct vc_data *c, int lines)
+{
+       struct sisusb_usb_data *sisusb;
+       int margin = c->vc_size_row * 4;
+       int ul, we, p, st;
+
+       /* The return value does not seem to be used */
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return 0;
+
+       /* sisusb->lock is down */
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return 0;
+       }
+
+       if (!lines)             /* Turn scrollback off */
+               c->vc_visible_origin = c->vc_origin;
+       else {
+
+               if (sisusb->con_rolled_over >
+                               (c->vc_scr_end - sisusb->scrbuf) + margin) {
+
+                       ul = c->vc_scr_end - sisusb->scrbuf;
+                       we = sisusb->con_rolled_over + c->vc_size_row;
+
+               } else {
+
+                       ul = 0;
+                       we = sisusb->scrbuf_size;
+
+               }
+
+               p = (c->vc_visible_origin - sisusb->scrbuf - ul + we) % we +
+                               lines * c->vc_size_row;
+
+               st = (c->vc_origin - sisusb->scrbuf - ul + we) % we;
+
+               if (st < 2 * margin)
+                       margin = 0;
+
+               if (p < margin)
+                       p = 0;
+
+               if (p > st - margin)
+                       p = st;
+
+               c->vc_visible_origin = sisusb->scrbuf + (p + ul) % we;
+       }
+
+       sisusbcon_set_start_address(sisusb, c);
+
+       up(&sisusb->lock);
+
+       return 1;
+}
+
+/* Interface routine */
+static void
+sisusbcon_cursor(struct vc_data *c, int mode)
+{
+       struct sisusb_usb_data *sisusb;
+       int from, to, baseline;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return;
+
+       /* sisusb->lock is down */
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return;
+       }
+
+       if (c->vc_origin != c->vc_visible_origin) {
+               c->vc_visible_origin = c->vc_origin;
+               sisusbcon_set_start_address(sisusb, c);
+       }
+
+       if (mode == CM_ERASE) {
+               sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20);
+               sisusb->sisusb_cursor_size_to = -1;
+               up(&sisusb->lock);
+               return;
+       }
+
+       sisusb_set_cursor(sisusb, (c->vc_pos - sisusb->scrbuf) / 2);
+
+       baseline = c->vc_font.height - (c->vc_font.height < 10 ? 1 : 2);
+
+       switch (c->vc_cursor_type & 0x0f) {
+               case CUR_BLOCK:         from = 1;
+                                       to   = c->vc_font.height;
+                                       break;
+               case CUR_TWO_THIRDS:    from = c->vc_font.height / 3;
+                                       to   = baseline;
+                                       break;
+               case CUR_LOWER_HALF:    from = c->vc_font.height / 2;
+                                       to   = baseline;
+                                       break;
+               case CUR_LOWER_THIRD:   from = (c->vc_font.height * 2) / 3;
+                                       to   = baseline;
+                                       break;
+               case CUR_NONE:          from = 31;
+                                       to = 30;
+                                       break;
+               default:
+               case CUR_UNDERLINE:     from = baseline - 1;
+                                       to   = baseline;
+                                       break;
+       }
+
+       if (sisusb->sisusb_cursor_size_from != from ||
+           sisusb->sisusb_cursor_size_to != to) {
+
+               sisusb_setidxreg(sisusb, SISCR, 0x0a, from);
+               sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, to);
+
+               sisusb->sisusb_cursor_size_from = from;
+               sisusb->sisusb_cursor_size_to   = to;
+       }
+
+       up(&sisusb->lock);
+}
+
+static int
+sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
+                                       int t, int b, int dir, int lines)
+{
+       int cols = sisusb->sisusb_num_columns;
+       int length = ((b - t) * cols) * 2;
+       u16 eattr = c->vc_video_erase_char;
+       ssize_t written;
+
+       /* sisusb->lock is down */
+
+       /* Scroll an area which does not match the
+        * visible screen's dimensions. This needs
+        * to be done separately, as it does not
+        * use hardware panning.
+        */
+
+       switch (dir) {
+
+               case SM_UP:
+                       sisusbcon_memmovew(SISUSB_VADDR(0, t),
+                                          SISUSB_VADDR(0, t + lines),
+                                          (b - t - lines) * cols * 2);
+                       sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr,
+                                         lines * cols * 2);
+                       break;
+
+               case SM_DOWN:
+                       sisusbcon_memmovew(SISUSB_VADDR(0, t + lines),
+                                          SISUSB_VADDR(0, t),
+                                          (b - t - lines) * cols * 2);
+                       sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr,
+                                         lines * cols * 2);
+                       break;
+       }
+
+       sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t),
+                               (u32)SISUSB_HADDR(0, t), length, &written);
+
+       up(&sisusb->lock);
+
+       return 1;
+}
+
+/* Interface routine */
+static int
+sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
+{
+       struct sisusb_usb_data *sisusb;
+       u16 eattr = c->vc_video_erase_char;
+       ssize_t written;
+       int copyall = 0;
+       unsigned long oldorigin;
+       unsigned int delta = lines * c->vc_size_row;
+       u32 originoffset;
+
+       /* Returning != 0 means we have done the scrolling successfully.
+        * Returning 0 makes vt do the scrolling on its own.
+        * Note that con_scroll is only called if the console is
+        * visible. In that case, the origin should be our buffer,
+        * not the vt's private one.
+        */
+
+       if (!lines)
+               return 1;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return 0;
+
+       /* sisusb->lock is down */
+
+       if (sisusb_is_inactive(c, sisusb)) {
+               up(&sisusb->lock);
+               return 0;
+       }
+
+       /* Special case */
+       if (t || b != c->vc_rows)
+               return sisusbcon_scroll_area(c, sisusb, t, b, dir, lines);
+
+       if (c->vc_origin != c->vc_visible_origin) {
+               c->vc_visible_origin = c->vc_origin;
+               sisusbcon_set_start_address(sisusb, c);
+       }
+
+       /* limit amount to maximum realistic size */
+       if (lines > c->vc_rows)
+               lines = c->vc_rows;
+
+       oldorigin = c->vc_origin;
+
+       switch (dir) {
+
+       case SM_UP:
+
+               if (c->vc_scr_end + delta >=
+                               sisusb->scrbuf + sisusb->scrbuf_size) {
+                       sisusbcon_memcpyw((u16 *)sisusb->scrbuf,
+                                         (u16 *)(oldorigin + delta),
+                                         c->vc_screenbuf_size - delta);
+                       c->vc_origin = sisusb->scrbuf;
+                       sisusb->con_rolled_over = oldorigin - sisusb->scrbuf;
+                       copyall = 1;
+               } else
+                       c->vc_origin += delta;
+
+               sisusbcon_memsetw(
+                       (u16 *)(c->vc_origin + c->vc_screenbuf_size - delta),
+                                       eattr, delta);
+
+               break;
+
+       case SM_DOWN:
+
+               if (oldorigin - delta < sisusb->scrbuf) {
+                       sisusbcon_memmovew((u16 *)(sisusb->scrbuf +
+                                                       sisusb->scrbuf_size -
+                                                       c->vc_screenbuf_size +
+                                                       delta),
+                                          (u16 *)oldorigin,
+                                          c->vc_screenbuf_size - delta);
+                       c->vc_origin = sisusb->scrbuf +
+                                       sisusb->scrbuf_size -
+                                       c->vc_screenbuf_size;
+                       sisusb->con_rolled_over = 0;
+                       copyall = 1;
+               } else
+                       c->vc_origin -= delta;
+
+               c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
+
+               scr_memsetw((u16 *)(c->vc_origin), eattr, delta);
+
+               break;
+       }
+
+       originoffset = (u32)(c->vc_origin - sisusb->scrbuf);
+
+       if (copyall)
+               sisusb_copy_memory(sisusb,
+                       (char *)c->vc_origin,
+                       (u32)(sisusb->vrambase + originoffset),
+                       c->vc_screenbuf_size, &written);
+       else if (dir == SM_UP)
+               sisusb_copy_memory(sisusb,
+                       (char *)c->vc_origin + c->vc_screenbuf_size - delta,
+                       (u32)sisusb->vrambase + originoffset +
+                                       c->vc_screenbuf_size - delta,
+                       delta, &written);
+       else
+               sisusb_copy_memory(sisusb,
+                       (char *)c->vc_origin,
+                       (u32)(sisusb->vrambase + originoffset),
+                       delta, &written);
+
+       c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
+       c->vc_visible_origin = c->vc_origin;
+
+       sisusbcon_set_start_address(sisusb, c);
+
+       c->vc_pos = c->vc_pos - oldorigin + c->vc_origin;
+
+       up(&sisusb->lock);
+
+       return 1;
+}
+
+/* Interface routine */
+static int
+sisusbcon_set_origin(struct vc_data *c)
+{
+       struct sisusb_usb_data *sisusb;
+
+       /* Returning != 0 means we were successful.
+        * Returning 0 will vt make to use its own
+        *      screenbuffer as the origin.
+        */
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return 0;
+
+       /* sisusb->lock is down */
+
+       if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) {
+               up(&sisusb->lock);
+               return 0;
+       }
+
+       c->vc_origin = c->vc_visible_origin = sisusb->scrbuf;
+
+       sisusbcon_set_start_address(sisusb, c);
+
+       sisusb->con_rolled_over = 0;
+
+       up(&sisusb->lock);
+
+       return 1;
+}
+
+/* Interface routine */
+static int
+sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows)
+{
+       struct sisusb_usb_data *sisusb;
+       int fh;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return -ENODEV;
+
+       fh = sisusb->current_font_height;
+
+       up(&sisusb->lock);
+
+       /* We are quite unflexible as regards resizing. The vt code
+        * handles sizes where the line length isn't equal the pitch
+        * quite badly. As regards the rows, our panning tricks only
+        * work well if the number of rows equals the visible number
+        * of rows.
+        */
+
+       if (newcols != 80 || c->vc_scan_lines / fh != newrows)
+               return -EINVAL;
+
+       return 0;
+}
+
+int
+sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
+                       u8 *arg, int cmapsz, int ch512, int dorecalc,
+                       struct vc_data *c, int fh, int uplock)
+{
+       int font_select = 0x00, i, err = 0;
+       u32 offset = 0;
+       u8 dummy;
+
+       /* sisusb->lock is down */
+
+       /*
+        * The default font is kept in slot 0.
+        * A user font is loaded in slot 2 (256 ch)
+        * or 2+3 (512 ch).
+        */
+
+       if ((slot != 0 && slot != 2) || !fh) {
+               if (uplock)
+                       up(&sisusb->lock);
+               return -EINVAL;
+       }
+
+       if (set)
+               sisusb->font_slot = slot;
+
+       /* Default font is always 256 */
+       if (slot == 0)
+               ch512 = 0;
+       else
+               offset = 4 * cmapsz;
+
+       font_select = (slot == 0) ? 0x00 : (ch512 ? 0x0e : 0x0a);
+
+       err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */
+       err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x04); /* Write to plane 2 */
+       err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x07); /* Memory mode a0-bf */
+       err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset */
+
+       if (err)
+               goto font_op_error;
+
+       err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x03); /* Select plane read 2 */
+       err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x00); /* Disable odd/even */
+       err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x00); /* Address range a0-bf */
+
+       if (err)
+               goto font_op_error;
+
+       if (arg) {
+               if (set)
+                       for (i = 0; i < cmapsz; i++) {
+                               err |= sisusb_writeb(sisusb,
+                                       sisusb->vrambase + offset + i,
+                                       arg[i]);
+                               if (err)
+                                       break;
+                       }
+               else
+                       for (i = 0; i < cmapsz; i++) {
+                               err |= sisusb_readb(sisusb,
+                                       sisusb->vrambase + offset + i,
+                                       &arg[i]);
+                               if (err)
+                                       break;
+                       }
+
+               /*
+                * In 512-character mode, the character map is not contiguous if
+                * we want to remain EGA compatible -- which we do
+                */
+
+               if (ch512) {
+                       if (set)
+                               for (i = 0; i < cmapsz; i++) {
+                                       err |= sisusb_writeb(sisusb,
+                                               sisusb->vrambase + offset +
+                                                       (2 * cmapsz) + i,
+                                               arg[cmapsz + i]);
+                                       if (err)
+                                               break;
+                               }
+                       else
+                               for (i = 0; i < cmapsz; i++) {
+                                       err |= sisusb_readb(sisusb,
+                                               sisusb->vrambase + offset +
+                                                       (2 * cmapsz) + i,
+                                               &arg[cmapsz + i]);
+                                       if (err)
+                                               break;
+                               }
+               }
+       }
+
+       if (err)
+               goto font_op_error;
+
+       err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */
+       err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x03); /* Write to planes 0+1 */
+       err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x03); /* Memory mode a0-bf */
+       if (set)
+               sisusb_setidxreg(sisusb, SISSR, 0x03, font_select);
+       err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset end */
+
+       if (err)
+               goto font_op_error;
+
+       err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x00); /* Select plane read 0 */
+       err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x10); /* Enable odd/even */
+       err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x06); /* Address range b8-bf */
+
+       if (err)
+               goto font_op_error;
+
+       if ((set) && (ch512 != sisusb->current_font_512)) {
+
+               /* Font is shared among all our consoles.
+                * And so is the hi_font_mask.
+                */
+               for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                       struct vc_data *c = vc_cons[i].d;
+                       if (c && c->vc_sw == &sisusb_con)
+                               c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
+               }
+
+               sisusb->current_font_512 = ch512;
+
+               /* color plane enable register:
+                       256-char: enable intensity bit
+                       512-char: disable intensity bit */
+               sisusb_getreg(sisusb, SISINPSTAT, &dummy);
+               sisusb_setreg(sisusb, SISAR, 0x12);
+               sisusb_setreg(sisusb, SISAR, ch512 ? 0x07 : 0x0f);
+
+               sisusb_getreg(sisusb, SISINPSTAT, &dummy);
+               sisusb_setreg(sisusb, SISAR, 0x20);
+               sisusb_getreg(sisusb, SISINPSTAT, &dummy);
+       }
+
+       if (dorecalc) {
+
+               /*
+                * Adjust the screen to fit a font of a certain height
+                */
+
+               unsigned char ovr, vde, fsr;
+               int rows = 0, maxscan = 0;
+
+               if (c) {
+
+                       /* Number of video rows */
+                       rows = c->vc_scan_lines / fh;
+                       /* Scan lines to actually display-1 */
+                       maxscan = rows * fh - 1;
+
+                       /*printk(KERN_DEBUG "sisusb recalc rows %d maxscan %d fh %d sl %d\n",
+                               rows, maxscan, fh, c->vc_scan_lines);*/
+
+                       sisusb_getidxreg(sisusb, SISCR, 0x07, &ovr);
+                       vde = maxscan & 0xff;
+                       ovr = (ovr & 0xbd) |
+                             ((maxscan & 0x100) >> 7) |
+                             ((maxscan & 0x200) >> 3);
+                       sisusb_setidxreg(sisusb, SISCR, 0x07, ovr);
+                       sisusb_setidxreg(sisusb, SISCR, 0x12, vde);
+
+               }
+
+               sisusb_getidxreg(sisusb, SISCR, 0x09, &fsr);
+               fsr = (fsr & 0xe0) | (fh - 1);
+               sisusb_setidxreg(sisusb, SISCR, 0x09, fsr);
+               sisusb->current_font_height = fh;
+
+               sisusb->sisusb_cursor_size_from = -1;
+               sisusb->sisusb_cursor_size_to   = -1;
+
+       }
+
+       if (uplock)
+               up(&sisusb->lock);
+
+       if (dorecalc && c) {
+               int i, rows = c->vc_scan_lines / fh;
+
+               /* Now adjust our consoles' size */
+
+               for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                       struct vc_data *vc = vc_cons[i].d;
+
+                       if (vc && vc->vc_sw == &sisusb_con) {
+                               if (CON_IS_VISIBLE(vc)) {
+                                       vc->vc_sw->con_cursor(vc, CM_DRAW);
+                               }
+                               vc->vc_font.height = fh;
+                               vc_resize(vc, 0, rows);
+                       }
+               }
+       }
+
+       return 0;
+
+font_op_error:
+       if (uplock)
+               up(&sisusb->lock);
+
+       return -EIO;
+}
+
+/* Interface routine */
+static int
+sisusbcon_font_set(struct vc_data *c, struct console_font *font,
+                                                       unsigned flags)
+{
+       struct sisusb_usb_data *sisusb;
+       unsigned charcount = font->charcount;
+
+       if (font->width != 8 || (charcount != 256 && charcount != 512))
+               return -EINVAL;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return -ENODEV;
+
+       /* sisusb->lock is down */
+
+       /* Save the user-provided font into a buffer. This
+        * is used for restoring text mode after quitting
+        * from X and for the con_getfont routine.
+        */
+       if (sisusb->font_backup) {
+               if (sisusb->font_backup_size < charcount) {
+                       vfree(sisusb->font_backup);
+                       sisusb->font_backup = NULL;
+               }
+       }
+
+       if (!sisusb->font_backup)
+               sisusb->font_backup = vmalloc(charcount * 32);
+
+       if (sisusb->font_backup) {
+               memcpy(sisusb->font_backup, font->data, charcount * 32);
+               sisusb->font_backup_size = charcount;
+               sisusb->font_backup_height = font->height;
+               sisusb->font_backup_512 = (charcount == 512) ? 1 : 0;
+       }
+
+       /* do_font_op ups sisusb->lock */
+
+       return sisusbcon_do_font_op(sisusb, 1, 2, font->data,
+                       8192, (charcount == 512),
+                       (!(flags & KD_FONT_FLAG_DONT_RECALC)) ? 1 : 0,
+                       c, font->height, 1);
+}
+
+/* Interface routine */
+static int
+sisusbcon_font_get(struct vc_data *c, struct console_font *font)
+{
+       struct sisusb_usb_data *sisusb;
+
+       if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
+               return -ENODEV;
+
+       /* sisusb->lock is down */
+
+       font->width = 8;
+       font->height = c->vc_font.height;
+       font->charcount = 256;
+
+       if (!font->data) {
+               up(&sisusb->lock);
+               return 0;
+       }
+
+       if (!sisusb->font_backup) {
+               up(&sisusb->lock);
+               return -ENODEV;
+       }
+
+       /* Copy 256 chars only, like vgacon */
+       memcpy(font->data, sisusb->font_backup, 256 * 32);
+
+       up(&sisusb->lock);
+
+       return 0;
+}
+
+/*
+ *  The console `switch' structure for the sisusb console
+ */
+
+static const struct consw sisusb_con = {
+       .owner =                THIS_MODULE,
+       .con_startup =          sisusbcon_startup,
+       .con_init =             sisusbcon_init,
+       .con_deinit =           sisusbcon_deinit,
+       .con_clear =            sisusbcon_clear,
+       .con_putc =             sisusbcon_putc,
+       .con_putcs =            sisusbcon_putcs,
+       .con_cursor =           sisusbcon_cursor,
+       .con_scroll =           sisusbcon_scroll,
+       .con_bmove =            sisusbcon_bmove,
+       .con_switch =           sisusbcon_switch,
+       .con_blank =            sisusbcon_blank,
+       .con_font_set =         sisusbcon_font_set,
+       .con_font_get =         sisusbcon_font_get,
+       .con_set_palette =      sisusbcon_set_palette,
+       .con_scrolldelta =      sisusbcon_scrolldelta,
+       .con_build_attr =       sisusbcon_build_attr,
+       .con_invert_region =    sisusbcon_invert_region,
+       .con_set_origin =       sisusbcon_set_origin,
+       .con_save_screen =      sisusbcon_save_screen,
+       .con_resize =           sisusbcon_resize,
+};
+
+/* Our very own dummy console driver */
+
+static const char *sisusbdummycon_startup(void)
+{
+    return "SISUSBVGADUMMY";
+}
+
+static void sisusbdummycon_init(struct vc_data *vc, int init)
+{
+    vc->vc_can_do_color = 1;
+    if (init) {
+       vc->vc_cols = 80;
+       vc->vc_rows = 25;
+    } else
+       vc_resize(vc, 80, 25);
+}
+
+static int sisusbdummycon_dummy(void)
+{
+    return 0;
+}
+
+#define SISUSBCONDUMMY (void *)sisusbdummycon_dummy
+
+const struct consw sisusb_dummy_con = {
+       .owner =                THIS_MODULE,
+       .con_startup =          sisusbdummycon_startup,
+       .con_init =             sisusbdummycon_init,
+       .con_deinit =           SISUSBCONDUMMY,
+       .con_clear =            SISUSBCONDUMMY,
+       .con_putc =             SISUSBCONDUMMY,
+       .con_putcs =            SISUSBCONDUMMY,
+       .con_cursor =           SISUSBCONDUMMY,
+       .con_scroll =           SISUSBCONDUMMY,
+       .con_bmove =            SISUSBCONDUMMY,
+       .con_switch =           SISUSBCONDUMMY,
+       .con_blank =            SISUSBCONDUMMY,
+       .con_font_set =         SISUSBCONDUMMY,
+       .con_font_get =         SISUSBCONDUMMY,
+       .con_font_default =     SISUSBCONDUMMY,
+       .con_font_copy =        SISUSBCONDUMMY,
+       .con_set_palette =      SISUSBCONDUMMY,
+       .con_scrolldelta =      SISUSBCONDUMMY,
+};
+
+int
+sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
+{
+       int i, ret, minor = sisusb->minor;
+
+       down(&disconnect_sem);
+
+       down(&sisusb->lock);
+
+       /* Erm.. that should not happen */
+       if (sisusb->haveconsole || !sisusb->SiS_Pr) {
+               up(&sisusb->lock);
+               up(&disconnect_sem);
+               return 1;
+       }
+
+       sisusb->con_first = first;
+       sisusb->con_last  = last;
+
+       if (first > last ||
+           first > MAX_NR_CONSOLES ||
+           last > MAX_NR_CONSOLES) {
+               up(&sisusb->lock);
+               up(&disconnect_sem);
+               return 1;
+       }
+
+       /* If gfxcore not initialized or no consoles given, quit graciously */
+       if (!sisusb->gfxinit || first < 1 || last < 1) {
+               up(&sisusb->lock);
+               up(&disconnect_sem);
+               return 0;
+       }
+
+       sisusb->sisusb_cursor_loc       = -1;
+       sisusb->sisusb_cursor_size_from = -1;
+       sisusb->sisusb_cursor_size_to   = -1;
+
+       /* Set up text mode (and upload  default font) */
+       if (sisusb_reset_text_mode(sisusb, 1)) {
+               up(&sisusb->lock);
+               up(&disconnect_sem);
+               printk(KERN_ERR
+                       "sisusbvga[%d]: Failed to set up text mode\n",
+                       minor);
+               return 1;
+       }
+
+       /* Initialize some gfx registers */
+       sisusb_initialize(sisusb);
+
+       for (i = first - 1; i <= last - 1; i++) {
+               /* Save sisusb for our interface routines */
+               mysisusbs[i] = sisusb;
+       }
+
+       /* Initial console setup */
+       sisusb->sisusb_num_columns = 80;
+
+       /* Use a 32K buffer (matches b8000-bffff area) */
+       sisusb->scrbuf_size = 32 * 1024;
+
+       /* Allocate screen buffer */
+       if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
+               up(&sisusb->lock);
+               up(&disconnect_sem);
+               printk(KERN_ERR
+                       "sisusbvga[%d]: Failed to allocate screen buffer\n",
+                       minor);
+               return 1;
+       }
+
+       up(&sisusb->lock);
+       up(&disconnect_sem);
+
+       /* Now grab the desired console(s) */
+       ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
+
+       if (!ret)
+               sisusb->haveconsole = 1;
+       else {
+               for (i = first - 1; i <= last - 1; i++)
+                       mysisusbs[i] = NULL;
+       }
+
+       return ret;
+}
+
+void
+sisusb_console_exit(struct sisusb_usb_data *sisusb)
+{
+       int i;
+
+       /* This is called if the device is disconnected
+        * and while disconnect and lock semaphores
+        * are up. This should be save because we
+        * can't lose our sisusb any other way but by
+        * disconnection (and hence, the disconnect
+        * sema is for protecting all other access
+        * functions from disconnection, not the
+        * other way round).
+        */
+
+       /* Now what do we do in case of disconnection:
+        * One alternative would be to simply call
+        * give_up_console(). Nah, not a good idea.
+        * give_up_console() is obviously buggy as it
+        * only discards the consw pointer from the
+        * driver_map, but doesn't adapt vc->vc_sw
+        * of the affected consoles. Hence, the next
+        * call to any of the console functions will
+        * eventually take a trip to oops county.
+        * Also, give_up_console for some reason
+        * doesn't decrement our module refcount.
+        * Instead, we switch our consoles to a private
+        * dummy console. This, of course, keeps our
+        * refcount up as well, but it works perfectly.
+        */
+
+       if (sisusb->haveconsole) {
+               for (i = 0; i < MAX_NR_CONSOLES; i++)
+                       if (sisusb->havethisconsole[i])
+                               take_over_console(&sisusb_dummy_con, i, i, 0);
+                               /* At this point, con_deinit for all our
+                                * consoles is executed by take_over_console().
+                                */
+               sisusb->haveconsole = 0;
+       }
+
+       vfree((void *)sisusb->scrbuf);
+       sisusb->scrbuf = 0;
+
+       vfree(sisusb->font_backup);
+       sisusb->font_backup = NULL;
+}
+
+void __init sisusb_init_concode(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               mysisusbs[i] = NULL;
+}
+
+#endif /* INCL_CON */
+
+
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
new file mode 100644 (file)
index 0000000..f28bc24
--- /dev/null
@@ -0,0 +1,1047 @@
+/*
+ * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
+ *
+ * Display mode initializing code
+ *
+ * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, this code is licensed under the
+ * terms of the GPL v2.
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+
+#include "sisusb.h"
+
+#ifdef INCL_SISUSB_CON
+
+#include "sisusb_init.h"
+
+/*********************************************/
+/*         POINTER INITIALIZATION            */
+/*********************************************/
+
+static void
+SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+{
+       SiS_Pr->SiS_ModeResInfo   = SiSUSB_ModeResInfo;
+       SiS_Pr->SiS_StandTable    = SiSUSB_StandTable;
+
+       SiS_Pr->SiS_SModeIDTable  = SiSUSB_SModeIDTable;
+       SiS_Pr->SiS_EModeIDTable  = SiSUSB_EModeIDTable;
+       SiS_Pr->SiS_RefIndex      = SiSUSB_RefIndex;
+       SiS_Pr->SiS_CRT1Table     = SiSUSB_CRT1Table;
+
+       SiS_Pr->SiS_VCLKData      = SiSUSB_VCLKData;
+}
+
+/*********************************************/
+/*            HELPER: Get ModeID             */
+/*********************************************/
+
+unsigned short
+SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
+{
+       unsigned short ModeIndex = 0;
+
+       switch (HDisplay)
+       {
+               case 320:
+                       if (VDisplay == 200)
+                               ModeIndex = ModeIndex_320x200[Depth];
+                       else if (VDisplay == 240)
+                               ModeIndex = ModeIndex_320x240[Depth];
+                       break;
+               case 400:
+                       if (VDisplay == 300)
+                               ModeIndex = ModeIndex_400x300[Depth];
+                       break;
+               case 512:
+                       if (VDisplay == 384)
+                               ModeIndex = ModeIndex_512x384[Depth];
+                       break;
+               case 640:
+                       if (VDisplay == 480)
+                               ModeIndex = ModeIndex_640x480[Depth];
+                       else if (VDisplay == 400)
+                               ModeIndex = ModeIndex_640x400[Depth];
+                       break;
+               case 720:
+                       if (VDisplay == 480)
+                               ModeIndex = ModeIndex_720x480[Depth];
+                       else if (VDisplay == 576)
+                               ModeIndex = ModeIndex_720x576[Depth];
+                       break;
+               case 768:
+                       if (VDisplay == 576)
+                               ModeIndex = ModeIndex_768x576[Depth];
+                       break;
+               case 800:
+                       if (VDisplay == 600)
+                               ModeIndex = ModeIndex_800x600[Depth];
+                       else if (VDisplay == 480)
+                               ModeIndex = ModeIndex_800x480[Depth];
+                       break;
+               case 848:
+                       if (VDisplay == 480)
+                               ModeIndex = ModeIndex_848x480[Depth];
+                       break;
+               case 856:
+                       if (VDisplay == 480)
+                               ModeIndex = ModeIndex_856x480[Depth];
+                       break;
+               case 960:
+                       if (VDisplay == 540)
+                               ModeIndex = ModeIndex_960x540[Depth];
+                       else if (VDisplay == 600)
+                               ModeIndex = ModeIndex_960x600[Depth];
+                       break;
+               case 1024:
+                       if (VDisplay == 576)
+                               ModeIndex = ModeIndex_1024x576[Depth];
+                       else if (VDisplay == 768)
+                               ModeIndex = ModeIndex_1024x768[Depth];
+                       break;
+               case 1152:
+                       if (VDisplay == 864)
+                               ModeIndex = ModeIndex_1152x864[Depth];
+                       break;
+               case 1280:
+                       switch (VDisplay) {
+                               case 720:
+                                       ModeIndex = ModeIndex_1280x720[Depth];
+                                       break;
+                               case 768:
+                                       ModeIndex = ModeIndex_1280x768[Depth];
+                                       break;
+                               case 1024:
+                                       ModeIndex = ModeIndex_1280x1024[Depth];
+                                       break;
+                       }
+       }
+
+       return ModeIndex;
+}
+
+/*********************************************/
+/*          HELPER: SetReg, GetReg           */
+/*********************************************/
+
+static void
+SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
+                       unsigned short index, unsigned short data)
+{
+       sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
+}
+
+static void
+SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
+                                               unsigned short data)
+{
+       sisusb_setreg(SiS_Pr->sisusb, port, data);
+}
+
+static unsigned char
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
+                                               unsigned short index)
+{
+       u8 data;
+
+       sisusb_getidxreg(SiS_Pr->sisusb, port, index, &data);
+
+       return data;
+}
+
+static unsigned char
+SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
+{
+       u8 data;
+
+       sisusb_getreg(SiS_Pr->sisusb, port, &data);
+
+       return data;
+}
+
+static void
+SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
+                       unsigned short index, unsigned short DataAND,
+                                               unsigned short DataOR)
+{
+       sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
+}
+
+static void
+SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
+                       unsigned short index, unsigned short DataAND)
+{
+       sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
+}
+
+static void
+SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
+                       unsigned short index, unsigned short DataOR)
+{
+       sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
+}
+
+/*********************************************/
+/*      HELPER: DisplayOn, DisplayOff        */
+/*********************************************/
+
+static void
+SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+{
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
+}
+
+/*********************************************/
+/*        HELPER: Init Port Addresses        */
+/*********************************************/
+
+void
+SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+{
+       SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
+       SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
+       SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
+       SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
+       SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
+       SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
+       SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
+       SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
+       SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
+       SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
+       SiS_Pr->SiS_P3cb = BaseAddr + 0x1b;
+       SiS_Pr->SiS_P3cc = BaseAddr + 0x1c;
+       SiS_Pr->SiS_P3cd = BaseAddr + 0x1d;
+       SiS_Pr->SiS_P3da = BaseAddr + 0x2a;
+       SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;
+}
+
+/*********************************************/
+/*             HELPER: GetSysFlags           */
+/*********************************************/
+
+static void
+SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+{
+       SiS_Pr->SiS_MyCR63 = 0x63;
+}
+
+/*********************************************/
+/*         HELPER: Init PCI & Engines        */
+/*********************************************/
+
+static void
+SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+{
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
+       /*  - Enable 2D (0x40)
+        *  - Enable 3D (0x02)
+        *  - Enable 3D vertex command fetch (0x10)
+        *  - Enable 3D command parser (0x08)
+        *  - Enable 3D G/L transformation engine (0x80)
+        */
+       SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1E, 0xDA);
+}
+
+/*********************************************/
+/*        HELPER: SET SEGMENT REGISTERS      */
+/*********************************************/
+
+static void
+SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+{
+       unsigned short temp;
+
+       value &= 0x00ff;
+       temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0xf0;
+       temp |= (value >> 4);
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
+       temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0xf0;
+       temp |= (value & 0x0f);
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
+}
+
+static void
+SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+{
+       unsigned short temp;
+
+       value &= 0x00ff;
+       temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0x0f;
+       temp |= (value & 0xf0);
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
+       temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0x0f;
+       temp |= (value << 4);
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
+}
+
+static void
+SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+{
+       SiS_SetSegRegLower(SiS_Pr, value);
+       SiS_SetSegRegUpper(SiS_Pr, value);
+}
+
+static void
+SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+{
+       SiS_SetSegmentReg(SiS_Pr, 0);
+}
+
+static void
+SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
+{
+       unsigned short temp = value >> 8;
+
+       temp &= 0x07;
+       temp |= (temp << 4);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1d, temp);
+       SiS_SetSegmentReg(SiS_Pr, value);
+}
+
+static void
+SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+{
+       SiS_SetSegmentRegOver(SiS_Pr, 0);
+}
+
+static void
+SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+{
+       SiS_ResetSegmentReg(SiS_Pr);
+       SiS_ResetSegmentRegOver(SiS_Pr);
+}
+
+/*********************************************/
+/*           HELPER: SearchModeID            */
+/*********************************************/
+
+static int
+SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
+                                               unsigned short *ModeIdIndex)
+{
+       if ((*ModeNo) <= 0x13) {
+
+               if ((*ModeNo) != 0x03)
+                       return 0;
+
+               (*ModeIdIndex) = 0;
+
+       } else {
+
+               for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+
+                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+                               break;
+
+                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+                               return 0;
+               }
+
+       }
+
+       return 1;
+}
+
+/*********************************************/
+/*            HELPER: ENABLE CRT1            */
+/*********************************************/
+
+static void
+SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+{
+       /* Enable CRT1 gating */
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
+}
+
+/*********************************************/
+/*           HELPER: GetColorDepth           */
+/*********************************************/
+
+static unsigned short
+SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+               unsigned short ModeIdIndex)
+{
+       static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+       unsigned short modeflag;
+       short index;
+
+       if (ModeNo <= 0x13) {
+               modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+       } else {
+               modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+       }
+
+       index = (modeflag & ModeTypeMask) - ModeEGA;
+       if (index < 0) index = 0;
+       return ColorDepth[index];
+}
+
+/*********************************************/
+/*             HELPER: GetOffset             */
+/*********************************************/
+
+static unsigned short
+SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+               unsigned short ModeIdIndex, unsigned short rrti)
+{
+       unsigned short xres, temp, colordepth, infoflag;
+
+       infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+       xres = SiS_Pr->SiS_RefIndex[rrti].XRes;
+
+       colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex);
+
+       temp = xres / 16;
+
+       if (infoflag & InterlaceMode)
+               temp <<= 1;
+
+       temp *= colordepth;
+
+       if (xres % 16)
+               temp += (colordepth >> 1);
+
+       return temp;
+}
+
+/*********************************************/
+/*                   SEQ                     */
+/*********************************************/
+
+static void
+SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+       unsigned char SRdata;
+       int i;
+
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x00, 0x03);
+
+       SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
+
+       for(i = 2; i <= 4; i++) {
+               SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
+       }
+}
+
+/*********************************************/
+/*                  MISC                     */
+/*********************************************/
+
+static void
+SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+       unsigned char Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
+
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, Miscdata);
+}
+
+/*********************************************/
+/*                  CRTC                     */
+/*********************************************/
+
+static void
+SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+       unsigned char CRTCdata;
+       unsigned short i;
+
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
+
+       for(i = 0; i <= 0x18; i++) {
+               CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
+       }
+}
+
+/*********************************************/
+/*                   ATT                     */
+/*********************************************/
+
+static void
+SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+       unsigned char ARdata;
+       unsigned short i;
+
+       for(i = 0; i <= 0x13; i++) {
+               ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
+               SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
+               SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
+               SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, ARdata);
+       }
+       SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x14);
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x00);
+
+       SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x20);
+       SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
+}
+
+/*********************************************/
+/*                   GRC                     */
+/*********************************************/
+
+static void
+SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
+{
+       unsigned char GRdata;
+       unsigned short i;
+
+       for(i = 0; i <= 0x08; i++) {
+               GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
+       }
+
+       if (SiS_Pr->SiS_ModeType > ModeVGA) {
+               /* 256 color disable */
+               SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3ce, 0x05, 0xBF);
+       }
+}
+
+/*********************************************/
+/*          CLEAR EXTENDED REGISTERS         */
+/*********************************************/
+
+static void
+SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+{
+       int i;
+
+       for(i = 0x0A; i <= 0x0E; i++) {
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
+       }
+
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x37, 0xFE);
+}
+
+/*********************************************/
+/*              Get rate index               */
+/*********************************************/
+
+static unsigned short
+SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+                                       unsigned short ModeIdIndex)
+{
+       unsigned short rrti, i, index, temp;
+
+       if (ModeNo <= 0x13)
+               return 0xFFFF;
+
+       index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+       if (index > 0) index--;
+
+       rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+       ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
+
+       i = 0;
+       do {
+               if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
+                       break;
+
+               temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+               if (temp < SiS_Pr->SiS_ModeType)
+                       break;
+
+               i++;
+               index--;
+       } while(index != 0xFFFF);
+
+       i--;
+
+       return (rrti + i);
+}
+
+/*********************************************/
+/*                  SYNC                     */
+/*********************************************/
+
+static void
+SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+{
+       unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
+       sync &= 0xC0;
+       sync |= 0x2f;
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, sync);
+}
+
+/*********************************************/
+/*                  CRTC/2                   */
+/*********************************************/
+
+static void
+SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+                       unsigned short ModeIdIndex, unsigned short rrti)
+{
+       unsigned char  index;
+       unsigned short temp, i, j, modeflag;
+
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+
+       modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+
+       index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
+
+       for(i = 0,j = 0; i <= 7; i++, j++) {
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
+                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+       }
+       for(j = 0x10; i <= 10; i++, j++) {
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
+                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+       }
+       for(j = 0x15; i <= 12; i++, j++) {
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
+                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+       }
+       for(j = 0x0A; i <= 15; i++, j++) {
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
+                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+       }
+
+       temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
+       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+
+       temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
+       if (modeflag & DoubleScanMode)  temp |= 0x80;
+       SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
+
+       if (SiS_Pr->SiS_ModeType > ModeVGA)
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x14, 0x4F);
+}
+
+/*********************************************/
+/*               OFFSET & PITCH              */
+/*********************************************/
+/*  (partly overruled by SetPitch() in XF86) */
+/*********************************************/
+
+static void
+SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+                       unsigned short ModeIdIndex, unsigned short rrti)
+{
+       unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
+       unsigned short infoflag =  SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+       unsigned short temp;
+
+       temp = (du >> 8) & 0x0f;
+       SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, 0xF0, temp);
+
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
+
+       if (infoflag & InterlaceMode) du >>= 1;
+
+       du <<= 5;
+       temp = (du >> 8) & 0xff;
+       if (du & 0xff) temp++;
+       temp++;
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
+}
+
+/*********************************************/
+/*                  VCLK                     */
+/*********************************************/
+
+static void
+SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+                                               unsigned short rrti)
+{
+       unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
+       unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
+       unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
+
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+
+       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
+       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
+       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+}
+
+/*********************************************/
+/*                  FIFO                     */
+/*********************************************/
+
+static void
+SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+                                                       unsigned short mi)
+{
+       unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
+
+       /* disable auto-threshold */
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0xFE);
+
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0xAE);
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x09, 0xF0);
+
+       if (ModeNo <= 0x13)
+               return;
+
+       if ((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0x34);
+               SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0x01);
+       }
+}
+
+/*********************************************/
+/*              MODE REGISTERS               */
+/*********************************************/
+
+static void
+SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+                                                       unsigned short rrti)
+{
+       unsigned short data = 0, VCLK = 0, index = 0;
+
+       if (ModeNo > 0x13) {
+               index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
+               VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
+       }
+
+       if (VCLK >= 166) data |= 0x0c;
+       SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
+
+       if (VCLK >= 166)
+               SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1f, 0xe7);
+
+       /* DAC speed */
+       data = 0x03;
+       if (VCLK >= 260)
+               data = 0x00;
+       else if (VCLK >= 160)
+               data = 0x01;
+       else if (VCLK >= 135)
+               data = 0x02;
+
+       SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x07, 0xF8, data);
+}
+
+static void
+SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+                       unsigned short ModeIdIndex, unsigned short rrti)
+{
+       unsigned short data, infoflag = 0, modeflag;
+
+       if (ModeNo <= 0x13)
+               modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+       else {
+               modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+               infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+       }
+
+       /* Disable DPMS */
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1F, 0x3F);
+
+       data = 0;
+       if (ModeNo > 0x13) {
+               if (SiS_Pr->SiS_ModeType > ModeEGA) {
+                       data |= 0x02;
+                       data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
+               }
+               if (infoflag & InterlaceMode) data |= 0x20;
+       }
+       SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
+
+       data = 0;
+       if (infoflag & InterlaceMode) {
+               /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
+               unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+                       ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
+               unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+                       ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+               data = hrs - (hto >> 1) + 3;
+       }
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
+       SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x1a, 0xFC, (data >> 8));
+
+       if (modeflag & HalfDCLK)
+               SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0x08);
+
+       data = 0;
+       if (modeflag & LineCompareOff)
+               data = 0x08;
+       SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0xB7, data);
+
+       if ((SiS_Pr->SiS_ModeType == ModeEGA) && (ModeNo > 0x13))
+               SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0x40);
+
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xfb);
+
+       data = 0x60;
+       if (SiS_Pr->SiS_ModeType != ModeText) {
+               data ^= 0x60;
+               if (SiS_Pr->SiS_ModeType != ModeEGA)
+                       data ^= 0xA0;
+       }
+       SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x21, 0x1F, data);
+
+       SiS_SetVCLKState(SiS_Pr, ModeNo, rrti);
+
+       if (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x31) & 0x40)
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x2c);
+       else
+               SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x6c);
+}
+
+/*********************************************/
+/*                 LOAD DAC                  */
+/*********************************************/
+
+static void
+SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
+               unsigned short shiftflag, unsigned short dl, unsigned short ah,
+               unsigned short al, unsigned short dh)
+{
+       unsigned short d1, d2, d3;
+
+       switch (dl) {
+               case  0:
+                       d1 = dh; d2 = ah; d3 = al;
+                       break;
+               case  1:
+                       d1 = ah; d2 = al; d3 = dh;
+                       break;
+               default:
+                       d1 = al; d2 = dh; d3 = ah;
+       }
+       SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
+       SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
+       SiS_SetRegByte(SiS_Pr, DACData, (d3 << shiftflag));
+}
+
+static void
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+{
+       unsigned short data, data2, time, i, j, k, m, n, o;
+       unsigned short si, di, bx, sf;
+       unsigned long DACAddr, DACData;
+       const unsigned char *table = NULL;
+
+       if (ModeNo < 0x13)
+               data = SiS_Pr->SiS_SModeIDTable[mi].St_ModeFlag;
+       else
+               data = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
+
+       data &= DACInfoFlag;
+
+       j = time = 64;
+       if (data == 0x00)
+               table = SiS_MDA_DAC;
+       else if (data == 0x08)
+               table = SiS_CGA_DAC;
+       else if (data == 0x10)
+               table = SiS_EGA_DAC;
+       else {
+               j = 16;
+               time = 256;
+               table = SiS_VGA_DAC;
+       }
+
+       DACAddr = SiS_Pr->SiS_P3c8;
+       DACData = SiS_Pr->SiS_P3c9;
+       sf = 0;
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
+
+       SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
+
+       for(i = 0; i < j; i++) {
+               data = table[i];
+               for(k = 0; k < 3; k++) {
+                       data2 = 0;
+                       if (data & 0x01) data2 += 0x2A;
+                       if (data & 0x02) data2 += 0x15;
+                       SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
+                       data >>= 2;
+               }
+       }
+
+       if (time == 256) {
+               for(i = 16; i < 32; i++) {
+                       data = table[i] << sf;
+                       for(k = 0; k < 3; k++)
+                               SiS_SetRegByte(SiS_Pr, DACData, data);
+               }
+               si = 32;
+               for(m = 0; m < 9; m++) {
+                       di = si;
+                       bx = si + 4;
+                       for(n = 0; n < 3; n++) {
+                               for(o = 0; o < 5; o++) {
+                                       SiS_WriteDAC(SiS_Pr, DACData, sf, n,
+                                               table[di], table[bx], table[si]);
+                                       si++;
+                               }
+                               si -= 2;
+                               for(o = 0; o < 3; o++) {
+                                       SiS_WriteDAC(SiS_Pr, DACData, sf, n,
+                                               table[di], table[si], table[bx]);
+                                       si--;
+                               }
+                       }
+               si += 5;
+               }
+       }
+}
+
+/*********************************************/
+/*         SET CRT1 REGISTER GROUP           */
+/*********************************************/
+
+static void
+SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+                                       unsigned short ModeIdIndex)
+{
+       unsigned short StandTableIndex, rrti;
+
+       SiS_Pr->SiS_CRT1Mode = ModeNo;
+
+       if (ModeNo <= 0x13)
+               StandTableIndex = 0;
+       else
+               StandTableIndex = 1;
+
+       SiS_ResetSegmentRegisters(SiS_Pr);
+       SiS_SetSeqRegs(SiS_Pr, StandTableIndex);
+       SiS_SetMiscRegs(SiS_Pr, StandTableIndex);
+       SiS_SetCRTCRegs(SiS_Pr, StandTableIndex);
+       SiS_SetATTRegs(SiS_Pr, StandTableIndex);
+       SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
+       SiS_ClearExt1Regs(SiS_Pr, ModeNo);
+
+       rrti = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex);
+
+       if (rrti != 0xFFFF) {
+               SiS_SetCRT1Sync(SiS_Pr, rrti);
+               SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, rrti);
+               SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
+               SiS_SetCRT1VCLK(SiS_Pr, ModeNo, rrti);
+       }
+
+       SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex);
+
+       SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, rrti);
+
+       SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex);
+
+       SiS_DisplayOn(SiS_Pr);
+}
+
+/*********************************************/
+/*                 SiSSetMode()              */
+/*********************************************/
+
+int
+SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+{
+       unsigned short ModeIdIndex;
+       unsigned long  BaseAddr = SiS_Pr->IOAddress;
+
+       SiSUSB_InitPtr(SiS_Pr);
+       SiSUSBRegInit(SiS_Pr, BaseAddr);
+       SiS_GetSysFlags(SiS_Pr);
+
+       if (!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex)))
+               return 0;
+
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x05, 0x86);
+
+       SiSInitPCIetc(SiS_Pr);
+
+       ModeNo &= 0x7f;
+
+       SiS_Pr->SiS_ModeType =
+               SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+
+       SiS_Pr->SiS_SetFlag = LowModeTests;
+
+       /* Set mode on CRT1 */
+       SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
+
+       SiS_HandleCRT1(SiS_Pr);
+
+       SiS_DisplayOn(SiS_Pr);
+       SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
+
+       /* Store mode number */
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x34, ModeNo);
+
+       return 1;
+}
+
+int
+SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+{
+       unsigned short ModeNo = 0;
+       int i;
+
+       SiSUSB_InitPtr(SiS_Pr);
+
+       if (VModeNo == 0x03) {
+
+               ModeNo = 0x03;
+
+       } else {
+
+               i = 0;
+               do {
+
+                       if (SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID == VModeNo) {
+                               ModeNo = SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID;
+                               break;
+                       }
+
+               } while (SiS_Pr->SiS_EModeIDTable[i++].Ext_ModeID != 0xff);
+
+       }
+
+       if (!ModeNo)
+               return 0;
+
+       return SiSUSBSetMode(SiS_Pr, ModeNo);
+}
+
+#endif /* INCL_SISUSB_CON */
+
+
+
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
new file mode 100644 (file)
index 0000000..5b11577
--- /dev/null
@@ -0,0 +1,830 @@
+/* $XFree86$ */
+/* $XdotOrg$ */
+/*
+ * Data and prototypes for init.c
+ *
+ * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _SISUSB_INIT_H_
+#define _SISUSB_INIT_H_
+
+/* SiS_ModeType */
+#define ModeText               0x00
+#define ModeCGA                        0x01
+#define ModeEGA                        0x02
+#define ModeVGA                        0x03
+#define Mode15Bpp              0x04
+#define Mode16Bpp              0x05
+#define Mode24Bpp              0x06
+#define Mode32Bpp              0x07
+
+#define ModeTypeMask           0x07
+#define IsTextMode             0x07
+
+#define DACInfoFlag            0x0018
+#define MemoryInfoFlag         0x01E0
+#define MemorySizeShift                5
+
+/* modeflag */
+#define Charx8Dot              0x0200
+#define LineCompareOff         0x0400
+#define CRT2Mode               0x0800
+#define HalfDCLK               0x1000
+#define NoSupportSimuTV                0x2000
+#define NoSupportLCDScale      0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define DoubleScanMode         0x8000
+
+/* Infoflag */
+#define SupportTV              0x0008
+#define SupportTV1024          0x0800
+#define SupportCHTV            0x0800
+#define Support64048060Hz      0x0800  /* Special for 640x480 LCD */
+#define SupportHiVision                0x0010
+#define SupportYPbPr750p       0x1000
+#define SupportLCD             0x0020
+#define SupportRAMDAC2         0x0040  /* All           (<= 100Mhz) */
+#define SupportRAMDAC2_135     0x0100  /* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162     0x0200  /* B, C          (<= 162Mhz) */
+#define SupportRAMDAC2_202     0x0400  /* C             (<= 202Mhz) */
+#define InterlaceMode          0x0080
+#define SyncPP                 0x0000
+#define SyncPN                 0x4000
+#define SyncNP                 0x8000
+#define SyncNN                 0xc000
+
+/* SetFlag */
+#define ProgrammingCRT2                0x0001
+#define LowModeTests           0x0002
+#define LCDVESATiming          0x0008
+#define EnableLVDSDDA          0x0010
+#define SetDispDevSwitchFlag   0x0020
+#define CheckWinDos            0x0040
+#define SetDOSMode             0x0080
+
+/* Index in ModeResInfo table */
+#define SIS_RI_320x200         0
+#define SIS_RI_320x240         1
+#define SIS_RI_320x400         2
+#define SIS_RI_400x300         3
+#define SIS_RI_512x384         4
+#define SIS_RI_640x400         5
+#define SIS_RI_640x480         6
+#define SIS_RI_800x600         7
+#define SIS_RI_1024x768                8
+#define SIS_RI_1280x1024       9
+#define SIS_RI_1600x1200       10
+#define SIS_RI_1920x1440       11
+#define SIS_RI_2048x1536       12
+#define SIS_RI_720x480         13
+#define SIS_RI_720x576         14
+#define SIS_RI_1280x960                15
+#define SIS_RI_800x480         16
+#define SIS_RI_1024x576                17
+#define SIS_RI_1280x720                18
+#define SIS_RI_856x480         19
+#define SIS_RI_1280x768                20
+#define SIS_RI_1400x1050       21
+#define SIS_RI_1152x864                22  /* Up to here SiS conforming */
+#define SIS_RI_848x480         23
+#define SIS_RI_1360x768                24
+#define SIS_RI_1024x600                25
+#define SIS_RI_1152x768                26
+#define SIS_RI_768x576         27
+#define SIS_RI_1360x1024       28
+#define SIS_RI_1680x1050       29
+#define SIS_RI_1280x800                30
+#define SIS_RI_1920x1080       31
+#define SIS_RI_960x540         32
+#define SIS_RI_960x600         33
+
+#define SIS_VIDEO_CAPTURE      0x00 - 0x30
+#define SIS_VIDEO_PLAYBACK     0x02 - 0x30
+#define SIS_CRT2_PORT_04       0x04 - 0x30
+
+/* Mode numbers */
+static const unsigned short ModeIndex_320x200[]   = {0x59, 0x41, 0x00, 0x4f};
+static const unsigned short ModeIndex_320x240[]   = {0x50, 0x56, 0x00, 0x53};
+static const unsigned short ModeIndex_400x300[]   = {0x51, 0x57, 0x00, 0x54};
+static const unsigned short ModeIndex_512x384[]   = {0x52, 0x58, 0x00, 0x5c};
+static const unsigned short ModeIndex_640x400[]   = {0x2f, 0x5d, 0x00, 0x5e};
+static const unsigned short ModeIndex_640x480[]   = {0x2e, 0x44, 0x00, 0x62};
+static const unsigned short ModeIndex_720x480[]   = {0x31, 0x33, 0x00, 0x35};
+static const unsigned short ModeIndex_720x576[]   = {0x32, 0x34, 0x00, 0x36};
+static const unsigned short ModeIndex_768x576[]   = {0x5f, 0x60, 0x00, 0x61};
+static const unsigned short ModeIndex_800x480[]   = {0x70, 0x7a, 0x00, 0x76};
+static const unsigned short ModeIndex_800x600[]   = {0x30, 0x47, 0x00, 0x63};
+static const unsigned short ModeIndex_848x480[]   = {0x39, 0x3b, 0x00, 0x3e};
+static const unsigned short ModeIndex_856x480[]   = {0x3f, 0x42, 0x00, 0x45};
+static const unsigned short ModeIndex_960x540[]   = {0x1d, 0x1e, 0x00, 0x1f};
+static const unsigned short ModeIndex_960x600[]   = {0x20, 0x21, 0x00, 0x22};
+static const unsigned short ModeIndex_1024x768[]  = {0x38, 0x4a, 0x00, 0x64};
+static const unsigned short ModeIndex_1024x576[]  = {0x71, 0x74, 0x00, 0x77};
+static const unsigned short ModeIndex_1152x864[]  = {0x29, 0x2a, 0x00, 0x2b};
+static const unsigned short ModeIndex_1280x720[]  = {0x79, 0x75, 0x00, 0x78};
+static const unsigned short ModeIndex_1280x768[]  = {0x23, 0x24, 0x00, 0x25};
+static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
+
+static const unsigned char SiS_MDA_DAC[] =
+{
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+};
+
+static const unsigned char SiS_CGA_DAC[] =
+{
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+};
+
+static const unsigned char SiS_EGA_DAC[] =
+{
+        0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
+        0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
+        0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
+        0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
+        0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
+        0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
+        0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+};
+
+static const unsigned char SiS_VGA_DAC[] =
+{
+       0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+       0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+       0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
+       0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
+       0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
+       0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
+       0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
+       0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
+       0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
+       0x0B,0x0C,0x0D,0x0F,0x10
+};
+
+static const struct SiS_St SiSUSB_SModeIDTable[] =
+{
+       {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
+       {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+};
+
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
+{
+       { 640,400},
+       { 640,350},
+       { 720,400},
+       { 720,350},
+       { 640,480}
+};
+
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
+{
+       {  320, 200, 8, 8},   /* 0x00 */
+       {  320, 240, 8, 8},   /* 0x01 */
+       {  320, 400, 8, 8},   /* 0x02 */
+       {  400, 300, 8, 8},   /* 0x03 */
+       {  512, 384, 8, 8},   /* 0x04 */
+       {  640, 400, 8,16},   /* 0x05 */
+       {  640, 480, 8,16},   /* 0x06 */
+       {  800, 600, 8,16},   /* 0x07 */
+       { 1024, 768, 8,16},   /* 0x08 */
+       { 1280,1024, 8,16},   /* 0x09 */
+       { 1600,1200, 8,16},   /* 0x0a */
+       { 1920,1440, 8,16},   /* 0x0b */
+       { 2048,1536, 8,16},   /* 0x0c */
+       {  720, 480, 8,16},   /* 0x0d */
+       {  720, 576, 8,16},   /* 0x0e */
+       { 1280, 960, 8,16},   /* 0x0f */
+       {  800, 480, 8,16},   /* 0x10 */
+       { 1024, 576, 8,16},   /* 0x11 */
+       { 1280, 720, 8,16},   /* 0x12 */
+       {  856, 480, 8,16},   /* 0x13 */
+       { 1280, 768, 8,16},   /* 0x14 */
+       { 1400,1050, 8,16},   /* 0x15 */
+       { 1152, 864, 8,16},   /* 0x16 */
+       {  848, 480, 8,16},   /* 0x17 */
+       { 1360, 768, 8,16},   /* 0x18 */
+       { 1024, 600, 8,16},   /* 0x19 */
+       { 1152, 768, 8,16},   /* 0x1a */
+       {  768, 576, 8,16},   /* 0x1b */
+       { 1360,1024, 8,16},   /* 0x1c */
+       { 1680,1050, 8,16},   /* 0x1d */
+       { 1280, 800, 8,16},   /* 0x1e */
+       { 1920,1080, 8,16},   /* 0x1f */
+       {  960, 540, 8,16},   /* 0x20 */
+       {  960, 600, 8,16}    /* 0x21 */
+};
+
+static const struct SiS_StandTable SiSUSB_StandTable[] =
+{
+       /* MD_3_400 - mode 0x03 - 400 */
+       {
+               0x50,0x18,0x10,0x1000,
+               { 0x00,0x03,0x00,0x02 },
+               0x67,
+               { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+                 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+                 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+                 0xff },
+               { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+                 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+                 0x0c,0x00,0x0f,0x08 },
+               { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
+       },
+       /* Generic for VGA and higher */
+       {
+               0x00,0x00,0x00,0x0000,
+               { 0x01,0x0f,0x00,0x0e },
+               0x23,
+               { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+                 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+                 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+                 0xff },
+               { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+                 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+                 0x01,0x00,0x00,0x00 },
+               { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
+       }
+};
+
+static const struct SiS_Ext SiSUSB_EModeIDTable[] =
+{
+       {0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
+       {0x2f,0x0a1b,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
+       {0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
+       {0x31,0x4a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
+       {0x32,0x4a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
+       {0x33,0x4a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
+       {0x34,0x6a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
+       {0x35,0x4a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
+       {0x36,0x6a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
+       {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
+       {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
+       {0x41,0x9a1d,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
+       {0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
+       {0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
+       {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
+       {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
+       {0x50,0x9a1b,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8  */
+       {0x51,0xba1b,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8  */
+       {0x52,0xba1b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8  */
+       {0x56,0x9a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
+       {0x57,0xba1d,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
+       {0x58,0xba1d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
+       {0x59,0x9a1b,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8  */
+       {0x5c,0xba1f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
+       {0x5d,0x0a1d,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
+       {0x5e,0x0a1f,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
+       {0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
+       {0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
+       {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
+       {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
+       {0x70,0x6a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
+       {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
+       {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
+       {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
+       {0x76,0x6a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
+       {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
+       {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
+       {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
+       {0x7a,0x6a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
+       {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
+       {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
+       {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
+       {0x39,0x6a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
+       {0x3b,0x6a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
+       {0x3e,0x6a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
+       {0x3f,0x6a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
+       {0x42,0x6a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
+       {0x45,0x6a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
+       {0x4f,0x9a1f,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
+       {0x53,0x9a1f,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
+       {0x54,0xba1f,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
+       {0x5f,0x6a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
+       {0x60,0x6a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
+       {0x61,0x6a3f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
+       {0x1d,0x6a1b,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
+       {0x1e,0x6a3d,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
+       {0x1f,0x6a7f,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
+       {0x20,0x6a1b,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
+       {0x21,0x6a3d,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
+       {0x22,0x6a7f,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
+       {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
+       {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
+       {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
+       {0xff,0x0000,0x0000,0,               0x00,0x00,0x00,0x00,0x00,-1}
+};
+
+static const struct SiS_Ext2 SiSUSB_RefIndex[] =
+{
+       {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
+       {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
+       {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
+       {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
+       {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
+       {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
+       {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
+       {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
+       {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
+       {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
+       {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
+       {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
+       {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
+       {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
+       {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
+       {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
+       {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
+       {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
+       {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
+       {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
+       {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
+       {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
+       {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
+       {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
+       {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
+       {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
+       {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
+       {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
+       {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
+       {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
+       {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
+       {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
+       {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
+       {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
+       {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
+       {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
+       {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
+       {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
+       {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
+       {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
+       {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi  */
+       {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz   */
+       {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi  */
+       {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz   */
+       {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz   */
+       {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
+       {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
+       {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
+       {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
+       {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
+       {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
+       {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz  */
+       {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz  */
+       {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz  */
+       {0xffff,0x00,0x00,0x00,0x00,0x00,   0,   0,    0, 0x00, 0x00}
+};
+
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
+{
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
+   0x00}}, /* 0x0 */
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}, /* 0x1 */
+ {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
+   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
+   0x01}}, /* 0x2 */
+ {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
+   0x01}}, /* 0x3 */
+ {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
+   0x00}}, /* 0x4 */
+ {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
+   0x00}}, /* 0x5 */
+ {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
+   0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
+   0x00}}, /* 0x6 */
+ {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
+   0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
+   0x00}}, /* 0x7 */
+ {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
+   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
+   0x00}}, /* 0x8 */
+ {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
+   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
+   0x61}}, /* 0x9 */
+ {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
+   0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
+   0x61}}, /* 0xa */
+ {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
+   0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
+   0x61}}, /* 0xb */
+ {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
+   0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
+   0x00}}, /* 0xc */
+ {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
+   0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
+   0x01}}, /* 0xd */
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
+   0x01}}, /* 0xe */
+ {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
+   0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
+   0x01}}, /* 0xf */
+ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
+   0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
+   0x01}}, /* 0x10 */
+ {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
+   0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
+   0x01}}, /* 0x11 */
+ {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
+   0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
+   0x61}}, /* 0x12 */
+ {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
+   0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
+   0x61}}, /* 0x13 */
+ {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
+   0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
+   0x61}}, /* 0x14 */
+ {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
+   0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
+   0x00}}, /* 0x15 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}}, /* 0x16 */
+ {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}}, /* 0x17 */
+ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
+   0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
+   0x01}}, /* 0x18 */
+ {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
+   0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
+   0x01}}, /* 0x19 */
+ {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
+   0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
+   0x62}}, /* 0x1a */
+ {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
+   0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
+   0x62}}, /* 0x1b */
+ {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
+   0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
+   0x00}}, /* 0x1c */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
+   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+   0x01}}, /* 0x1d */
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
+   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+   0x01}}, /* 0x1e */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
+   0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
+   0x01}}, /* 0x1f */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x20 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x21 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x22 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x23 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x24 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x25 */
+ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x26 */
+ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x27 */
+ {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
+   0x63}}, /* 0x28 */
+ {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
+   0x63}}, /* 0x29 */
+ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2a */
+ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2b */
+ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2c */
+ {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
+   0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
+   0x44}}, /* 0x2d */
+ {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
+   0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
+   0x44}}, /* 0x2e */
+ {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
+   0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
+   0x44}}, /* 0x2f */
+ {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
+   0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
+   0x44}}, /* 0x30 */
+ {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
+   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
+   0x00}}, /* 0x31 */
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
+   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
+   0x01}}, /* 0x32 */
+ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
+   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
+   0x01}}, /* 0x33 */
+ {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
+   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
+   0x01}}, /* 0x34 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
+   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
+   0x01}}, /* 0x35 */
+ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
+   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
+   0x01}}, /* 0x36 */
+ {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
+   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
+   0x01}}, /* 0x37 */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x38 */
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x39 */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
+   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
+   0x01}}, /* 0x3a */
+ {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
+   0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
+   0x01}}, /* 0x3b */
+ {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+   0x00}}, /* 0x3c */
+ {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
+   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
+   0x41}}, /* 0x3d */
+ {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
+   0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
+   0x00}}, /* 0x3e */
+ {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
+   0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
+   0x00}}, /* 0x3f */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
+   0x01}},  /* 0x40 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}},  /* 0x41 */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
+   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
+   0x01}},  /* 0x42 */
+ {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
+   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
+   0x00}},  /* 0x43 */
+ {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
+   0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
+   0x01}},  /* 0x44 */
+ {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
+   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
+   0x00}},  /* 0x45 */
+ {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
+   0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
+   0x00}},  /* 0x46 */
+ {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
+   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
+   0x00}},  /* 0x47 */
+ {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
+   0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
+   0x00}},  /* 0x48 */
+ {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
+   0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
+   0x01}},  /* 0x49 */
+ {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
+   0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
+   0x01}},  /* 0x4a */
+ {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
+   0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
+   0x00}},  /* 0x4b */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
+   0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
+   0x01}},  /* 0x4c */
+ {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
+   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
+   0x41}},
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
+   0x00}},  /* 0x4e */
+ {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
+   0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
+   0x21}},  /* 0x4f */
+ {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
+   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
+   0x20}},  /* 0x50 */
+ {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
+   0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
+   0x61}},  /* 0x51 */
+ {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
+   0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
+   0x41}},  /* 0x52 */
+ {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
+   0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
+   0x01}},  /* 0x53 */
+ {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
+   0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
+   0x41}}   /* 0x54 */
+};
+
+static struct SiS_VCLKData SiSUSB_VCLKData[] =
+{
+       { 0x1b,0xe1, 25}, /* 0x00 */
+       { 0x4e,0xe4, 28}, /* 0x01 */
+       { 0x57,0xe4, 31}, /* 0x02 */
+       { 0xc3,0xc8, 36}, /* 0x03 */
+       { 0x42,0xe2, 40}, /* 0x04 */
+       { 0xfe,0xcd, 43}, /* 0x05 */
+       { 0x5d,0xc4, 44}, /* 0x06 */
+       { 0x52,0xe2, 49}, /* 0x07 */
+       { 0x53,0xe2, 50}, /* 0x08 */
+       { 0x74,0x67, 52}, /* 0x09 */
+       { 0x6d,0x66, 56}, /* 0x0a */
+       { 0x5a,0x64, 65}, /* 0x0b */
+       { 0x46,0x44, 67}, /* 0x0c */
+       { 0xb1,0x46, 68}, /* 0x0d */
+       { 0xd3,0x4a, 72}, /* 0x0e */
+       { 0x29,0x61, 75}, /* 0x0f */
+       { 0x6e,0x46, 76}, /* 0x10 */
+       { 0x2b,0x61, 78}, /* 0x11 */
+       { 0x31,0x42, 79}, /* 0x12 */
+       { 0xab,0x44, 83}, /* 0x13 */
+       { 0x46,0x25, 84}, /* 0x14 */
+       { 0x78,0x29, 86}, /* 0x15 */
+       { 0x62,0x44, 94}, /* 0x16 */
+       { 0x2b,0x41,104}, /* 0x17 */
+       { 0x3a,0x23,105}, /* 0x18 */
+       { 0x70,0x44,108}, /* 0x19 */
+       { 0x3c,0x23,109}, /* 0x1a */
+       { 0x5e,0x43,113}, /* 0x1b */
+       { 0xbc,0x44,116}, /* 0x1c */
+       { 0xe0,0x46,132}, /* 0x1d */
+       { 0x54,0x42,135}, /* 0x1e */
+       { 0xea,0x2a,139}, /* 0x1f */
+       { 0x41,0x22,157}, /* 0x20 */
+       { 0x70,0x24,162}, /* 0x21 */
+       { 0x30,0x21,175}, /* 0x22 */
+       { 0x4e,0x22,189}, /* 0x23 */
+       { 0xde,0x26,194}, /* 0x24 */
+       { 0x62,0x06,202}, /* 0x25 */
+       { 0x3f,0x03,229}, /* 0x26 */
+       { 0xb8,0x06,234}, /* 0x27 */
+       { 0x34,0x02,253}, /* 0x28 */
+       { 0x58,0x04,255}, /* 0x29 */
+       { 0x24,0x01,265}, /* 0x2a */
+       { 0x9b,0x02,267}, /* 0x2b */
+       { 0x70,0x05,270}, /* 0x2c */
+       { 0x25,0x01,272}, /* 0x2d */
+       { 0x9c,0x02,277}, /* 0x2e */
+       { 0x27,0x01,286}, /* 0x2f */
+       { 0x3c,0x02,291}, /* 0x30 */
+       { 0xef,0x0a,292}, /* 0x31 */
+       { 0xf6,0x0a,310}, /* 0x32 */
+       { 0x95,0x01,315}, /* 0x33 */
+       { 0xf0,0x09,324}, /* 0x34 */
+       { 0xfe,0x0a,331}, /* 0x35 */
+       { 0xf3,0x09,332}, /* 0x36 */
+       { 0xea,0x08,340}, /* 0x37 */
+       { 0xe8,0x07,376}, /* 0x38 */
+       { 0xde,0x06,389}, /* 0x39 */
+       { 0x52,0x2a, 54}, /* 0x3a 301 TV */
+       { 0x52,0x6a, 27}, /* 0x3b 301 TV */
+       { 0x62,0x24, 70}, /* 0x3c 301 TV */
+       { 0x62,0x64, 70}, /* 0x3d 301 TV */
+       { 0xa8,0x4c, 30}, /* 0x3e 301 TV */
+       { 0x20,0x26, 33}, /* 0x3f 301 TV */
+       { 0x31,0xc2, 39}, /* 0x40 */
+       { 0x60,0x36, 30}, /* 0x41 Chrontel */
+       { 0x40,0x4a, 28}, /* 0x42 Chrontel */
+       { 0x9f,0x46, 44}, /* 0x43 Chrontel */
+       { 0x97,0x2c, 26}, /* 0x44 */
+       { 0x44,0xe4, 25}, /* 0x45 Chrontel */
+       { 0x7e,0x32, 47}, /* 0x46 Chrontel */
+       { 0x8a,0x24, 31}, /* 0x47 Chrontel */
+       { 0x97,0x2c, 26}, /* 0x48 Chrontel */
+       { 0xce,0x3c, 39}, /* 0x49 */
+       { 0x52,0x4a, 36}, /* 0x4a Chrontel */
+       { 0x34,0x61, 95}, /* 0x4b */
+       { 0x78,0x27,108}, /* 0x4c - was 102 */
+       { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
+       { 0x41,0x4e, 21}, /* 0x4e */
+       { 0xa1,0x4a, 29}, /* 0x4f Chrontel */
+       { 0x19,0x42, 42}, /* 0x50 */
+       { 0x54,0x46, 58}, /* 0x51 Chrontel */
+       { 0x25,0x42, 61}, /* 0x52 */
+       { 0x44,0x44, 66}, /* 0x53 Chrontel */
+       { 0x3a,0x62, 70}, /* 0x54 Chrontel */
+       { 0x62,0xc6, 34}, /* 0x55 848x480-60 */
+       { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
+       { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
+       { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
+       { 0x52,0x07,149}, /* 0x59 1280x960-85 */
+       { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
+       { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
+       { 0x45,0x25, 83}, /* 0x5c 1280x800  */
+       { 0x70,0x0a,147}, /* 0x5d 1680x1050 */
+       { 0x70,0x24,162}, /* 0x5e 1600x1200 */
+       { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
+       { 0x63,0x46, 68}, /* 0x60 1280x768_2 */
+       { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
+       {    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
+       { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
+       { 0x70,0x28, 90}, /* 0x64 1152x864@60 */
+       { 0x41,0xc4, 32}, /* 0x65 848x480@60 */
+       { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
+       { 0x76,0xe7, 27}, /* 0x67 720x480@60 */
+       { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
+       { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
+       { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
+       { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
+       { 0x45,0x25, 83}, /* 0x6c 1280x800 */
+       { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
+       { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
+       { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
+       { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
+       { 0x2b,0xc2, 35}  /* 0x71 768@576@60 */
+};
+
+void           SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr);
+unsigned short SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth);
+int            SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int            SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+
+extern int     sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int     sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
+extern int     sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+                                       u8 index, u8 data);
+extern int     sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+                                       u8 index, u8 *data);
+extern int     sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+                                       u8 idx, u8 myand, u8 myor);
+extern int     sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+                                       u8 index, u8 myor);
+extern int     sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+                                       u8 idx, u8 myand);
+
+#endif
+
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h
new file mode 100644 (file)
index 0000000..94edd47
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * General structure definitions for universal mode switching modules
+ *
+ * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
+ *
+ * If distributed as part of the Linux kernel, the following license terms
+ * apply:
+ *
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License as published by
+ * * the Free Software Foundation; either version 2 of the named License,
+ * * or any later version.
+ * *
+ * * This program is distributed in the hope that it will be useful,
+ * * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * * GNU General Public License for more details.
+ * *
+ * * You should have received a copy of the GNU General Public License
+ * * along with this program; if not, write to the Free Software
+ * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Otherwise, the following license terms apply:
+ *
+ * * Redistribution and use in source and binary forms, with or without
+ * * modification, are permitted provided that the following conditions
+ * * are met:
+ * * 1) Redistributions of source code must retain the above copyright
+ * *    notice, this list of conditions and the following disclaimer.
+ * * 2) Redistributions in binary form must reproduce the above copyright
+ * *    notice, this list of conditions and the following disclaimer in the
+ * *    documentation and/or other materials provided with the distribution.
+ * * 3) The name of the author may not be used to endorse or promote products
+ * *    derived from this software without specific prior written permission.
+ * *
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ */
+
+#ifndef _SISUSB_STRUCT_H_
+#define _SISUSB_STRUCT_H_
+
+struct SiS_St {
+       unsigned char   St_ModeID;
+       unsigned short  St_ModeFlag;
+       unsigned char   St_StTableIndex;
+       unsigned char   St_CRT2CRTC;
+       unsigned char   St_ResInfo;
+       unsigned char   VB_StTVFlickerIndex;
+       unsigned char   VB_StTVEdgeIndex;
+       unsigned char   VB_StTVYFilterIndex;
+       unsigned char   St_PDC;
+};
+
+struct SiS_StandTable
+{
+       unsigned char   CRT_COLS;
+       unsigned char   ROWS;
+       unsigned char   CHAR_HEIGHT;
+       unsigned short  CRT_LEN;
+       unsigned char   SR[4];
+       unsigned char   MISC;
+       unsigned char   CRTC[0x19];
+       unsigned char   ATTR[0x14];
+       unsigned char   GRC[9];
+};
+
+struct SiS_StResInfo_S {
+       unsigned short  HTotal;
+       unsigned short  VTotal;
+};
+
+struct SiS_Ext
+{
+       unsigned char   Ext_ModeID;
+       unsigned short  Ext_ModeFlag;
+       unsigned short  Ext_VESAID;
+       unsigned char   Ext_RESINFO;
+       unsigned char   VB_ExtTVFlickerIndex;
+       unsigned char   VB_ExtTVEdgeIndex;
+       unsigned char   VB_ExtTVYFilterIndex;
+       unsigned char   VB_ExtTVYFilterIndexROM661;
+       unsigned char   REFindex;
+       char            ROMMODEIDX661;
+};
+
+struct SiS_Ext2
+{
+       unsigned short  Ext_InfoFlag;
+       unsigned char   Ext_CRT1CRTC;
+       unsigned char   Ext_CRTVCLK;
+       unsigned char   Ext_CRT2CRTC;
+       unsigned char   Ext_CRT2CRTC_NS;
+       unsigned char   ModeID;
+       unsigned short  XRes;
+       unsigned short  YRes;
+       unsigned char   Ext_PDC;
+       unsigned char   Ext_FakeCRT2CRTC;
+       unsigned char   Ext_FakeCRT2Clk;
+};
+
+struct SiS_CRT1Table
+{
+       unsigned char   CR[17];
+};
+
+struct SiS_VCLKData
+{
+       unsigned char   SR2B,SR2C;
+       unsigned short  CLOCK;
+};
+
+struct SiS_ModeResInfo
+{
+       unsigned short  HTotal;
+       unsigned short  VTotal;
+       unsigned char   XChar;
+       unsigned char   YChar;
+};
+
+struct SiS_Private
+{
+       void *sisusb;
+
+       unsigned long IOAddress;
+
+       unsigned long SiS_P3c4;
+       unsigned long SiS_P3d4;
+       unsigned long SiS_P3c0;
+       unsigned long SiS_P3ce;
+       unsigned long SiS_P3c2;
+       unsigned long SiS_P3ca;
+       unsigned long SiS_P3c6;
+       unsigned long SiS_P3c7;
+       unsigned long SiS_P3c8;
+       unsigned long SiS_P3c9;
+       unsigned long SiS_P3cb;
+       unsigned long SiS_P3cc;
+       unsigned long SiS_P3cd;
+       unsigned long SiS_P3da;
+       unsigned long SiS_Part1Port;
+
+       unsigned char   SiS_MyCR63;
+       unsigned short  SiS_CRT1Mode;
+       unsigned short  SiS_ModeType;
+       unsigned short  SiS_SetFlag;
+
+       const struct SiS_StandTable     *SiS_StandTable;
+       const struct SiS_St             *SiS_SModeIDTable;
+       const struct SiS_Ext            *SiS_EModeIDTable;
+       const struct SiS_Ext2           *SiS_RefIndex;
+       const struct SiS_CRT1Table      *SiS_CRT1Table;
+       struct SiS_VCLKData             *SiS_VCLKData;
+       const struct SiS_ModeResInfo    *SiS_ModeResInfo;
+};
+
+#endif
+
index faa74436de52cdf539a14f53c5e950d7e1c06834..03fb70ef2eb3ec14e60c5f32188a24d78d5295b4 100644 (file)
@@ -3,8 +3,8 @@
 /*
  *     uss720.c  --  USS720 USB Parport Cable.
  *
- *     Copyright (C) 1999
- *         Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *     Copyright (C) 1999, 2005
+ *         Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *     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
  *  Based on parport_pc.c
  *
  *  History:
- *   0.1  04.08.99  Created
- *   0.2  07.08.99  Some fixes mainly suggested by Tim Waugh
- *                 Interrupt handling currently disabled because
- *                 usb_request_irq crashes somewhere within ohci.c
- *                 for no apparent reason (that is for me, anyway)
- *                 ECP currently untested
- *   0.3  10.08.99  fixing merge errors
- *   0.4  13.08.99  Added Vendor/Product ID of Brad Hard's cable
- *   0.5  20.09.99  usb_control_msg wrapper used
- *        Nov01.00  usb_device_table support by Adam J. Richter
- *        08.04.01  Identify version on module load.  gb
+ *   0.1  04.08.1999  Created
+ *   0.2  07.08.1999  Some fixes mainly suggested by Tim Waugh
+ *                   Interrupt handling currently disabled because
+ *                   usb_request_irq crashes somewhere within ohci.c
+ *                   for no apparent reason (that is for me, anyway)
+ *                   ECP currently untested
+ *   0.3  10.08.1999  fixing merge errors
+ *   0.4  13.08.1999  Added Vendor/Product ID of Brad Hard's cable
+ *   0.5  20.09.1999  usb_control_msg wrapper used
+ *        Nov01.2000  usb_device_table support by Adam J. Richter
+ *        08.04.2001  Identify version on module load.  gb
+ *   0.6  02.09.2005  Fix "scheduling in interrupt" problem by making save/restore
+ *                    context asynchronous
  *
  */
 
 /*****************************************************************************/
 
+#define DEBUG
+
 #include <linux/module.h>
 #include <linux/socket.h>
 #include <linux/parport.h>
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/kref.h>
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5"
-#define DRIVER_AUTHOR "Thomas M. Sailer, sailer@ife.ee.ethz.ch"
+#define DRIVER_VERSION "v0.6"
+#define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch"
 #define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip"
 
 /* --------------------------------------------------------------------- */
 
 struct parport_uss720_private {
        struct usb_device *usbdev;
-       void *irqhandle;
-       unsigned int irqpipe;
-       unsigned char reg[7];  /* USB registers */
+       struct parport *pp;
+       struct kref ref_count;
+       __u8 reg[7];  /* USB registers */
+       struct list_head asynclist;
+       spinlock_t asynclock;
+};
+
+struct uss720_async_request {
+       struct parport_uss720_private *priv;
+       struct kref ref_count;
+       struct list_head asynclist;
+       struct completion compl;
+       struct urb *urb;
+       struct usb_ctrlrequest dr;
+       __u8 reg[7];
 };
 
 /* --------------------------------------------------------------------- */
 
-static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val)
+static void destroy_priv(struct kref *kref)
 {
-       struct parport_uss720_private *priv = pp->private_data;
-       struct usb_device *usbdev = priv->usbdev;
-       static const unsigned char regindex[9] = {
-               4, 0, 1, 5, 5, 0, 2, 3, 6
-       };
-       int ret;
+       struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count);
 
-       if (!usbdev)
-               return -1;
-       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, 1000);
-       if (ret != 7) {
-               printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x expected 7\n",
-                      (unsigned int)reg, ret);
-               ret = -1;
-       } else {
+       usb_put_dev(priv->usbdev);
+       kfree(priv);
+       dbg("destroying priv datastructure");
+}
+
+static void destroy_async(struct kref *kref)
+{
+       struct uss720_async_request *rq = container_of(kref, struct uss720_async_request, ref_count);
+       struct parport_uss720_private *priv = rq->priv;
+       unsigned long flags;
+
+       if (likely(rq->urb))
+               usb_free_urb(rq->urb);
+       spin_lock_irqsave(&priv->asynclock, flags);
+       list_del_init(&rq->asynclist);
+       spin_unlock_irqrestore(&priv->asynclock, flags);
+       kfree(rq);
+       kref_put(&priv->ref_count, destroy_priv);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void async_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+       struct uss720_async_request *rq;
+       struct parport *pp;
+       struct parport_uss720_private *priv;
+
+       rq = urb->context;
+       priv = rq->priv;
+       pp = priv->pp;
+       if (urb->status) {
+               err("async_complete: urb error %d", urb->status);
+       } else if (rq->dr.bRequest == 3) {
+               memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
-               printk(KERN_DEBUG "uss720: get_1284_register(%d) return %02x %02x %02x %02x %02x %02x %02x\n",
-                      (unsigned int)reg, (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
-                      (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], (unsigned int)priv->reg[4],
-                      (unsigned int)priv->reg[5], (unsigned int)priv->reg[6]);
+               dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x",
+                   (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2],
+                   (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
+                   (unsigned int)priv->reg[6]);
 #endif
                /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
-               if (priv->reg[2] & priv->reg[1] & 0x10)
+               if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
                        parport_generic_irq(0, pp, NULL);
-               ret = 0;
        }
-       if (val)
-               *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
-       return ret;
+       complete(&rq->compl);
+       kref_put(&rq->ref_count, destroy_async);
 }
 
-static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val)
+static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv,
+                                                        __u8 request, __u8 requesttype, __u16 value, __u16 index,
+                                                        unsigned int mem_flags)
 {
-       struct parport_uss720_private *priv = pp->private_data;
-       struct usb_device *usbdev = priv->usbdev;
+       struct usb_device *usbdev;
+       struct uss720_async_request *rq;
+       unsigned long flags;
        int ret;
 
+       if (!priv)
+               return NULL;
+       usbdev = priv->usbdev;
        if (!usbdev)
-               return -1;
-       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, 1000);
-       if (ret) {
-               printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n", 
-                      (unsigned int)reg, (unsigned int)val, ret);
-       } else {
-#if 0
-               printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x)\n", 
-                      (unsigned int)reg, (unsigned int)val);
-#endif
+               return NULL;
+       rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
+       if (!rq) {
+               err("submit_async_request out of memory");
+               return NULL;
+       }
+       kref_init(&rq->ref_count);
+       INIT_LIST_HEAD(&rq->asynclist);
+       init_completion(&rq->compl);
+       kref_get(&priv->ref_count);
+       rq->priv = priv;
+       rq->urb = usb_alloc_urb(0, mem_flags);
+       if (!rq->urb) {
+               kref_put(&rq->ref_count, destroy_async);
+               err("submit_async_request out of memory");
+               return NULL;
+       }
+       rq->dr.bRequestType = requesttype;
+       rq->dr.bRequest = request;
+       rq->dr.wValue = cpu_to_le16(value);
+       rq->dr.wIndex = cpu_to_le16(index);
+       rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
+       usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0),
+                            (unsigned char *)&rq->dr,
+                            (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq);
+       /* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */
+       spin_lock_irqsave(&priv->asynclock, flags);
+       list_add_tail(&rq->asynclist, &priv->asynclist);
+       spin_unlock_irqrestore(&priv->asynclock, flags);
+       ret = usb_submit_urb(rq->urb, mem_flags);
+       if (!ret) {
+               kref_get(&rq->ref_count);
+               return rq;
        }
+       kref_put(&rq->ref_count, destroy_async);
+       err("submit_async_request submit_urb failed with %d", ret);
+       return NULL;
+}
+
+static unsigned int kill_all_async_requests_priv(struct parport_uss720_private *priv)
+{
+       struct uss720_async_request *rq;
+       unsigned long flags;
+       unsigned int ret = 0;
+
+       spin_lock_irqsave(&priv->asynclock, flags);
+       list_for_each_entry(rq, &priv->asynclist, asynclist) {
+               usb_unlink_urb(rq->urb);
+               ret++;
+       }
+       spin_unlock_irqrestore(&priv->asynclock, flags);
        return ret;
 }
 
 /* --------------------------------------------------------------------- */
 
+static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, unsigned int mem_flags)
+{
+       struct parport_uss720_private *priv;
+       struct uss720_async_request *rq;
+       static const unsigned char regindex[9] = {
+               4, 0, 1, 5, 5, 0, 2, 3, 6
+       };
+       int ret;
+
+       if (!pp)
+               return -EIO;
+       priv = pp->private_data;
+       rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags);
+       if (!rq) {
+               err("get_1284_register(%u) failed", (unsigned int)reg);
+               return -EIO;
+       }
+       if (!val) {
+               kref_put(&rq->ref_count, destroy_async);
+               return 0;
+       }
+       if (wait_for_completion_timeout(&rq->compl, HZ)) {
+               ret = rq->urb->status;
+               *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
+               if (ret)
+                       warn("get_1284_register: usb error %d", ret);
+               kref_put(&rq->ref_count, destroy_async);
+               return ret;
+       }
+       warn("get_1284_register timeout");
+       kill_all_async_requests_priv(priv);
+       return -EIO;
+}
+
+static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, unsigned int mem_flags)
+{
+       struct parport_uss720_private *priv;
+       struct uss720_async_request *rq;
+
+       if (!pp)
+               return -EIO;
+       priv = pp->private_data;
+       rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags);
+       if (!rq) {
+               err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val);
+               return -EIO;
+       }
+       kref_put(&rq->ref_count, destroy_async);
+       return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
 /* ECR modes */
 #define ECR_SPP 00
 #define ECR_PS2 01
@@ -132,8 +269,9 @@ static int change_mode(struct parport *pp, int m)
 {
        struct parport_uss720_private *priv = pp->private_data;
        int mode;
+       __u8 reg;
 
-       if (get_1284_register(pp, 6, NULL))
+       if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
                return -EIO;
        /* Bits <7:5> contain the mode. */
        mode = (priv->reg[2] >> 5) & 0x7;
@@ -153,7 +291,7 @@ static int change_mode(struct parport *pp, int m)
                case ECR_ECP: /* ECP Parallel Port mode */
                        /* Poll slowly. */
                        for (;;) {
-                               if (get_1284_register(pp, 6, NULL))
+                               if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
                                        return -EIO;
                                if (priv->reg[2] & 0x01)
                                        break;
@@ -167,7 +305,9 @@ static int change_mode(struct parport *pp, int m)
                }
        }
        /* Set the mode. */
-       if (set_1284_register(pp, 6, m << 5))
+       if (set_1284_register(pp, 6, m << 5, GFP_KERNEL))
+               return -EIO;
+       if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
                return -EIO;
        return 0;
 }
@@ -179,7 +319,7 @@ static int clear_epp_timeout(struct parport *pp)
 {
        unsigned char stat;
 
-       if (get_1284_register(pp, 1, &stat))
+       if (get_1284_register(pp, 1, &stat, GFP_KERNEL))
                return 1;
        return stat & 1;
 }
@@ -205,14 +345,14 @@ static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
 
 static void parport_uss720_write_data(struct parport *pp, unsigned char d)
 {
-       set_1284_register(pp, 0, d);
+       set_1284_register(pp, 0, d, GFP_KERNEL);
 }
 
 static unsigned char parport_uss720_read_data(struct parport *pp)
 {
        unsigned char ret;
 
-       if (get_1284_register(pp, 0, &ret))
+       if (get_1284_register(pp, 0, &ret, GFP_KERNEL))
                return 0;
        return ret;
 }
@@ -222,7 +362,7 @@ static void parport_uss720_write_control(struct parport *pp, unsigned char d)
        struct parport_uss720_private *priv = pp->private_data; 
 
        d = (d & 0xf) | (priv->reg[1] & 0xf0);
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -241,7 +381,7 @@ static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned ch
        mask &= 0x0f;
        val &= 0x0f;
        d = (priv->reg[1] & (~mask)) ^ val;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return 0;
        priv->reg[1] = d;
        return d & 0xf;
@@ -251,7 +391,7 @@ static unsigned char parport_uss720_read_status(struct parport *pp)
 {
        unsigned char ret;
 
-       if (get_1284_register(pp, 1, &ret))
+       if (get_1284_register(pp, 1, &ret, GFP_KERNEL))
                return 0;
        return ret & 0xf8;
 }
@@ -262,7 +402,7 @@ static void parport_uss720_disable_irq(struct parport *pp)
        unsigned char d;
 
        d = priv->reg[1] & ~0x10;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -273,7 +413,7 @@ static void parport_uss720_enable_irq(struct parport *pp)
        unsigned char d;
 
        d = priv->reg[1] | 0x10;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -284,7 +424,7 @@ static void parport_uss720_data_forward (struct parport *pp)
        unsigned char d;
 
        d = priv->reg[1] & ~0x20;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -295,7 +435,7 @@ static void parport_uss720_data_reverse (struct parport *pp)
        unsigned char d;
 
        d = priv->reg[1] | 0x20;
-       if (set_1284_register(pp, 2, d))
+       if (set_1284_register(pp, 2, d, GFP_KERNEL))
                return;
        priv->reg[1] = d;
 }
@@ -310,17 +450,23 @@ static void parport_uss720_save_state(struct parport *pp, struct parport_state *
 {
        struct parport_uss720_private *priv = pp->private_data; 
 
-       if (get_1284_register(pp, 2, NULL))
+#if 0
+       if (get_1284_register(pp, 2, NULL, GFP_ATOMIC))
                return;
+#endif
        s->u.pc.ctr = priv->reg[1];
        s->u.pc.ecr = priv->reg[2];
 }
 
 static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s)
 {
-       set_1284_register(pp, 2, s->u.pc.ctr);
-       set_1284_register(pp, 6, s->u.pc.ecr);
-       get_1284_register(pp, 2, NULL);
+       struct parport_uss720_private *priv = pp->private_data;
+
+       set_1284_register(pp, 2, s->u.pc.ctr, GFP_ATOMIC);
+       set_1284_register(pp, 6, s->u.pc.ecr, GFP_ATOMIC);
+       get_1284_register(pp, 2, NULL, GFP_ATOMIC);
+       priv->reg[1] = s->u.pc.ctr;
+       priv->reg[2] = s->u.pc.ecr;
 }
 
 static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
@@ -331,7 +477,7 @@ static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t
        if (change_mode(pp, ECR_EPP))
                return 0;
        for (; got < length; got++) {
-               if (get_1284_register(pp, 4, (char *)buf))
+               if (get_1284_register(pp, 4, (char *)buf, GFP_KERNEL))
                        break;
                buf++;
                if (priv->reg[0] & 0x01) {
@@ -352,10 +498,10 @@ static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf,
        if (change_mode(pp, ECR_EPP))
                return 0;
        for (; written < length; written++) {
-               if (set_1284_register(pp, 4, (char *)buf))
+               if (set_1284_register(pp, 4, (char *)buf, GFP_KERNEL))
                        break;
                ((char*)buf)++;
-               if (get_1284_register(pp, 1, NULL))
+               if (get_1284_register(pp, 1, NULL, GFP_KERNEL))
                        break;
                if (priv->reg[0] & 0x01) {
                        clear_epp_timeout(pp);
@@ -390,7 +536,7 @@ static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t
        if (change_mode(pp, ECR_EPP))
                return 0;
        for (; got < length; got++) {
-               if (get_1284_register(pp, 3, (char *)buf))
+               if (get_1284_register(pp, 3, (char *)buf, GFP_KERNEL))
                        break;
                buf++;
                if (priv->reg[0] & 0x01) {
@@ -410,10 +556,10 @@ static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf,
        if (change_mode(pp, ECR_EPP))
                return 0;
        for (; written < length; written++) {
-               if (set_1284_register(pp, 3, *(char *)buf))
+               if (set_1284_register(pp, 3, *(char *)buf, GFP_KERNEL))
                        break;
                buf++;
-               if (get_1284_register(pp, 1, NULL))
+               if (get_1284_register(pp, 1, NULL, GFP_KERNEL))
                        break;
                if (priv->reg[0] & 0x01) {
                        clear_epp_timeout(pp);
@@ -467,7 +613,7 @@ static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buff
        if (change_mode(pp, ECR_ECP))
                return 0;
        for (; written < len; written++) {
-               if (set_1284_register(pp, 5, *(char *)buffer))
+               if (set_1284_register(pp, 5, *(char *)buffer, GFP_KERNEL))
                        break;
                buffer++;
        }
@@ -536,93 +682,91 @@ static struct parport_operations parport_uss720_ops =
 static int uss720_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
-       struct usb_device *usbdev = interface_to_usbdev(intf);
+       struct usb_device *usbdev = usb_get_dev(interface_to_usbdev(intf));
        struct usb_host_interface *interface;
        struct usb_host_endpoint *endpoint;
        struct parport_uss720_private *priv;
        struct parport *pp;
+       unsigned char reg;
        int i;
 
-       printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n",
-              le16_to_cpu(usbdev->descriptor.idVendor),
-              le16_to_cpu(usbdev->descriptor.idProduct));
+       dbg("probe: vendor id 0x%x, device id 0x%x\n",
+           le16_to_cpu(usbdev->descriptor.idVendor),
+           le16_to_cpu(usbdev->descriptor.idProduct));
 
        /* our known interfaces have 3 alternate settings */
-       if (intf->num_altsetting != 3)
+       if (intf->num_altsetting != 3) {
+               usb_put_dev(usbdev);
                return -ENODEV;
-
+       }
        i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
-       printk(KERN_DEBUG "uss720: set inteface result %d\n", i);
+       dbg("set inteface result %d", i);
 
        interface = intf->cur_altsetting;
 
        /*
         * Allocate parport interface 
         */
-       printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
-
-       if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL)))
+       if (!(priv = kcalloc(sizeof(struct parport_uss720_private), 1, GFP_KERNEL))) {
+               usb_put_dev(usbdev);
                return -ENOMEM;
+       }
+       priv->pp = NULL;
+       priv->usbdev = usbdev;
+       kref_init(&priv->ref_count);
+       spin_lock_init(&priv->asynclock);
+       INIT_LIST_HEAD(&priv->asynclist);
        if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
-               printk(KERN_WARNING "usb-uss720: could not register parport\n");
+               warn("could not register parport");
                goto probe_abort;
        }
 
+       priv->pp = pp;
        pp->private_data = priv;
-       priv->usbdev = usbdev;
        pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
 
        /* set the USS720 control register to manual mode, no ECP compression, enable all ints */
-       set_1284_register(pp, 7, 0x00);
-       set_1284_register(pp, 6, 0x30);  /* PS/2 mode */
-       set_1284_register(pp, 2, 0x0c);
+       set_1284_register(pp, 7, 0x00, GFP_KERNEL);
+       set_1284_register(pp, 6, 0x30, GFP_KERNEL);  /* PS/2 mode */
+       set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
        /* debugging */
-       get_1284_register(pp, 0, NULL);
-       printk("uss720: reg: %02x %02x %02x %02x %02x %02x %02x\n",
-              priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
+       get_1284_register(pp, 0, &reg, GFP_KERNEL);
+       dbg("reg: %02x %02x %02x %02x %02x %02x %02x",
+           priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
 
        endpoint = &interface->endpoint[2];
-       printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
-#if 0
-       priv->irqpipe = usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress);
-       i = usb_request_irq(usbdev, priv->irqpipe,
-                                 uss720_irq, endpoint->bInterval,
-                                 pp, &priv->irqhandle);
-       if (i) {
-               printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i);
-               goto probe_abort_port;
-       }
-#endif
+       dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
        parport_announce_port(pp);
 
-       usb_set_intfdata (intf, pp);
+       usb_set_intfdata(intf, pp);
        return 0;
 
-#if 0
-probe_abort_port:
-       parport_put_port(pp);
-#endif
 probe_abort:
-       kfree(priv);
+       kill_all_async_requests_priv(priv);
+       kref_put(&priv->ref_count, destroy_priv);
        return -ENODEV;
 }
 
 static void uss720_disconnect(struct usb_interface *intf)
 {
-       struct parport *pp = usb_get_intfdata (intf);
+       struct parport *pp = usb_get_intfdata(intf);
        struct parport_uss720_private *priv;
+       struct usb_device *usbdev;
 
-       usb_set_intfdata (intf, NULL);
+       dbg("disconnect");
+       usb_set_intfdata(intf, NULL);
        if (pp) {
                priv = pp->private_data;
-               parport_remove_port(pp);
-#if 0
-               usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe);
-#endif
+               usbdev = priv->usbdev;
                priv->usbdev = NULL;
+               priv->pp = NULL;
+               dbg("parport_remove_port");
+               parport_remove_port(pp);
                parport_put_port(pp);
-               kfree(priv);
+               kill_all_async_requests_priv(priv);
+               kref_put(&priv->ref_count, destroy_priv);
        }
+       dbg("disconnect done");
 }
 
 /* table of cables that work through this driver */
@@ -647,8 +791,8 @@ static struct usb_driver uss720_driver = {
 
 /* --------------------------------------------------------------------- */
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 static int __init uss720_init(void)
@@ -659,6 +803,9 @@ static int __init uss720_init(void)
                goto out;
 
        info(DRIVER_VERSION ":" DRIVER_DESC);
+       info("NOTE: this is a special purpose driver to allow nonstandard");
+       info("protocols (eg. bitbang) over USS720 usb to parallel cables");
+       info("If you just want to connect to a printer, use usblp instead");
 out:
        return retval;
 }
index 417464dea9f6457948a3caba9f82a4170c81e30a..17d0190ef64ecce708999654a8e278c96d6a3558 100644 (file)
@@ -79,7 +79,7 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
                return '-';
 
        if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
-               return 'D';
+               return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
        if (urb->setup_packet == NULL)
                return 'Z';     /* '0' would be not as pretty. */
 
index 4ace9964fc6bd36a22c0a82da2fc432be4eef5f7..97c78c21e8d1db5a865092d05fbc93df93b959f6 100644 (file)
@@ -32,7 +32,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.04"
+#define DRIVER_VERSION "v0.05"
 #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
 
 /*
@@ -54,8 +54,11 @@ static void cp2101_shutdown(struct usb_serial*);
 static int debug;
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
+       { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
+       { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { } /* Terminating Entry */
 };
index 05c44ae3ed32adce07adbfb0a3d05edfdc5c1979..9ee1aaff2fcdc759a8f0fa28864eb58a5719ddf6 100644 (file)
@@ -610,8 +610,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
                timeout = max((HZ*2560)/bps,HZ/10);
        else
                timeout = 2*HZ;
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(timeout);
+       schedule_timeout_interruptible(timeout);
 
        dbg("%s - stopping urbs", __FUNCTION__);
        usb_kill_urb (port->interrupt_in_urb);
index 0a6e8b474b1ff46db9efd8b423dd9ad36b215c18..4e434cb10bb12de49efedf44838aaad248bad2b8 100644 (file)
@@ -914,7 +914,7 @@ static void ftdi_determine_type(struct usb_serial_port *port)
        unsigned interfaces;
 
        /* Assume it is not the original SIO device for now. */
-       priv->baud_base = 48000000 / 16;
+       priv->baud_base = 48000000 / 2;
        priv->write_offset = 0;
 
        version = le16_to_cpu(udev->descriptor.bcdDevice);
index 461474176cfbc8aae66081e1dc1c3b3117c83c37..3cf245bdda54d0a877989e5850886562d877c2d9 100644 (file)
@@ -95,6 +95,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
        { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
+       { USB_DEVICE( NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID ) },
        { }                                     /* Terminating entry */
 };
 
@@ -652,8 +653,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp)
                timeout = max((HZ*2560)/bps,HZ/10);
        else
                timeout = 2*HZ;
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(timeout);
+       schedule_timeout_interruptible(timeout);
 
        /* shutdown our urbs */
        dbg("%s - shutting down urbs", __FUNCTION__);
index b734c4003c5af6cf725d009f979e408641a6f8cf..7be9644f5a03e763c4f56e2308c341d9a78eaff2 100644 (file)
@@ -58,3 +58,7 @@
 
 #define SYNTECH_VENDOR_ID      0x0745
 #define SYNTECH_PRODUCT_ID     0x0001
+
+/* Nokia CA-42 Cable */
+#define NOKIA_CA42_VENDOR_ID   0x078b
+#define NOKIA_CA42_PRODUCT_ID  0x1234
index d34dc9f417f0267f40d1927e3c7f0f8d8d481193..4837524eada7170049c78f61fdff0eab29fddd0a 100644 (file)
@@ -227,42 +227,42 @@ static int queuecommand(struct scsi_cmnd *srb,
  ***********************************************************************/
 
 /* Command timeout and abort */
-/* This is always called with scsi_lock(host) held */
 static int command_abort(struct scsi_cmnd *srb)
 {
        struct us_data *us = host_to_us(srb->device->host);
 
        US_DEBUGP("%s called\n", __FUNCTION__);
 
+       /* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
+        * bits are protected by the host lock. */
+       scsi_lock(us_to_host(us));
+
        /* Is this command still active? */
        if (us->srb != srb) {
+               scsi_unlock(us_to_host(us));
                US_DEBUGP ("-- nothing to abort\n");
                return FAILED;
        }
 
        /* Set the TIMED_OUT bit.  Also set the ABORTING bit, but only if
         * a device reset isn't already in progress (to avoid interfering
-        * with the reset).  To prevent races with auto-reset, we must
-        * stop any ongoing USB transfers while still holding the host
-        * lock. */
+        * with the reset).  Note that we must retain the host lock while
+        * calling usb_stor_stop_transport(); otherwise it might interfere
+        * with an auto-reset that begins as soon as we release the lock. */
        set_bit(US_FLIDX_TIMED_OUT, &us->flags);
        if (!test_bit(US_FLIDX_RESETTING, &us->flags)) {
                set_bit(US_FLIDX_ABORTING, &us->flags);
                usb_stor_stop_transport(us);
        }
+       scsi_unlock(us_to_host(us));
 
        /* Wait for the aborted command to finish */
        wait_for_completion(&us->notify);
-
-       /* Reacquire the lock and allow USB transfers to resume */
-       clear_bit(US_FLIDX_ABORTING, &us->flags);
-       clear_bit(US_FLIDX_TIMED_OUT, &us->flags);
        return SUCCESS;
 }
 
 /* This invokes the transport reset mechanism to reset the state of the
  * device */
-/* This is always called with scsi_lock(host) held */
 static int device_reset(struct scsi_cmnd *srb)
 {
        struct us_data *us = host_to_us(srb->device->host);
@@ -279,7 +279,6 @@ static int device_reset(struct scsi_cmnd *srb)
 }
 
 /* Simulate a SCSI bus reset by resetting the device's USB port. */
-/* This is always called with scsi_lock(host) held */
 static int bus_reset(struct scsi_cmnd *srb)
 {
        struct us_data *us = host_to_us(srb->device->host);
@@ -291,7 +290,6 @@ static int bus_reset(struct scsi_cmnd *srb)
        result = usb_stor_port_reset(us);
        up(&(us->dev_semaphore));
 
-       /* lock the host for the return */
        return result < 0 ? FAILED : SUCCESS;
 }
 
index ad0cfd7a782f2e8c5418d04c6e3f13563e9993f7..b79dad1b598c04365c9727d6b283e94e0cb881b7 100644 (file)
@@ -86,6 +86,16 @@ UNUSUAL_DEV(  0x040d, 0x6205, 0x0003, 0x0003,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net>
+ * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product)
+ * for USB floppies that need the SINGLE_LUN enforcement.
+ */
+UNUSUAL_DEV(  0x0409, 0x0040, 0x0000, 0x9999,
+               "NEC",
+               "NEC USB UF000x",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_SINGLE_LUN ),
+
 /* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
  * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
  * always fails and confuses drive.
@@ -96,6 +106,13 @@ UNUSUAL_DEV(  0x0411, 0x001c, 0x0113, 0x0113,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_INQUIRY ),
 
+/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
+UNUSUAL_DEV(  0x0424, 0x0fdc, 0x0210, 0x0210,
+               "SMSC",
+               "FDC GOLD-2.30",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_SINGLE_LUN ),
+
 #ifdef CONFIG_USB_STORAGE_DPCM
 UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
                "Microtech",
@@ -103,6 +120,24 @@ UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
                US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
 #endif
 
+/*
+ * Pete Zaitcev <zaitcev@yahoo.com>, from Patrick C. F. Ernzer, bz#162559.
+ * The key does not actually break, but it returns zero sense which
+ * makes our SCSI stack to print confusing messages.
+ */
+UNUSUAL_DEV(  0x0457, 0x0150, 0x0100, 0x0100,
+               "USBest Technology",    /* sold by Transcend */
+               "USB Mass Storage Device",
+               US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+
+/* Patch submitted by Daniel Drake <dsd@gentoo.org>
+ * Device reports nonsense bInterfaceProtocol 6 when connected over USB2 */
+UNUSUAL_DEV(  0x0451, 0x5416, 0x0100, 0x0100,
+               "Neuros Audio",
+               "USB 2.0 HD 2.5",
+               US_SC_DEVICE, US_PR_BULK, NULL,
+               US_FL_NEED_OVERRIDE ),
+
 /* Patch submitted by Philipp Friedrich <philipp@void.at> */
 UNUSUAL_DEV(  0x0482, 0x0100, 0x0100, 0x0100,
                "Kyocera",
index cb4c770baf32a52be5d5ced2f0a3db946c43c359..f9a9bfa1aef5be8d0181ea2ddc64d844e6c85d61 100644 (file)
@@ -392,11 +392,16 @@ SkipForAbort:
                /* If an abort request was received we need to signal that
                 * the abort has finished.  The proper test for this is
                 * the TIMED_OUT flag, not srb->result == DID_ABORT, because
-                * a timeout/abort request might be received after all the
-                * USB processing was complete. */
-               if (test_bit(US_FLIDX_TIMED_OUT, &us->flags))
+                * the timeout might have occurred after the command had
+                * already completed with a different result code. */
+               if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
                        complete(&(us->notify));
 
+                       /* Allow USB transfers to resume */
+                       clear_bit(US_FLIDX_ABORTING, &us->flags);
+                       clear_bit(US_FLIDX_TIMED_OUT, &us->flags);
+               }
+
                /* finished working on this command */
                us->srb = NULL;
                scsi_unlock(host);
index 615874e03ce8bbad26eab9f992b5a43632a02071..31ee13eef7afb34eb1a4c40756108ebb1c2ad2e8 100644 (file)
@@ -753,7 +753,8 @@ config FB_I810_GTF
 
 config FB_I810_I2C
        bool "Enable DDC Support"
-       depends on FB_I810 && I2C && FB_I810_GTF
+       depends on FB_I810 && FB_I810_GTF
+       select I2C
        select I2C_ALGOBIT
        help
 
index 353cb3f73cf2f6267dbaf2a8a625d261742828ce..a32817678552f61de175cd18302343be45a725a1 100644 (file)
@@ -43,18 +43,10 @@ static void corgibl_send_intensity(int intensity)
                        intensity &= CORGI_LIMIT_MASK;
        }
 
-       /* Skip 0x20 as it will blank the display */
-       if (intensity >= 0x20)
-               intensity++;
-
        spin_lock_irqsave(&bl_lock, flags);
-       /* Bits 0-4 are accessed via the SSP interface */
-       corgi_ssp_blduty_set(intensity & 0x1f);
-       /* Bit 5 is via SCOOP */
-       if (intensity & 0x0020)
-               set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
-       else
-               reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
+
+       corgibl_mach_set_intensity(intensity);
+
        spin_unlock_irqrestore(&bl_lock, flags);
 }
 
@@ -113,8 +105,8 @@ static int corgibl_get_power(struct backlight_device *bd)
 
 static int corgibl_set_intensity(struct backlight_device *bd, int intensity)
 {
-       if (intensity > CORGI_MAX_INTENSITY)
-               intensity = CORGI_MAX_INTENSITY;
+       if (intensity > corgibl_data.max_brightness)
+               intensity = corgibl_data.max_brightness;
        corgibl_send_intensity(intensity);
        current_intensity=intensity;
        return 0;
@@ -141,7 +133,6 @@ static struct backlight_properties corgibl_data = {
        .owner          = THIS_MODULE,
        .get_power      = corgibl_get_power,
        .set_power      = corgibl_set_power,
-       .max_brightness = CORGI_MAX_INTENSITY,
        .get_brightness = corgibl_get_intensity,
        .set_brightness = corgibl_set_intensity,
 };
@@ -150,12 +141,18 @@ static struct backlight_device *corgi_backlight_device;
 
 static int __init corgibl_probe(struct device *dev)
 {
+       struct corgibl_machinfo *machinfo = dev->platform_data;
+
+       corgibl_data.max_brightness = machinfo->max_intensity;
+       corgibl_mach_set_intensity = machinfo->set_bl_intensity;
+
        corgi_backlight_device = backlight_device_register ("corgi-bl",
                NULL, &corgibl_data);
        if (IS_ERR (corgi_backlight_device))
                return PTR_ERR (corgi_backlight_device);
 
        corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY);
+       corgibl_limit_intensity(0);
 
        printk("Corgi Backlight Driver Initialized.\n");
        return 0;
index 5fe182d6e4ab44bc09dc605b5980da37a915e67f..eb83a7874c71508798bac35e4205f1770edac560 100644 (file)
@@ -137,7 +137,7 @@ config FONT_8x8
 
 config FONT_8x16
        bool "VGA 8x16 font" if FONTS
-       depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y
+       depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || USB_SISUSBVGA_CON
        default y if !SPARC32 && !SPARC64 && !FONTS
        help
          This is the "high resolution" font for the VGA frame buffer (the one
index b562f6bb9d316d64addc4acc4934e83257bda83f..42c7b8dcd22073397da5f89bdf94ddc62dc71204 100644 (file)
@@ -33,6 +33,10 @@ endif
 
 obj-$(CONFIG_FB_STI)              += sticore.o font.o
 
+ifeq ($(CONFIG_USB_SISUSBVGA_CON),y)
+obj-$(CONFIG_USB_SISUSBVGA)           += font.o
+endif
+
 # Targets that kbuild needs to know about
 targets := promcon_tbl.c
 
index 2e93224d2d5509a14ce09ae25bd524e78f014742..0fc8bb499c3facf6f75c9ea4259cf62eaf876a13 100644 (file)
@@ -767,7 +767,7 @@ static const char *fbcon_startup(void)
        const char *display_desc = "frame buffer device";
        struct display *p = &fb_display[fg_console];
        struct vc_data *vc = vc_cons[fg_console].d;
-       struct font_desc *font = NULL;
+       const struct font_desc *font = NULL;
        struct module *owner;
        struct fb_info *info = NULL;
        struct fbcon_ops *ops;
@@ -841,7 +841,7 @@ static const char *fbcon_startup(void)
                                                info->var.yres);
                vc->vc_font.width = font->width;
                vc->vc_font.height = font->height;
-               vc->vc_font.data = p->fontdata = font->data;
+               vc->vc_font.data = (void *)(p->fontdata = font->data);
                vc->vc_font.charcount = 256; /* FIXME  Need to support more fonts */
        }
 
@@ -941,7 +941,7 @@ static void fbcon_init(struct vc_data *vc, int init)
           fb, copy the font from that console */
        t = &fb_display[svc->vc_num];
        if (!vc->vc_font.data) {
-               vc->vc_font.data = p->fontdata = t->fontdata;
+               vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
                vc->vc_font.width = (*default_mode)->vc_font.width;
                vc->vc_font.height = (*default_mode)->vc_font.height;
                p->userfont = t->userfont;
@@ -1188,7 +1188,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
                return;
        t = &fb_display[svc->vc_num];
        if (!vc->vc_font.data) {
-               vc->vc_font.data = p->fontdata = t->fontdata;
+               vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
                vc->vc_font.width = (*default_mode)->vc_font.width;
                vc->vc_font.height = (*default_mode)->vc_font.height;
                p->userfont = t->userfont;
@@ -1687,6 +1687,8 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
        case SM_DOWN:
                if (count > vc->vc_rows)        /* Maximum realistic size */
                        count = vc->vc_rows;
+               if (logo_shown >= 0)
+                       goto redraw_down;
                switch (p->scrollmode) {
                case SCROLL_MOVE:
                        ops->bmove(vc, info, t, 0, t + count, 0,
@@ -2148,7 +2150,7 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
 }
 
 static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
-                            u8 * data, int userfont)
+                            const u8 * data, int userfont)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct display *p = &fb_display[vc->vc_num];
@@ -2166,7 +2168,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
                cnt = FNTCHARCNT(data);
        else
                cnt = 256;
-       vc->vc_font.data = p->fontdata = data;
+       vc->vc_font.data = (void *)(p->fontdata = data);
        if ((p->userfont = userfont))
                REFCOUNT(data)++;
        vc->vc_font.width = w;
@@ -2323,7 +2325,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne
                    tmp->vc_font.width == w &&
                    !memcmp(fb_display[i].fontdata, new_data, size)) {
                        kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
-                       new_data = fb_display[i].fontdata;
+                       new_data = (u8 *)fb_display[i].fontdata;
                        break;
                }
        }
@@ -2333,7 +2335,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne
 static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
-       struct font_desc *f;
+       const struct font_desc *f;
 
        if (!name)
                f = get_default_font(info->var.xres, info->var.yres);
index 08befafe11d14c82f822f078e4fb50467dad2361..0738cd62def219f743c34b93586efeb9e033596d 100644 (file)
@@ -30,7 +30,7 @@ struct display {
     /* Filled in by the frame buffer device */
     u_short inverse;                /* != 0 text black on white as default */
     /* Filled in by the low-level console driver */
-    u_char *fontdata;
+    const u_char *fontdata;
     int userfont;                   /* != 0 if fontdata kmalloc()ed */
     u_short scrollmode;             /* Scroll Method */
     short yscroll;                  /* Hardware scrolling */
index ff0af96e4dfc47dc33268fef032364aee1007041..e6aa0eab5bb6b464c95b124d952fb52e5774c887 100644 (file)
@@ -7,7 +7,7 @@
 
 #define FONTDATAMAX 9216
 
-static unsigned char fontdata_10x18[FONTDATAMAX] = {
+static const unsigned char fontdata_10x18[FONTDATAMAX] = {
 
        /* 0 0x00 '^@' */
        0x00, 0x00, /* 0000000000 */
@@ -5132,7 +5132,7 @@ static unsigned char fontdata_10x18[FONTDATAMAX] = {
 };
 
 
-struct font_desc font_10x18 = {
+const struct font_desc font_10x18 = {
        FONT10x18_IDX,
        "10x18",
        10,
index c52f1294044a29145364c6375de641bdb5e82c96..89976cd97494eb74fbc059b2af9faf8f99cfa00a 100644 (file)
@@ -8,7 +8,7 @@
 
 #define FONTDATAMAX (11*256)
 
-static unsigned char fontdata_6x11[FONTDATAMAX] = {
+static const unsigned char fontdata_6x11[FONTDATAMAX] = {
 
        /* 0 0x00 '^@' */
        0x00, /* 00000000 */
@@ -3341,7 +3341,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
 };
 
 
-struct font_desc font_vga_6x11 = {
+const struct font_desc font_vga_6x11 = {
        VGA6x11_IDX,
        "ProFont6x11",
        6,
index 1fa7fcf2ff72aa8008da6e0c4aad458d1e9607d7..bbf1166473972a4410638669d85ad30d1a7daf25 100644 (file)
@@ -7,7 +7,7 @@
 
 #define FONTDATAMAX 3584
 
-static unsigned char fontdata_7x14[FONTDATAMAX] = {
+static const unsigned char fontdata_7x14[FONTDATAMAX] = {
 
        /* 0 0x00 '^@' */
        0x00, /* 0000000 */
@@ -4108,7 +4108,7 @@ static unsigned char fontdata_7x14[FONTDATAMAX] = {
 };
 
 
-struct font_desc font_7x14 = {
+const struct font_desc font_7x14 = {
        FONT7x14_IDX,
        "7x14",
        7,
index e6f8dbaa122bbc6ab37774e6caebf0f5973db12a..74fe86f28ff4644447476a4d701f61d3ab6b5b3a 100644 (file)
@@ -8,7 +8,7 @@
 
 #define FONTDATAMAX 4096
 
-static unsigned char fontdata_8x16[FONTDATAMAX] = {
+static const unsigned char fontdata_8x16[FONTDATAMAX] = {
 
        /* 0 0x00 '^@' */
        0x00, /* 00000000 */
@@ -4621,7 +4621,7 @@ static unsigned char fontdata_8x16[FONTDATAMAX] = {
 };
 
 
-struct font_desc font_vga_8x16 = {
+const struct font_desc font_vga_8x16 = {
        VGA8x16_IDX,
        "VGA8x16",
        8,
index 57fbe266a6b914d700f1f81cc5888ef5b4f63137..26199f8ee908103f0065eb12068832e4bf6f61f4 100644 (file)
@@ -8,7 +8,7 @@
 
 #define FONTDATAMAX 2048
 
-static unsigned char fontdata_8x8[FONTDATAMAX] = {
+static const unsigned char fontdata_8x8[FONTDATAMAX] = {
 
        /* 0 0x00 '^@' */
        0x00, /* 00000000 */
@@ -2573,7 +2573,7 @@ static unsigned char fontdata_8x8[FONTDATAMAX] = {
 };
 
 
-struct font_desc font_vga_8x8 = {
+const struct font_desc font_vga_8x8 = {
        VGA8x8_IDX,
        "VGA8x8",
        8,
index d565505e3069120926b8fe611c9927728a682cb6..2d2e39632e2d72032d402cc124b0baf22e8f2af3 100644 (file)
@@ -3,7 +3,7 @@
 #include <linux/config.h>
 #include <linux/font.h>
 
-static unsigned char acorndata_8x8[] = {
+static const unsigned char acorndata_8x8[] = {
 /* 00 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */
 /* 01 */  0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */
 /* 02 */  0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */
@@ -262,7 +262,7 @@ static unsigned char acorndata_8x8[] = {
 /* FF */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-struct font_desc font_acorn_8x8 = {
+const struct font_desc font_acorn_8x8 = {
        ACORN8x8_IDX,
        "Acorn8x8",
        8,
index 593b95500a0cc1fe1dc901831fff01ae710e868e..d818234fdf11e760b9dfb26c2df18259e0b06da9 100644 (file)
@@ -43,7 +43,7 @@ __END__;
 
 #define FONTDATAMAX 1536
 
-static unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
+static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
 
        /*{*/
                /*   Char 0: ' '  */
@@ -2147,7 +2147,7 @@ static unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
        /*}*/
 };
 
-struct font_desc font_mini_4x6 = {
+const struct font_desc font_mini_4x6 = {
        MINI4x6_IDX,
        "MINI4x6",
        4,
index 5fa95f1188180ace14353acd1095ff843f59c6ea..e646c88f55c7b245c98cc19f1350ec49f3a78d74 100644 (file)
@@ -13,7 +13,7 @@
 
 #define FONTDATAMAX 2048
 
-static unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
+static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
 
    /* 0 0x00 '^@' */
    0x00, /* 00000000 */
@@ -2577,7 +2577,7 @@ static unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
 
 };
 
-struct font_desc font_pearl_8x8 = {
+const struct font_desc font_pearl_8x8 = {
        PEARL8x8_IDX,
        "PEARL8x8",
        8,
index c7bd967ea1000ed91ec4f73a73dbec2d0e8c7fbb..ab5eb93407b4c9820f6851531c4d181439990f13 100644 (file)
@@ -2,7 +2,7 @@
 
 #define FONTDATAMAX 11264
 
-static unsigned char fontdata_sun12x22[FONTDATAMAX] = {
+static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
 
        /* 0 0x00 '^@' */
        0x00, 0x00, /* 000000000000 */
@@ -6151,7 +6151,7 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = {
 };
 
 
-struct font_desc font_sun_12x22 = {
+const struct font_desc font_sun_12x22 = {
        SUN12x22_IDX,
        "SUN12x22",
        12,
index 2af3ab354652973b0021175f04f1aba2fd384eae..41f910f5529c95ebc83493f2f92e72dc82413a18 100644 (file)
@@ -2,7 +2,7 @@
 
 #define FONTDATAMAX 4096
 
-static unsigned char fontdata_sun8x16[FONTDATAMAX] = {
+static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
 /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
 /* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
@@ -261,7 +261,7 @@ static unsigned char fontdata_sun8x16[FONTDATAMAX] = {
 /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 };
 
-struct font_desc font_sun_8x16 = {
+const struct font_desc font_sun_8x16 = {
        SUN8x16_IDX,
        "SUN8x16",
        8,
index e79b297026490531dc39fdd4767f7ca319aa4772..4fd07d9eca039d062c9968c452757f952b962a7e 100644 (file)
@@ -23,7 +23,7 @@
 
 #define NO_FONTS
 
-static struct font_desc *fonts[] = {
+static const struct font_desc *fonts[] = {
 #ifdef CONFIG_FONT_8x8
 #undef NO_FONTS
     &font_vga_8x8,
@@ -84,7 +84,7 @@ static struct font_desc *fonts[] = {
  *
  */
 
-struct font_desc *find_font(char *name)
+const struct font_desc *find_font(const char *name)
 {
    unsigned int i;
 
@@ -108,10 +108,10 @@ struct font_desc *find_font(char *name)
  *
  */
 
-struct font_desc *get_default_font(int xres, int yres)
+const struct font_desc *get_default_font(int xres, int yres)
 {
     int i, c, cc;
-    struct font_desc *f, *g;
+    const struct font_desc *f, *g;
 
     g = NULL;
     cc = -10000;
@@ -138,7 +138,6 @@ struct font_desc *get_default_font(int xres, int yres)
     return g;
 }
 
-EXPORT_SYMBOL(fonts);
 EXPORT_SYMBOL(find_font);
 EXPORT_SYMBOL(get_default_font);
 
index 7018ffffcbc4e391f8dbc8076a072ed59f865f82..0dbc9ddb6766e78eba0b1b58f5e5eb0c57d0051b 100644 (file)
@@ -95,18 +95,18 @@ static struct pci_driver i810fb_driver = {
 static char *mode_option __devinitdata = NULL;
 static int vram       __devinitdata = 4;
 static int bpp        __devinitdata = 8;
-static int mtrr       __devinitdata = 0;
-static int accel      __devinitdata = 0;
-static int hsync1     __devinitdata = 0;
-static int hsync2     __devinitdata = 0;
-static int vsync1     __devinitdata = 0;
-static int vsync2     __devinitdata = 0;
-static int xres       __devinitdata = 640;
-static int yres       __devinitdata = 480;
-static int vyres      __devinitdata = 0;
-static int sync       __devinitdata = 0;
-static int ext_vga    __devinitdata = 0;
-static int dcolor     __devinitdata = 0;
+static int mtrr       __devinitdata;
+static int accel      __devinitdata;
+static int hsync1     __devinitdata;
+static int hsync2     __devinitdata;
+static int vsync1     __devinitdata;
+static int vsync2     __devinitdata;
+static int xres       __devinitdata;
+static int yres       __devinitdata;
+static int vyres      __devinitdata;
+static int sync       __devinitdata;
+static int extvga     __devinitdata;
+static int dcolor     __devinitdata;
 
 /*------------------------------------------------------------*/
 
@@ -950,7 +950,7 @@ static int i810_check_params(struct fb_var_screeninfo *var,
                             struct fb_info *info)
 {
        struct i810fb_par *par = (struct i810fb_par *) info->par;
-       int line_length, vidmem, mode_valid = 0;
+       int line_length, vidmem, mode_valid = 0, retval = 0;
        u32 vyres = var->yres_virtual, vxres = var->xres_virtual;
        /*
         *  Memory limit
@@ -1026,10 +1026,11 @@ static int i810_check_params(struct fb_var_screeninfo *var,
                        printk("i810fb: invalid video mode%s\n",
                               default_sync ? "" : ". Specifying "
                               "vsyncN/hsyncN parameters may help");
+                       retval = -EINVAL;
                }
        }
 
-       return 0;
+       return retval;
 }      
 
 /**
@@ -1724,12 +1725,21 @@ static void __devinit i810_init_defaults(struct i810fb_par *par,
        if (bpp < 8)
                bpp = 8;
        
+       par->i810fb_ops = i810fb_ops;
+
+       if (xres)
+               info->var.xres = xres;
+       else
+               info->var.xres = 640;
+
+       if (yres)
+               info->var.yres = yres;
+       else
+               info->var.yres = 480;
+
        if (!vyres) 
-               vyres = (vram << 20)/(xres*bpp >> 3);
+               vyres = (vram << 20)/(info->var.xres*bpp >> 3);
 
-       par->i810fb_ops = i810fb_ops;
-       info->var.xres = xres;
-       info->var.yres = yres;
        info->var.yres_virtual = vyres;
        info->var.bits_per_pixel = bpp;
 
@@ -1756,7 +1766,7 @@ static void __devinit i810_init_device(struct i810fb_par *par)
        i810_init_cursor(par);
 
        /* mvo: enable external vga-connector (for laptops) */
-       if (ext_vga) {
+       if (extvga) {
                i810_writel(HVSYNC, mmio, 0);
                i810_writel(PWR_CLKC, mmio, 3);
        }
@@ -1830,7 +1840,7 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info)
 {
        struct fb_videomode mode;
        struct fb_var_screeninfo var;
-       struct fb_monspecs *specs = NULL;
+       struct fb_monspecs *specs = &info->monspecs;
        int found = 0;
 #ifdef CONFIG_FB_I810_I2C
        int i;
@@ -1853,16 +1863,24 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info)
        if (!err)
                printk("i810fb_init_pci: DDC probe successful\n");
 
-       fb_edid_to_monspecs(par->edid, &info->monspecs);
+       fb_edid_to_monspecs(par->edid, specs);
 
-       if (info->monspecs.modedb == NULL)
+       if (specs->modedb == NULL)
                printk("i810fb_init_pci: Unable to get Mode Database\n");
 
-       specs = &info->monspecs;
        fb_videomode_to_modelist(specs->modedb, specs->modedb_len,
                                 &info->modelist);
        if (specs->modedb != NULL) {
-               if (specs->misc & FB_MISC_1ST_DETAIL) {
+               if (xres && yres) {
+                       struct fb_videomode *m;
+
+                       if ((m = fb_find_best_mode(&var, &info->modelist))) {
+                               mode = *m;
+                               found  = 1;
+                       }
+               }
+
+               if (!found && specs->misc & FB_MISC_1ST_DETAIL) {
                        for (i = 0; i < specs->modedb_len; i++) {
                                if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
                                        mode = specs->modedb[i];
@@ -1903,8 +1921,8 @@ static int __devinit i810fb_setup(char *options)
                        mtrr = 1;
                else if (!strncmp(this_opt, "accel", 5))
                        accel = 1;
-               else if (!strncmp(this_opt, "ext_vga", 7))
-                       ext_vga = 1;
+               else if (!strncmp(this_opt, "extvga", 6))
+                       extvga = 1;
                else if (!strncmp(this_opt, "sync", 4))
                        sync = 1;
                else if (!strncmp(this_opt, "vram:", 5))
@@ -2133,8 +2151,8 @@ module_param(accel, bool, 0);
 MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)");
 module_param(mtrr, bool, 0);
 MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)");
-module_param(ext_vga, bool, 0);
-MODULE_PARM_DESC(ext_vga, "Enable external VGA connector (default = 0)");
+module_param(extvga, bool, 0);
+MODULE_PARM_DESC(extvga, "Enable external VGA connector (default = 0)");
 module_param(sync, bool, 0);
 MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing"
                 " (default = 0)");
index 98e00d8601e5be9c210351b4fd4a7d4599cb7773..e02da41f1b262b9cb780dd19d4d36767ccdbe357 100644 (file)
@@ -1285,7 +1285,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi
        vaddr_t vm;
        unsigned int offs;
        unsigned int offs2;
-       unsigned char store;
+       unsigned char store, orig;
        unsigned char bytes[32];
        unsigned char* tmp;
 
@@ -1298,7 +1298,8 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi
        if (maxSize > 0x2000000) maxSize = 0x2000000;
 
        mga_outb(M_EXTVGA_INDEX, 0x03);
-       mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
+       orig = mga_inb(M_EXTVGA_DATA);
+       mga_outb(M_EXTVGA_DATA, orig | 0x80);
 
        store = mga_readb(vm, 0x1234);
        tmp = bytes;
@@ -1323,7 +1324,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi
        mga_writeb(vm, 0x1234, store);
 
        mga_outb(M_EXTVGA_INDEX, 0x03);
-       mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
+       mga_outb(M_EXTVGA_DATA, orig);
 
        *realSize = offs - 0x100000;
 #ifdef CONFIG_FB_MATROX_MILLENIUM
@@ -1858,6 +1859,8 @@ static int initMatrox2(WPMINFO struct board* b){
                                                        to yres_virtual * xres_virtual < 2^32 */
        }
        matroxfb_init_fix(PMINFO2);
+       ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase));
+       matroxfb_update_fix(PMINFO2);
        /* Normalize values (namely yres_virtual) */
        matroxfb_check_var(&vesafb_defined, &ACCESS_FBINFO(fbcon));
        /* And put it into "current" var. Do NOT program hardware yet, or we'll not take over
@@ -2010,11 +2013,11 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
        }
        /* not match... */
        if (!b->vendor)
-               return -1;
+               return -ENODEV;
        if (dev > 0) {
                /* not requested one... */
                dev--;
-               return -1;
+               return -ENODEV;
        }
        pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
        if (pci_enable_device(pdev)) {
index e0dad948467b32cc921f742f5abbefb5d28b4674..2e11b601c488cb63f4e0d815f258d03cda74bf12 100644 (file)
@@ -67,6 +67,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
+#include <linux/ctype.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-mfb.h>
@@ -2594,7 +2595,7 @@ static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
 {
        char *next;
 
-       if (!(CHAR_IS_NUM(options[0]))) {
+       if (!(isdigit(options[0]))) {
                (*bn) = 0;
                return (options);
        }
index b7c24b34d270db1129009b374d52710a012c0287..279e0e0363d6afb7e7326da42381d6c36c5e37f4 100644 (file)
 #include <linux/delay.h>
 #ifdef CONFIG_W1_F23_CRC
 #include <linux/crc16.h>
+
+#define CRC16_INIT             0
+#define CRC16_VALID            0xb001
+
 #endif
 
 #include "w1.h"
@@ -214,7 +218,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
 #ifdef CONFIG_W1_F23_CRC
        /* can only write full blocks in cached mode */
        if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) {
-               dev_err(&sl->dev, "invalid offset/count off=%d cnt=%d\n",
+               dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n",
                        (int)off, count);
                return -EINVAL;
        }
index e08edc17c6a038d7f78791c2f7d175e729ec903b..361b4007d4a00867059e885855e26549ea702da3 100644 (file)
@@ -162,7 +162,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
 
 
 static inline int
-nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner)
 {
        int status;
        dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
@@ -238,8 +238,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
         */
        status = nfsd4_process_open2(rqstp, current_fh, open);
 out:
-       if (open->op_stateowner)
+       if (open->op_stateowner) {
                nfs4_get_stateowner(open->op_stateowner);
+               *replay_owner = open->op_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -809,8 +811,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                        op->status = nfsd4_access(rqstp, current_fh, &op->u.access);
                        break;
                case OP_CLOSE:
-                       op->status = nfsd4_close(rqstp, current_fh, &op->u.close);
-                       replay_owner = op->u.close.cl_stateowner;
+                       op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner);
                        break;
                case OP_COMMIT:
                        op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit);
@@ -831,15 +832,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                        op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link);
                        break;
                case OP_LOCK:
-                       op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock);
-                       replay_owner = op->u.lock.lk_stateowner;
+                       op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner);
                        break;
                case OP_LOCKT:
                        op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt);
                        break;
                case OP_LOCKU:
-                       op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku);
-                       replay_owner = op->u.locku.lu_stateowner;
+                       op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner);
                        break;
                case OP_LOOKUP:
                        op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup);
@@ -853,16 +852,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                                op->status = nfs_ok;
                        break;
                case OP_OPEN:
-                       op->status = nfsd4_open(rqstp, current_fh, &op->u.open);
-                       replay_owner = op->u.open.op_stateowner;
+                       op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner);
                        break;
                case OP_OPEN_CONFIRM:
-                       op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm);
-                       replay_owner = op->u.open_confirm.oc_stateowner;
+                       op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner);
                        break;
                case OP_OPEN_DOWNGRADE:
-                       op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade);
-                       replay_owner = op->u.open_downgrade.od_stateowner;
+                       op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner);
                        break;
                case OP_PUTFH:
                        op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh);
index b83f8fb441e15328ed9cff30099a7f637151124d..6bbefd06f10dea127ee0bf406eb1ef01fcfd4247 100644 (file)
@@ -624,7 +624,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
        cb->cb_ident = se->se_callback_ident;
        return;
 out_err:
-       printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
+       dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
                "will not receive delegations\n",
                clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
 
@@ -678,13 +678,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
        int                     status;
        char                    dname[HEXDIR_LEN];
        
-       status = nfserr_inval;
        if (!check_name(clname))
-               goto out;
+               return nfserr_inval;
 
        status = nfs4_make_rec_clidname(dname, &clname);
        if (status)
-               goto out;
+               return status;
 
        /* 
         * XXX The Duplicate Request Cache (DRC) has been checked (??)
@@ -2014,7 +2013,7 @@ STALE_STATEID(stateid_t *stateid)
 {
        if (stateid->si_boot == boot_time)
                return 0;
-       printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
+       dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
                stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
                stateid->si_generation);
        return 1;
@@ -2275,7 +2274,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
 
 check_replay:
        if (seqid == sop->so_seqid - 1) {
-               printk("NFSD: preprocess_seqid_op: retransmission?\n");
+               dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
                /* indicate replay to calling function */
                return NFSERR_REPLAY_ME;
        }
@@ -2286,7 +2285,7 @@ check_replay:
 }
 
 int
-nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
+nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner)
 {
        int status;
        struct nfs4_stateowner *sop;
@@ -2320,8 +2319,10 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
 
        nfsd4_create_clid_dir(sop->so_client);
 out:
-       if (oc->oc_stateowner)
+       if (oc->oc_stateowner) {
                nfs4_get_stateowner(oc->oc_stateowner);
+               *replay_owner = oc->oc_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -2352,7 +2353,7 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
 }
 
 int
-nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
+nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner)
 {
        int status;
        struct nfs4_stateid *stp;
@@ -2394,8 +2395,10 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n
        memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
        status = nfs_ok;
 out:
-       if (od->od_stateowner)
+       if (od->od_stateowner) {
                nfs4_get_stateowner(od->od_stateowner);
+               *replay_owner = od->od_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -2404,7 +2407,7 @@ out:
  * nfs4_unlock_state() called after encode
  */
 int
-nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
+nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner)
 {
        int status;
        struct nfs4_stateid *stp;
@@ -2430,8 +2433,10 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos
        /* release_state_owner() calls nfsd_close() if needed */
        release_state_owner(stp, OPEN_STATE);
 out:
-       if (close->cl_stateowner)
+       if (close->cl_stateowner) {
                nfs4_get_stateowner(close->cl_stateowner);
+               *replay_owner = close->cl_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -2500,8 +2505,7 @@ find_stateid(stateid_t *stid, int flags)
                            (local->st_stateid.si_fileid == f_id))
                                return local;
                }
-       } else
-               printk("NFSD: find_stateid: ERROR: no state flag\n");
+       }
        return NULL;
 }
 
@@ -2624,7 +2628,9 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
        sop->so_is_open_owner = 0;
        sop->so_id = current_ownerid++;
        sop->so_client = clp;
-       sop->so_seqid = lock->lk_new_lock_seqid;
+       /* It is the openowner seqid that will be incremented in encode in the
+        * case of new lockowners; so increment the lock seqid manually: */
+       sop->so_seqid = lock->lk_new_lock_seqid + 1;
        sop->so_confirmed = 1;
        rp = &sop->so_replay;
        rp->rp_status = NFSERR_SERVERFAULT;
@@ -2676,9 +2682,10 @@ check_lock_length(u64 offset, u64 length)
  *  LOCK operation 
  */
 int
-nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
+nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner)
 {
        struct nfs4_stateowner *open_sop = NULL;
+       struct nfs4_stateowner *lock_sop = NULL;
        struct nfs4_stateid *lock_stp;
        struct file *filp;
        struct file_lock file_lock;
@@ -2705,19 +2712,19 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                struct nfs4_file *fp;
                
                status = nfserr_stale_clientid;
-               if (STALE_CLIENTID(&lock->lk_new_clientid)) {
-                       printk("NFSD: nfsd4_lock: clientid is stale!\n");
+               if (STALE_CLIENTID(&lock->lk_new_clientid))
                        goto out;
-               }
 
                /* validate and update open stateid and open seqid */
                status = nfs4_preprocess_seqid_op(current_fh, 
                                        lock->lk_new_open_seqid,
                                        &lock->lk_new_open_stateid,
                                        CHECK_FH | OPEN_STATE,
-                                       &open_sop, &open_stp, lock);
+                                       &lock->lk_stateowner, &open_stp,
+                                       lock);
                if (status)
                        goto out;
+               open_sop = lock->lk_stateowner;
                /* create lockowner and lock stateid */
                fp = open_stp->st_file;
                strhashval = lock_ownerstr_hashval(fp->fi_inode, 
@@ -2727,16 +2734,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                 * the same file, or should they just be allowed (and
                 * create new stateids)? */
                status = nfserr_resource;
-               if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
+               lock_sop = alloc_init_lock_stateowner(strhashval,
+                               open_sop->so_client, open_stp, lock);
+               if (lock_sop == NULL)
                        goto out;
-               if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, 
-                                               fp, open_stp)) == NULL) {
-                       release_stateowner(lock->lk_stateowner);
-                       lock->lk_stateowner = NULL;
+               lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
+               if (lock_stp == NULL) {
+                       release_stateowner(lock_sop);
                        goto out;
                }
-               /* bump the open seqid used to create the lock */
-               open_sop->so_seqid++;
        } else {
                /* lock (lock owner + lock stateid) already exists */
                status = nfs4_preprocess_seqid_op(current_fh,
@@ -2746,12 +2752,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                                       &lock->lk_stateowner, &lock_stp, lock);
                if (status)
                        goto out;
+               lock_sop = lock->lk_stateowner;
        }
        /* lock->lk_stateowner and lock_stp have been created or found */
        filp = lock_stp->st_vfs_file;
 
        if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {
-               printk("NFSD: nfsd4_lock: permission denied!\n");
+               dprintk("NFSD: nfsd4_lock: permission denied!\n");
                goto out;
        }
 
@@ -2776,7 +2783,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                        status = nfserr_inval;
                goto out;
        }
-       file_lock.fl_owner = (fl_owner_t) lock->lk_stateowner;
+       file_lock.fl_owner = (fl_owner_t)lock_sop;
        file_lock.fl_pid = current->tgid;
        file_lock.fl_file = filp;
        file_lock.fl_flags = FL_POSIX;
@@ -2832,14 +2839,13 @@ out_destroy_new_stateid:
                 * An error encountered after instantiation of the new
                 * stateid has forced us to destroy it.
                 */
-               if (!seqid_mutating_err(status))
-                       open_sop->so_seqid--;
-
                release_state_owner(lock_stp, LOCK_STATE);
        }
 out:
-       if (lock->lk_stateowner)
+       if (lock->lk_stateowner) {
                nfs4_get_stateowner(lock->lk_stateowner);
+               *replay_owner = lock->lk_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -2866,13 +2872,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
        nfs4_lock_state();
 
        status = nfserr_stale_clientid;
-       if (STALE_CLIENTID(&lockt->lt_clientid)) {
-               printk("NFSD: nfsd4_lockt: clientid is stale!\n");
+       if (STALE_CLIENTID(&lockt->lt_clientid))
                goto out;
-       }
 
        if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) {
-               printk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
+               dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
                if (status == nfserr_symlink)
                        status = nfserr_inval;
                goto out;
@@ -2930,7 +2934,7 @@ out:
 }
 
 int
-nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku)
+nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner)
 {
        struct nfs4_stateid *stp;
        struct file *filp = NULL;
@@ -2976,7 +2980,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
        if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
                file_lock.fl_ops->fl_release_private(&file_lock);
        if (status) {
-               printk("NFSD: nfs4_locku: posix_lock_file failed!\n");
+               dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
                goto out_nfserr;
        }
        /*
@@ -2986,8 +2990,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
        memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));
 
 out:
-       if (locku->lu_stateowner)
+       if (locku->lu_stateowner) {
                nfs4_get_stateowner(locku->lu_stateowner);
+               *replay_owner = locku->lu_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 
@@ -3036,10 +3042,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
        /* XXX check for lease expiration */
 
        status = nfserr_stale_clientid;
-       if (STALE_CLIENTID(clid)) {
-               printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n");
+       if (STALE_CLIENTID(clid))
                return status;
-       }
 
        nfs4_lock_state();
 
index e4fd6134244dd0f93290c3653ab56a3e4b4e1d12..49eafbdb15c145e1884945e8aae5e1a74d0e3ed0 100644 (file)
@@ -34,9 +34,6 @@ ToDo/Notes:
          journals with two different restart pages.  We sanity check both and
          either use the only sane one or the more recent one of the two in the
          case that both are valid.
-       - Modify fs/ntfs/malloc.h::ntfs_malloc_nofs() to do the kmalloc() based
-         allocations with __GFP_HIGHMEM, analogous to how the vmalloc() based
-         allocations are done.
        - Add fs/ntfs/malloc.h::ntfs_malloc_nofs_nofail() which is analogous to
          ntfs_malloc_nofs() but it performs allocations with __GFP_NOFAIL and
          hence cannot fail.
@@ -90,7 +87,11 @@ ToDo/Notes:
          in the first buffer head instead of a driver global spin lock to
          improve scalability.
        - Minor fix to error handling and error message display in
-         fs/ntfs/aops.c::ntfs_prepare_nonresident_write(). 
+         fs/ntfs/aops.c::ntfs_prepare_nonresident_write().
+       - Change the mount options {u,f,d}mask to always parse the number as
+         an octal number to conform to how chmod(1) works, too.  Thanks to
+         Giuseppe Bilotta and Horst von Brand for pointing out the errors of
+         my ways.
 
 2.1.23 - Implement extension of resident files and make writing safe as well as
         many bug fixes, cleanups, and enhancements...
index 9994e019a3cfa958216899ffeae4ebbca3c4db54..3288bcc2c4aa162190316277f9c6aefa4f128216 100644 (file)
@@ -45,7 +45,7 @@ static inline void *__ntfs_malloc(unsigned long size,
        if (likely(size <= PAGE_SIZE)) {
                BUG_ON(!size);
                /* kmalloc() has per-CPU caches so is faster for now. */
-               return kmalloc(PAGE_SIZE, gfp_mask);
+               return kmalloc(PAGE_SIZE, gfp_mask & ~__GFP_HIGHMEM);
                /* return (void *)__get_free_page(gfp_mask); */
        }
        if (likely(size >> PAGE_SHIFT < num_physpages))
index b2b392961268fdefebc7b054d6149ceed78d57c9..453d0d51ea4bc4d9b731e48345db0e45bb034b24 100644 (file)
@@ -126,6 +126,14 @@ static BOOL parse_options(ntfs_volume *vol, char *opt)
                if (*v)                                                 \
                        goto needs_val;                                 \
        }
+#define NTFS_GETOPT_OCTAL(option, variable)                            \
+       if (!strcmp(p, option)) {                                       \
+               if (!v || !*v)                                          \
+                       goto needs_arg;                                 \
+               variable = simple_strtoul(ov = v, &v, 8);               \
+               if (*v)                                                 \
+                       goto needs_val;                                 \
+       }
 #define NTFS_GETOPT_BOOL(option, variable)                             \
        if (!strcmp(p, option)) {                                       \
                BOOL val;                                               \
@@ -157,9 +165,9 @@ static BOOL parse_options(ntfs_volume *vol, char *opt)
                        *v++ = 0;
                NTFS_GETOPT("uid", uid)
                else NTFS_GETOPT("gid", gid)
-               else NTFS_GETOPT("umask", fmask = dmask)
-               else NTFS_GETOPT("fmask", fmask)
-               else NTFS_GETOPT("dmask", dmask)
+               else NTFS_GETOPT_OCTAL("umask", fmask = dmask)
+               else NTFS_GETOPT_OCTAL("fmask", fmask)
+               else NTFS_GETOPT_OCTAL("dmask", dmask)
                else NTFS_GETOPT("mft_zone_multiplier", mft_zone_multiplier)
                else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, TRUE)
                else NTFS_GETOPT_BOOL("show_sys_files", show_sys_files)
index 2fac58c51910cf250607a8f7161edc608d8c18cc..f0d90cf0495c490316d427e309c38695ceb4e005 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -738,52 +738,15 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
        return error;
 }
 
-/*
- * Note that while the flag value (low two bits) for sys_open means:
- *     00 - read-only
- *     01 - write-only
- *     10 - read-write
- *     11 - special
- * it is changed into
- *     00 - no permissions needed
- *     01 - read-permission
- *     10 - write-permission
- *     11 - read-write
- * for the internal routines (ie open_namei()/follow_link() etc). 00 is
- * used by symlinks.
- */
-struct file *filp_open(const char * filename, int flags, int mode)
-{
-       int namei_flags, error;
-       struct nameidata nd;
-
-       namei_flags = flags;
-       if ((namei_flags+1) & O_ACCMODE)
-               namei_flags++;
-       if (namei_flags & O_TRUNC)
-               namei_flags |= 2;
-
-       error = open_namei(filename, namei_flags, mode, &nd);
-       if (!error)
-               return dentry_open(nd.dentry, nd.mnt, flags);
-
-       return ERR_PTR(error);
-}
-
-EXPORT_SYMBOL(filp_open);
-
-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
+static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
+                                       int flags, struct file *f)
 {
-       struct file * f;
        struct inode *inode;
        int error;
 
-       error = -ENFILE;
-       f = get_empty_filp();
-       if (!f)
-               goto cleanup_dentry;
        f->f_flags = flags;
-       f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
+       f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK |
+                               FMODE_PREAD | FMODE_PWRITE;
        inode = dentry->d_inode;
        if (f->f_mode & FMODE_WRITE) {
                error = get_write_access(inode);
@@ -828,12 +791,63 @@ cleanup_all:
        f->f_vfsmnt = NULL;
 cleanup_file:
        put_filp(f);
-cleanup_dentry:
        dput(dentry);
        mntput(mnt);
        return ERR_PTR(error);
 }
 
+/*
+ * Note that while the flag value (low two bits) for sys_open means:
+ *     00 - read-only
+ *     01 - write-only
+ *     10 - read-write
+ *     11 - special
+ * it is changed into
+ *     00 - no permissions needed
+ *     01 - read-permission
+ *     10 - write-permission
+ *     11 - read-write
+ * for the internal routines (ie open_namei()/follow_link() etc). 00 is
+ * used by symlinks.
+ */
+struct file *filp_open(const char * filename, int flags, int mode)
+{
+       int namei_flags, error;
+       struct nameidata nd;
+       struct file *f;
+
+       namei_flags = flags;
+       if ((namei_flags+1) & O_ACCMODE)
+               namei_flags++;
+       if (namei_flags & O_TRUNC)
+               namei_flags |= 2;
+
+       error = -ENFILE;
+       f = get_empty_filp();
+       if (f == NULL)
+               return ERR_PTR(error);
+
+       error = open_namei(filename, namei_flags, mode, &nd);
+       if (!error)
+               return __dentry_open(nd.dentry, nd.mnt, flags, f);
+
+       put_filp(f);
+       return ERR_PTR(error);
+}
+EXPORT_SYMBOL(filp_open);
+
+struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
+{
+       int error;
+       struct file *f;
+
+       error = -ENFILE;
+       f = get_empty_filp();
+       if (f == NULL)
+               return ERR_PTR(error);
+
+       return __dentry_open(dentry, mnt, flags, f);
+}
 EXPORT_SYMBOL(dentry_open);
 
 /*
index c9f178fb494f511207ca93b982e599f62d7f481d..c20babd6216d970bdb1fbf2c879cab4de7341d2f 100644 (file)
@@ -667,7 +667,7 @@ static int reiserfs_allocate_blocks_for_region(struct reiserfs_transaction_handl
        if (th->t_trans_id) {
                int err;
                // update any changes we made to blk count
-               reiserfs_update_sd(th, inode);
+               mark_inode_dirty(inode);
                err =
                    journal_end(th, inode->i_sb,
                                JOURNAL_PER_BALANCE_CNT * 3 + 1 +
@@ -855,17 +855,18 @@ static int reiserfs_submit_file_region_for_write(struct reiserfs_transaction_han
 
                if (th->t_trans_id) {
                        reiserfs_write_lock(inode->i_sb);
-                       reiserfs_update_sd(th, inode);  // And update on-disk metadata
+                       // this sets the proper flags for O_SYNC to trigger a commit
+                       mark_inode_dirty(inode);
                        reiserfs_write_unlock(inode->i_sb);
                } else
-                       inode->i_sb->s_op->dirty_inode(inode);
+                       mark_inode_dirty(inode);
 
                sd_update = 1;
        }
        if (th->t_trans_id) {
                reiserfs_write_lock(inode->i_sb);
                if (!sd_update)
-                       reiserfs_update_sd(th, inode);
+                       mark_inode_dirty(inode);
                status = journal_end(th, th->t_super, th->t_blocks_allocated);
                if (status)
                        retval = status;
@@ -1320,7 +1321,7 @@ static ssize_t reiserfs_file_write(struct file *file,     /* the file we are going t
                                return err;
                        }
                        reiserfs_update_inode_transaction(inode);
-                       reiserfs_update_sd(&th, inode);
+                       mark_inode_dirty(inode);
                        err = journal_end(&th, inode->i_sb, 1);
                        if (err) {
                                reiserfs_write_unlock(inode->i_sb);
index 1a8a1bf2154d10475a0bacc89b085070587d48d6..d76ee6c4f9b8874f1a26acdaa37a9fe9d693e490 100644 (file)
@@ -2639,6 +2639,12 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
                }
                reiserfs_update_inode_transaction(inode);
                inode->i_size = pos;
+               /*
+                * this will just nest into our transaction.  It's important
+                * to use mark_inode_dirty so the inode gets pushed around on the
+                * dirty lists, and so that O_SYNC works as expected
+                */
+               mark_inode_dirty(inode);
                reiserfs_update_sd(&myth, inode);
                update_sd = 1;
                ret = journal_end(&myth, inode->i_sb, 1);
@@ -2649,21 +2655,13 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
        if (th) {
                reiserfs_write_lock(inode->i_sb);
                if (!update_sd)
-                       reiserfs_update_sd(th, inode);
+                       mark_inode_dirty(inode);
                ret = reiserfs_end_persistent_transaction(th);
                reiserfs_write_unlock(inode->i_sb);
                if (ret)
                        goto out;
        }
 
-       /* we test for O_SYNC here so we can commit the transaction
-        ** for any packed tails the file might have had
-        */
-       if (f && (f->f_flags & O_SYNC)) {
-               reiserfs_write_lock(inode->i_sb);
-               ret = reiserfs_commit_for_inode(inode);
-               reiserfs_write_unlock(inode->i_sb);
-       }
       out:
        return ret;
 
index 22b53e369f5999632f19924aa4c620139c694b61..8393bf374b2b59c85bd90c60440322bacd4c8426 100644 (file)
@@ -339,13 +339,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 #define kern_addr_valid(addr)  (1)
 #endif
 
-#define io_remap_page_range(vma, start, busaddr, size, prot)   \
-({                                                             \
-       void *va = (void __force *)ioremap(busaddr, size);      \
-       unsigned long pfn = virt_to_phys(va) >> PAGE_SHIFT;     \
-       remap_pfn_range(vma, start, pfn, size, prot);           \
-})
-
 #define io_remap_pfn_range(vma, start, pfn, size, prot)        \
                remap_pfn_range(vma, start, pfn, size, prot)
 
diff --git a/include/asm-arm/arch-pxa/akita.h b/include/asm-arm/arch-pxa/akita.h
new file mode 100644 (file)
index 0000000..4a1fbcf
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Hardware specific definitions for SL-C1000 (Akita)
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/* Akita IO Expander GPIOs */
+
+#define AKITA_IOEXP_RESERVED_7      (1 << 7)
+#define AKITA_IOEXP_IR_ON           (1 << 6)
+#define AKITA_IOEXP_AKIN_PULLUP     (1 << 5)
+#define AKITA_IOEXP_BACKLIGHT_CONT  (1 << 4)
+#define AKITA_IOEXP_BACKLIGHT_ON    (1 << 3)
+#define AKITA_IOEXP_MIC_BIAS        (1 << 2)
+#define AKITA_IOEXP_RESERVED_1      (1 << 1)
+#define AKITA_IOEXP_RESERVED_0      (1 << 0)
+
+/* Direction Bitfield  0=output  1=input */
+#define AKITA_IOEXP_IO_DIR     0
+/* Default Values */
+#define AKITA_IOEXP_IO_OUT     (AKITA_IOEXP_IR_ON | AKITA_IOEXP_AKIN_PULLUP)
+
+void akita_set_ioexp(struct device *dev, unsigned char bitmask);
+void akita_reset_ioexp(struct device *dev, unsigned char bitmask);
+
index 4b7aa0b8391e0741aab1fcee845ff1cc919421e1..e554caa0d18b02030fb87bae0048c7fc0e257f11 100644 (file)
@@ -106,17 +106,5 @@ extern struct platform_device corgiscoop_device;
 extern struct platform_device corgissp_device;
 extern struct platform_device corgifb_device;
 
-/*
- * External Functions
- */
-extern unsigned long corgi_ssp_ads7846_putget(unsigned long);
-extern unsigned long corgi_ssp_ads7846_get(void);
-extern void corgi_ssp_ads7846_put(unsigned long data);
-extern void corgi_ssp_ads7846_lock(void);
-extern void corgi_ssp_ads7846_unlock(void);
-extern void corgi_ssp_lcdtg_send (unsigned char adrs, unsigned char data);
-extern void corgi_ssp_blduty_set(int duty);
-extern int corgi_ssp_max1111_get(unsigned long data);
-
 #endif /* __ASM_ARCH_CORGI_H  */
 
diff --git a/include/asm-arm/arch-pxa/sharpsl.h b/include/asm-arm/arch-pxa/sharpsl.h
new file mode 100644 (file)
index 0000000..311f2bb
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SharpSL SSP Driver
+ */
+
+unsigned long corgi_ssp_ads7846_putget(unsigned long);
+unsigned long corgi_ssp_ads7846_get(void);
+void corgi_ssp_ads7846_put(unsigned long data);
+void corgi_ssp_ads7846_lock(void);
+void corgi_ssp_ads7846_unlock(void);
+void corgi_ssp_lcdtg_send (unsigned char adrs, unsigned char data);
+void corgi_ssp_blduty_set(int duty);
+int corgi_ssp_max1111_get(unsigned long data);
+
+/*
+ * SharpSL Touchscreen Driver
+ */
+
+struct corgits_machinfo {
+       unsigned long (*get_hsync_len)(void);
+       void (*put_hsync)(void);
+       void (*wait_hsync)(void);
+};
+
+/*
+ * SharpSL Backlight
+ */
+
+struct corgibl_machinfo {
+       int max_intensity;
+       void (*set_bl_intensity)(int intensity);
+};
+
diff --git a/include/asm-arm/arch-pxa/spitz.h b/include/asm-arm/arch-pxa/spitz.h
new file mode 100644 (file)
index 0000000..62e1fe4
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Hardware specific definitions for SL-Cx000 series of PDAs
+ *
+ * Copyright (c) 2005 Alexander Wykes
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __ASM_ARCH_SPITZ_H
+#define __ASM_ARCH_SPITZ_H  1
+#endif
+
+/* Spitz/Akita GPIOs */
+
+#define SPITZ_GPIO_KEY_INT         (0) /* Key Interrupt */
+#define SPITZ_GPIO_RESET           (1)
+#define SPITZ_GPIO_nSD_DETECT      (9)
+#define SPITZ_GPIO_TP_INT          (11) /* Touch Panel interrupt */
+#define SPITZ_GPIO_AK_INT          (13) /* Remote Control */
+#define SPITZ_GPIO_ADS7846_CS      (14)
+#define SPITZ_GPIO_SYNC            (16)
+#define SPITZ_GPIO_MAX1111_CS      (20)
+#define SPITZ_GPIO_FATAL_BAT       (21)
+#define SPITZ_GPIO_HSYNC           (22)
+#define SPITZ_GPIO_nSD_CLK         (32)
+#define SPITZ_GPIO_USB_DEVICE      (35)
+#define SPITZ_GPIO_USB_HOST        (37)
+#define SPITZ_GPIO_USB_CONNECT     (41)
+#define SPITZ_GPIO_LCDCON_CS       (53)
+#define SPITZ_GPIO_nPCE            (54)
+#define SPITZ_GPIO_nSD_WP          (81)
+#define SPITZ_GPIO_ON_RESET        (89)
+#define SPITZ_GPIO_BAT_COVER       (90)
+#define SPITZ_GPIO_CF_CD           (94)
+#define SPITZ_GPIO_ON_KEY          (95)
+#define SPITZ_GPIO_SWA             (97)
+#define SPITZ_GPIO_SWB             (96)
+#define SPITZ_GPIO_CHRG_FULL       (101)
+#define SPITZ_GPIO_CO              (101)
+#define SPITZ_GPIO_CF_IRQ          (105)
+#define SPITZ_GPIO_AC_IN           (115)
+#define SPITZ_GPIO_HP_IN           (116)
+
+/* Spitz Only GPIOs */
+
+#define SPITZ_GPIO_CF2_IRQ         (106) /* CF slot1 Ready */
+#define SPITZ_GPIO_CF2_CD          (93)
+
+
+/* Spitz/Akita Keyboard Definitions */
+
+#define SPITZ_KEY_STROBE_NUM         (11)
+#define SPITZ_KEY_SENSE_NUM          (7)
+#define SPITZ_GPIO_G0_STROBE_BIT     0x0f800000
+#define SPITZ_GPIO_G1_STROBE_BIT     0x00100000
+#define SPITZ_GPIO_G2_STROBE_BIT     0x01000000
+#define SPITZ_GPIO_G3_STROBE_BIT     0x00041880
+#define SPITZ_GPIO_G0_SENSE_BIT      0x00021000
+#define SPITZ_GPIO_G1_SENSE_BIT      0x000000d4
+#define SPITZ_GPIO_G2_SENSE_BIT      0x08000000
+#define SPITZ_GPIO_G3_SENSE_BIT      0x00000000
+
+#define SPITZ_GPIO_KEY_STROBE0       88
+#define SPITZ_GPIO_KEY_STROBE1       23
+#define SPITZ_GPIO_KEY_STROBE2       24
+#define SPITZ_GPIO_KEY_STROBE3       25
+#define SPITZ_GPIO_KEY_STROBE4       26
+#define SPITZ_GPIO_KEY_STROBE5       27
+#define SPITZ_GPIO_KEY_STROBE6       52
+#define SPITZ_GPIO_KEY_STROBE7       103
+#define SPITZ_GPIO_KEY_STROBE8       107
+#define SPITZ_GPIO_KEY_STROBE9       108
+#define SPITZ_GPIO_KEY_STROBE10      114
+
+#define SPITZ_GPIO_KEY_SENSE0        12
+#define SPITZ_GPIO_KEY_SENSE1        17
+#define SPITZ_GPIO_KEY_SENSE2        91
+#define SPITZ_GPIO_KEY_SENSE3        34
+#define SPITZ_GPIO_KEY_SENSE4        36
+#define SPITZ_GPIO_KEY_SENSE5        38
+#define SPITZ_GPIO_KEY_SENSE6        39
+
+
+/* Spitz Scoop Device (No. 1) GPIOs */
+/* Suspend States in comments */
+#define SPITZ_SCP_LED_GREEN     SCOOP_GPCR_PA11  /* Keep */
+#define SPITZ_SCP_JK_B          SCOOP_GPCR_PA12  /* Keep */
+#define SPITZ_SCP_CHRG_ON       SCOOP_GPCR_PA13  /* Keep */
+#define SPITZ_SCP_MUTE_L        SCOOP_GPCR_PA14  /* Low */
+#define SPITZ_SCP_MUTE_R        SCOOP_GPCR_PA15  /* Low */
+#define SPITZ_SCP_CF_POWER      SCOOP_GPCR_PA16  /* Keep */
+#define SPITZ_SCP_LED_ORANGE    SCOOP_GPCR_PA17  /* Keep */
+#define SPITZ_SCP_JK_A          SCOOP_GPCR_PA18  /* Low */
+#define SPITZ_SCP_ADC_TEMP_ON   SCOOP_GPCR_PA19  /* Low */
+
+#define SPITZ_SCP_IO_DIR      (SPITZ_SCP_LED_GREEN | SPITZ_SCP_JK_B | SPITZ_SCP_CHRG_ON | \
+                               SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | SPITZ_SCP_LED_ORANGE | \
+                               SPITZ_SCP_CF_POWER | SPITZ_SCP_JK_A | SPITZ_SCP_ADC_TEMP_ON)
+#define SPITZ_SCP_IO_OUT      (SPITZ_SCP_CHRG_ON | SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R)
+#define SPITZ_SCP_SUS_CLR     (SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | SPITZ_SCP_JK_A | SPITZ_SCP_ADC_TEMP_ON)
+#define SPITZ_SCP_SUS_SET     0
+
+/* Spitz Scoop Device (No. 2) GPIOs */
+/* Suspend States in comments */
+#define SPITZ_SCP2_IR_ON           SCOOP_GPCR_PA11  /* High */
+#define SPITZ_SCP2_AKIN_PULLUP     SCOOP_GPCR_PA12  /* Keep */
+#define SPITZ_SCP2_RESERVED_1      SCOOP_GPCR_PA13  /* High */
+#define SPITZ_SCP2_RESERVED_2      SCOOP_GPCR_PA14  /* Low */
+#define SPITZ_SCP2_RESERVED_3      SCOOP_GPCR_PA15  /* Low */
+#define SPITZ_SCP2_RESERVED_4      SCOOP_GPCR_PA16  /* Low */
+#define SPITZ_SCP2_BACKLIGHT_CONT  SCOOP_GPCR_PA17  /* Low */
+#define SPITZ_SCP2_BACKLIGHT_ON    SCOOP_GPCR_PA18  /* Low */
+#define SPITZ_SCP2_MIC_BIAS        SCOOP_GPCR_PA19  /* Low */
+
+#define SPITZ_SCP2_IO_DIR (SPITZ_SCP2_IR_ON | SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1 | \
+                           SPITZ_SCP2_RESERVED_2 | SPITZ_SCP2_RESERVED_3 | SPITZ_SCP2_RESERVED_4 | \
+                           SPITZ_SCP2_BACKLIGHT_CONT | SPITZ_SCP2_BACKLIGHT_ON | SPITZ_SCP2_MIC_BIAS)
+
+#define SPITZ_SCP2_IO_OUT   (SPITZ_SCP2_IR_ON | SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1)
+#define SPITZ_SCP2_SUS_CLR  (SPITZ_SCP2_RESERVED_2 | SPITZ_SCP2_RESERVED_3 | SPITZ_SCP2_RESERVED_4 | \
+                             SPITZ_SCP2_BACKLIGHT_CONT | SPITZ_SCP2_BACKLIGHT_ON | SPITZ_SCP2_MIC_BIAS)
+#define SPITZ_SCP2_SUS_SET  (SPITZ_SCP2_IR_ON | SPITZ_SCP2_RESERVED_1)
+
+
+/* Spitz IRQ Definitions */
+
+#define SPITZ_IRQ_GPIO_KEY_INT        IRQ_GPIO(SPITZ_GPIO_KEY_INT)
+#define SPITZ_IRQ_GPIO_AC_IN          IRQ_GPIO(SPITZ_GPIO_AC_IN)
+#define SPITZ_IRQ_GPIO_AK_INT         IRQ_GPIO(SPITZ_GPIO_AK_INT)
+#define SPITZ_IRQ_GPIO_HP_IN          IRQ_GPIO(SPITZ_GPIO_HP_IN)
+#define SPITZ_IRQ_GPIO_TP_INT         IRQ_GPIO(SPITZ_GPIO_TP_INT)
+#define SPITZ_IRQ_GPIO_SYNC           IRQ_GPIO(SPITZ_GPIO_SYNC)
+#define SPITZ_IRQ_GPIO_ON_KEY         IRQ_GPIO(SPITZ_GPIO_ON_KEY)
+#define SPITZ_IRQ_GPIO_SWA            IRQ_GPIO(SPITZ_GPIO_SWA)
+#define SPITZ_IRQ_GPIO_SWB            IRQ_GPIO(SPITZ_GPIO_SWB)
+#define SPITZ_IRQ_GPIO_BAT_COVER      IRQ_GPIO(SPITZ_GPIO_BAT_COVER)
+#define SPITZ_IRQ_GPIO_FATAL_BAT      IRQ_GPIO(SPITZ_GPIO_FATAL_BAT)
+#define SPITZ_IRQ_GPIO_CO             IRQ_GPIO(SPITZ_GPIO_CO)
+#define SPITZ_IRQ_GPIO_CF_IRQ         IRQ_GPIO(SPITZ_GPIO_CF_IRQ)
+#define SPITZ_IRQ_GPIO_CF_CD          IRQ_GPIO(SPITZ_GPIO_CF_CD)
+#define SPITZ_IRQ_GPIO_CF2_IRQ        IRQ_GPIO(SPITZ_GPIO_CF2_IRQ)
+#define SPITZ_IRQ_GPIO_nSD_INT        IRQ_GPIO(SPITZ_GPIO_nSD_INT)
+#define SPITZ_IRQ_GPIO_nSD_DETECT     IRQ_GPIO(SPITZ_GPIO_nSD_DETECT)
+
+/*
+ * Shared data structures
+ */
+extern struct platform_device spitzscoop_device;
+extern struct platform_device spitzscoop2_device;
+extern struct platform_device spitzssp_device;
+extern struct sharpsl_charger_machinfo spitz_pm_machinfo;
+
+extern void spitz_lcd_power(int on);
index 478c49b56e18d0fa3658eeb7c5a7d25c86f53de6..366bafbdfbb1b9c26270059afa968d2167c221f7 100644 (file)
@@ -445,12 +445,9 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 #define HAVE_ARCH_UNMAPPED_AREA
 
 /*
- * remap a physical address `phys' of size `size' with page protection `prot'
+ * remap a physical page `pfn' of size `size' with page protection `prot'
  * into virtual address `from'
  */
-#define io_remap_page_range(vma,from,phys,size,prot) \
-               remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
                remap_pfn_range(vma, from, pfn, size, prot)
 
index 4a0a00da425f3886d01ed24be565188f96a89cb7..f602cf57241131cfc7c84fb66348e267cd04b20f 100644 (file)
@@ -294,12 +294,9 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 #include <asm-generic/pgtable.h>
 
 /*
- * remap a physical address `phys' of size `size' with page protection `prot'
+ * remap a physical page `pfn' of size `size' with page protection `prot'
  * into virtual address `from'
  */
-#define io_remap_page_range(vma,from,phys,size,prot) \
-               remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
                remap_pfn_range(vma, from, pfn, size, prot)
 
index d0a9c2f9c13ece32a626044df2b730f0e6cac275..473fb4bb6329838a8ece91c055b6b2d67efb38db 100644 (file)
@@ -500,9 +500,6 @@ static inline int pte_file(pte_t pte)
 #define PageSkip(page)         (0)
 #define kern_addr_valid(addr)  (1)
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index faff403e1061562f77e6c7a13f7c46d6775bb257..7d0298347ee7df599088ca5cbb6a4f0c8ee2947b 100644 (file)
  * and page free order so much..
  */
 #ifdef CONFIG_SMP
-  #define FREE_PTE_NR  506
+  #ifdef ARCH_FREE_PTR_NR
+    #define FREE_PTR_NR   ARCH_FREE_PTR_NR
+  #else
+    #define FREE_PTE_NR        506
+  #endif
   #define tlb_fast_mode(tlb) ((tlb)->nr == ~0U)
 #else
   #define FREE_PTE_NR  1
index 69076eb3147600af035fbdfcfcbe024d88a61b2b..f6e296fc1297da57e448851613fc11542bd566fc 100644 (file)
@@ -52,8 +52,6 @@ extern int is_in_rom(unsigned long);
  * No page table caches to initialise
  */
 #define pgtable_cache_init()   do { } while (0)
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
index 6a1b1882285c004a1c5f80b109c046fe483c8bee..8c454aa58ac6b157441ad2a77f9211e4a30f882e 100644 (file)
@@ -130,6 +130,8 @@ extern unsigned int nmi_watchdog;
 #define NMI_LOCAL_APIC 2
 #define NMI_INVALID    3
 
+extern int disable_timer_pin_1;
+
 #else /* !CONFIG_X86_LOCAL_APIC */
 static inline void lapic_shutdown(void) { }
 
diff --git a/include/asm-i386/numa.h b/include/asm-i386/numa.h
new file mode 100644 (file)
index 0000000..96fcb15
--- /dev/null
@@ -0,0 +1,3 @@
+
+int pxm_to_nid(int pxm);
+
index 47bc1ffa3d4cfb42321cec3bf25d9da23ccc8486..d101ac414f074e308d6dfe182f7d190186cd429a 100644 (file)
@@ -431,9 +431,6 @@ extern void noexec_setup(const char *str);
 #define kern_addr_valid(addr)  (1)
 #endif /* CONFIG_FLATMEM */
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index 2461b731781ebc182fd7b70c534b6dd87bb15e76..0ec27c9e8e45ba696be1a06a81df49d27d222729 100644 (file)
@@ -60,7 +60,7 @@ static inline int node_to_first_cpu(int node)
        return first_cpu(mask);
 }
 
-#define pcibus_to_node(bus) mp_bus_id_to_node[(bus)->number]
+#define pcibus_to_node(bus) ((long) (bus)->sysdata)
 #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus))
 
 /* sched_domains SD_NODE_INIT for NUMAQ machines */
index a7cb377745bf01968d49984ade8d57fcd27369dd..fbaf90a3968c1f7c4f5bd11b818a604c625e8923 100644 (file)
@@ -332,7 +332,7 @@ type name(type1 arg1) \
 long __res; \
 __asm__ volatile ("int $0x80" \
        : "=a" (__res) \
-       : "0" (__NR_##name),"b" ((long)(arg1))); \
+       : "0" (__NR_##name),"b" ((long)(arg1)) : "memory"); \
 __syscall_return(type,__res); \
 }
 
@@ -342,7 +342,7 @@ type name(type1 arg1,type2 arg2) \
 long __res; \
 __asm__ volatile ("int $0x80" \
        : "=a" (__res) \
-       : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
+       : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)) : "memory"); \
 __syscall_return(type,__res); \
 }
 
@@ -353,7 +353,7 @@ long __res; \
 __asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
-                 "d" ((long)(arg3))); \
+                 "d" ((long)(arg3)) : "memory"); \
 __syscall_return(type,__res); \
 }
 
@@ -364,7 +364,7 @@ long __res; \
 __asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
-         "d" ((long)(arg3)),"S" ((long)(arg4))); \
+         "d" ((long)(arg3)),"S" ((long)(arg4)) : "memory"); \
 __syscall_return(type,__res); \
 } 
 
@@ -376,7 +376,7 @@ long __res; \
 __asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
-         "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
+         "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)) : "memory"); \
 __syscall_return(type,__res); \
 }
 
@@ -389,7 +389,7 @@ __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; p
        : "=a" (__res) \
        : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
          "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
-         "0" ((long)(arg6))); \
+         "0" ((long)(arg6)) : "memory"); \
 __syscall_return(type,__res); \
 }
 
index 2e34c06e677795268249609786ceb012e81e4f84..3339c7b55a6f69bf534620c45f7cfc6599a25bce 100644 (file)
@@ -443,10 +443,6 @@ extern void paging_init (void);
 #define pte_to_pgoff(pte)              ((pte_val(pte) << 1) >> 3)
 #define pgoff_to_pte(off)              ((pte_t) { ((off) << 2) | _PAGE_FILE })
 
-/* XXX is this right? */
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index da805e970844a1d9dab8210062e8c67cb5ac8805..388e5ee9fa2717e7bd3d7117a6aaa2d773d89597 100644 (file)
@@ -378,9 +378,6 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 #define kern_addr_valid(addr)  (1)
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)     \
-       remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)        \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index 0c87fc84f7a4ee20b44453202d430e2428e3db16..add129e93fd7076a5fadcf27134e5c71111b801f 100644 (file)
@@ -141,9 +141,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
 
 #define kern_addr_valid(addr)  (1)
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index f95e32b4042545025f7b557e8984bcb2021facb8..c42f88a9b9f986d25b3f859d38b9f3794ff17378 100644 (file)
@@ -259,7 +259,7 @@ static __inline__ int __test_bit(int nr, const volatile unsigned long * addr)
 #define find_first_bit(addr, size) \
         find_next_bit((addr), (size), 0)
 
-static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+static __inline__ int find_next_zero_bit (const void * addr, int size, int offset)
 {
        unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
        unsigned long result = offset & ~31UL;
index aa7a2ffa41af135cd49ddf60e683f76a369c5f8d..026bbc9565b428b4270ae0d759268ab0a4f36fd0 100644 (file)
@@ -2,23 +2,23 @@
 #define _M68KNOMMU_CACHEFLUSH_H
 
 /*
- * (C) Copyright 2000-2002, Greg Ungerer <gerg@snapgear.com>
+ * (C) Copyright 2000-2004, Greg Ungerer <gerg@snapgear.com>
  */
 #include <linux/mm.h>
 
 #define flush_cache_all()                      __flush_cache_all()
 #define flush_cache_mm(mm)                     do { } while (0)
-#define flush_cache_range(vma, start, end)     do { } while (0)
-#define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
-#define flush_dcache_range(start,len)          do { } while (0)
+#define flush_cache_range(vma, start, end)     __flush_cache_all()
+#define flush_cache_page(vma, vmaddr)          do { } while (0)
+#define flush_dcache_range(start,len)          __flush_cache_all()
 #define flush_dcache_page(page)                        do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
 #define flush_icache_range(start,len)          __flush_cache_all()
 #define flush_icache_page(vma,pg)              do { } while (0)
 #define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
-#define flush_cache_vmap(start, end)           flush_cache_all()
-#define flush_cache_vunmap(start, end)         flush_cache_all()
+#define flush_cache_vmap(start, end)           do { } while (0)
+#define flush_cache_vunmap(start, end)         do { } while (0)
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
        memcpy(dst, src, len)
@@ -50,22 +50,23 @@ extern inline void __flush_cache_all(void)
                "movec  %%d0,%%CACR\n\t"
                : : : "d0", "a0" );
 #endif /* CONFIG_M5407 */
-#ifdef CONFIG_M5272
+#if defined(CONFIG_M527x) || defined(CONFIG_M528x)
        __asm__ __volatile__ (
-               "movel  #0x01000000, %%d0\n\t"
-               "movec  %%d0, %%CACR\n\t"
-               "nop\n\t"
-               "movel  #0x80000100, %%d0\n\t"
+               "movel  #0x81400100, %%d0\n\t"
                "movec  %%d0, %%CACR\n\t"
                "nop\n\t"
                : : : "d0" );
-#endif /* CONFIG_M5272 */
-#if 0 /* CONFIG_M5249 */
+#endif /* CONFIG_M527x || CONFIG_M528x */
+#ifdef CONFIG_M5272
        __asm__ __volatile__ (
                "movel  #0x01000000, %%d0\n\t"
                "movec  %%d0, %%CACR\n\t"
                "nop\n\t"
-               "movel  #0xa0000200, %%d0\n\t"
+               : : : "d0" );
+#endif /* CONFIG_M5272 */
+#if CONFIG_M5249
+       __asm__ __volatile__ (
+               "movel  #0xa1000200, %%d0\n\t"
                "movec  %%d0, %%CACR\n\t"
                "nop\n\t"
                : : : "d0" );
index 92cf102c2534c0445ed581e74d451bce311ef104..294ec7583ac9149696314aaece0256746e595b18 100644 (file)
@@ -25,7 +25,8 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
  * better 64-bit) boundary
  */
 
-unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum);
+unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
+       int len, int sum);
 
 
 /*
@@ -35,8 +36,8 @@ unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum);
  * better 64-bit) boundary
  */
 
-extern unsigned int csum_partial_copy_from_user(const char *src, char *dst,
-                                               int len, int sum, int *csum_err);
+extern unsigned int csum_partial_copy_from_user(const unsigned char *src,
+       unsigned char *dst, int len, int sum, int *csum_err);
 
 #define csum_partial_copy_nocheck(src, dst, len, sum)  \
        csum_partial_copy((src), (dst), (len), (sum))
index d280d013da032c0e3992b98a5b01c2267791441e..e7878d0f7d7a57d94003a0c9788fc858cbec88e9 100644 (file)
 /*
  *     SDRAM configuration registers.
  */
-#ifdef CONFIG_M5271EVB
+#ifdef CONFIG_M5271
 #define        MCFSIM_DCR              0x40            /* SDRAM control */
 #define        MCFSIM_DACR0            0x48            /* SDRAM base address 0 */
 #define        MCFSIM_DMR0             0x4c            /* SDRAM address mask 0 */
 #define        MCFSIM_DACR1            0x50            /* SDRAM base address 1 */
 #define        MCFSIM_DMR1             0x54            /* SDRAM address mask 1 */
-#else
+#endif
+#ifdef CONFIG_M5275
 #define        MCFSIM_DMR              0x40            /* SDRAM mode */
 #define        MCFSIM_DCR              0x44            /* SDRAM control */
 #define        MCFSIM_DCFG1            0x48            /* SDRAM configuration 1 */
 #define        MCFSIM_DMR1             0x5c            /* SDRAM address mask 1 */
 #endif
 
+/*
+ *     GPIO pins setups to enable the UARTs.
+ */
+#ifdef CONFIG_M5271
+#define MCF_GPIO_PAR_UART      0x100048        /* PAR UART address */
+#define UART0_ENABLE_MASK      0x000f
+#define UART1_ENABLE_MASK      0x0ff0
+#define UART2_ENABLE_MASK      0x3000
+#endif
+#ifdef CONFIG_M5275
+#define MCF_GPIO_PAR_UART      0x10007c        /* PAR UART address */
+#define UART0_ENABLE_MASK      0x000f
+#define UART1_ENABLE_MASK      0x00f0
+#define UART2_ENABLE_MASK      0x3f00 
+#endif
+
 /****************************************************************************/
 #endif /* m527xsim_h */
index 371993a206acdc751d2727f435d88bade432963d..610774a17f70d86a00524fb1c1e88f99f9d484af 100644 (file)
 #define        MCFSIM_DACR1            0x50            /* SDRAM base address 1 */
 #define        MCFSIM_DMR1             0x54            /* SDRAM address mask 1 */
 
+/*
+ *     Derek Cheung - 6 Feb 2005
+ *             add I2C and QSPI register definition using Freescale's MCF5282
+ */
+/* set Port AS pin for I2C or UART */
+#define MCF5282_GPIO_PASPAR     (volatile u16 *) (MCF_IPSBAR + 0x00100056)
+
+/* Interrupt Mask Register Register Low */ 
+#define MCF5282_INTC0_IMRL      (volatile u32 *) (MCF_IPSBAR + 0x0C0C)
+/* Interrupt Control Register 7 */
+#define MCF5282_INTC0_ICR17     (volatile u8 *) (MCF_IPSBAR + 0x0C51)
+
+
+
+/*********************************************************************
+*
+* Inter-IC (I2C) Module
+*
+*********************************************************************/
+/* Read/Write access macros for general use */
+#define MCF5282_I2C_I2ADR       (volatile u8 *) (MCF_IPSBAR + 0x0300) // Address 
+#define MCF5282_I2C_I2FDR       (volatile u8 *) (MCF_IPSBAR + 0x0304) // Freq Divider
+#define MCF5282_I2C_I2CR        (volatile u8 *) (MCF_IPSBAR + 0x0308) // Control
+#define MCF5282_I2C_I2SR        (volatile u8 *) (MCF_IPSBAR + 0x030C) // Status
+#define MCF5282_I2C_I2DR        (volatile u8 *) (MCF_IPSBAR + 0x0310) // Data I/O
+
+/* Bit level definitions and macros */
+#define MCF5282_I2C_I2ADR_ADDR(x)                       (((x)&0x7F)<<0x01)
+
+#define MCF5282_I2C_I2FDR_IC(x)                         (((x)&0x3F))
+
+#define MCF5282_I2C_I2CR_IEN    (0x80) // I2C enable
+#define MCF5282_I2C_I2CR_IIEN   (0x40)  // interrupt enable
+#define MCF5282_I2C_I2CR_MSTA   (0x20)  // master/slave mode
+#define MCF5282_I2C_I2CR_MTX    (0x10)  // transmit/receive mode
+#define MCF5282_I2C_I2CR_TXAK   (0x08)  // transmit acknowledge enable
+#define MCF5282_I2C_I2CR_RSTA   (0x04)  // repeat start
+
+#define MCF5282_I2C_I2SR_ICF    (0x80)  // data transfer bit
+#define MCF5282_I2C_I2SR_IAAS   (0x40)  // I2C addressed as a slave
+#define MCF5282_I2C_I2SR_IBB    (0x20)  // I2C bus busy
+#define MCF5282_I2C_I2SR_IAL    (0x10)  // aribitration lost
+#define MCF5282_I2C_I2SR_SRW    (0x04)  // slave read/write
+#define MCF5282_I2C_I2SR_IIF    (0x02)  // I2C interrupt
+#define MCF5282_I2C_I2SR_RXAK   (0x01)  // received acknowledge
+
+
+
+/*********************************************************************
+*
+* Queued Serial Peripheral Interface (QSPI) Module
+*
+*********************************************************************/
+/* Derek - 21 Feb 2005 */
+/* change to the format used in I2C */
+/* Read/Write access macros for general use */
+#define MCF5282_QSPI_QMR        MCF_IPSBAR + 0x0340
+#define MCF5282_QSPI_QDLYR      MCF_IPSBAR + 0x0344
+#define MCF5282_QSPI_QWR        MCF_IPSBAR + 0x0348
+#define MCF5282_QSPI_QIR        MCF_IPSBAR + 0x034C
+#define MCF5282_QSPI_QAR        MCF_IPSBAR + 0x0350
+#define MCF5282_QSPI_QDR        MCF_IPSBAR + 0x0354
+#define MCF5282_QSPI_QCR        MCF_IPSBAR + 0x0354
+
+/* Bit level definitions and macros */
+#define MCF5282_QSPI_QMR_MSTR                           (0x8000)
+#define MCF5282_QSPI_QMR_DOHIE                          (0x4000)
+#define MCF5282_QSPI_QMR_BITS_16                        (0x0000)
+#define MCF5282_QSPI_QMR_BITS_8                         (0x2000)
+#define MCF5282_QSPI_QMR_BITS_9                         (0x2400)
+#define MCF5282_QSPI_QMR_BITS_10                        (0x2800)
+#define MCF5282_QSPI_QMR_BITS_11                        (0x2C00)
+#define MCF5282_QSPI_QMR_BITS_12                        (0x3000)
+#define MCF5282_QSPI_QMR_BITS_13                        (0x3400)
+#define MCF5282_QSPI_QMR_BITS_14                        (0x3800)
+#define MCF5282_QSPI_QMR_BITS_15                        (0x3C00)
+#define MCF5282_QSPI_QMR_CPOL                           (0x0200)
+#define MCF5282_QSPI_QMR_CPHA                           (0x0100)
+#define MCF5282_QSPI_QMR_BAUD(x)                        (((x)&0x00FF))
+
+#define MCF5282_QSPI_QDLYR_SPE                          (0x80)
+#define MCF5282_QSPI_QDLYR_QCD(x)                       (((x)&0x007F)<<8)
+#define MCF5282_QSPI_QDLYR_DTL(x)                       (((x)&0x00FF))
+
+#define MCF5282_QSPI_QWR_HALT                           (0x8000)
+#define MCF5282_QSPI_QWR_WREN                           (0x4000)
+#define MCF5282_QSPI_QWR_WRTO                           (0x2000)
+#define MCF5282_QSPI_QWR_CSIV                           (0x1000)
+#define MCF5282_QSPI_QWR_ENDQP(x)                       (((x)&0x000F)<<8)
+#define MCF5282_QSPI_QWR_CPTQP(x)                       (((x)&0x000F)<<4)
+#define MCF5282_QSPI_QWR_NEWQP(x)                       (((x)&0x000F))
+
+#define MCF5282_QSPI_QIR_WCEFB                          (0x8000)
+#define MCF5282_QSPI_QIR_ABRTB                          (0x4000)
+#define MCF5282_QSPI_QIR_ABRTL                          (0x1000)
+#define MCF5282_QSPI_QIR_WCEFE                          (0x0800)
+#define MCF5282_QSPI_QIR_ABRTE                          (0x0400)
+#define MCF5282_QSPI_QIR_SPIFE                          (0x0100)
+#define MCF5282_QSPI_QIR_WCEF                           (0x0008)
+#define MCF5282_QSPI_QIR_ABRT                           (0x0004)
+#define MCF5282_QSPI_QIR_SPIF                           (0x0001)
+
+#define MCF5282_QSPI_QAR_ADDR(x)                        (((x)&0x003F))
+
+#define MCF5282_QSPI_QDR_COMMAND(x)                     (((x)&0xFF00))
+#define MCF5282_QSPI_QCR_DATA(x)                        (((x)&0x00FF)<<8)
+#define MCF5282_QSPI_QCR_CONT                           (0x8000)
+#define MCF5282_QSPI_QCR_BITSE                          (0x4000)
+#define MCF5282_QSPI_QCR_DT                             (0x2000)
+#define MCF5282_QSPI_QCR_DSCK                           (0x1000)
+#define MCF5282_QSPI_QCR_CS                             (((x)&0x000F)<<8)
+
 /****************************************************************************/
 #endif /* m528xsim_h */
index bdd8c53ef34ce171ca6117a5c99f6f6948316e77..b17cd920977f592c7a05f5fdae337039fb784a66 100644 (file)
@@ -33,7 +33,7 @@
 .endm
 #endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */
 
-#if defined(CONFIG_M527x)
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x)
 /*
  *     New version 2 cores have a configurable split cache arrangement.
  *     For now I am just enabling instruction cache - but ultimately I
        movec   %d0,%CACR               /* enable cache */
        nop
 .endm
-#endif /* CONFIG_M527x */
+#endif /* CONFIG_M523x || CONFIG_M527x */
 
 #if defined(CONFIG_M528x)
-/*
- *     Cache is totally broken on early 5282 silicon. So far now we
- *     disable its cache all together.
- */
 .macro CACHE_ENABLE
-       movel   #0x01000000,%d0
-       movec   %d0,%CACR               /* invalidate cache */
        nop
-       movel   #0x0000c000,%d0         /* set SDRAM cached only */
-       movec   %d0,%ACR0
-       movel   #0x00000000,%d0         /* no other regions cached */
-       movec   %d0,%ACR1
-       movel   #0x00000000,%d0         /* configure cache */
-       movec   %d0,%CACR               /* enable cache */
+       movel   #0x01000000, %d0
+       movec   %d0, %CACR              /* Invalidate cache */
+       nop
+       movel   #0x0000c020, %d0        /* Set SDRAM cached only */
+       movec   %d0, %ACR0
+       movel   #0xff00c000, %d0        /* Cache Flash also */
+       movec   %d0, %ACR1
+       movel   #0x80000200, %d0        /* Setup cache mask */
+       movec   %d0, %CACR              /* Enable cache */
        nop
 .endm
 #endif /* CONFIG_M528x */
index 350c6090b5c1ed5f3959ad5eae8d4b06b7bc283c..b93f8ba8a248e6269a0d8385217dc6f50893cb3a 100644 (file)
@@ -21,7 +21,7 @@
 #define        MCFDMA_BASE1            0x240           /* Base address of DMA 1 */
 #elif defined(CONFIG_M5272)
 #define        MCFDMA_BASE0            0x0e0           /* Base address of DMA 0 */
-#elif defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
 /* These are relative to the IPSBAR, not MBAR */
 #define        MCFDMA_BASE0            0x100           /* Base address of DMA 0 */
 #define        MCFDMA_BASE1            0x140           /* Base address of DMA 1 */
index e2a69fffa3708c6a4f15c306f8c41e22d4be9a09..00893055e6c2c89669859082d19f6163a7298215 100644 (file)
@@ -56,8 +56,6 @@ extern int is_in_rom(unsigned long);
  * No page table caches to initialise.
  */
 #define pgtable_cache_init()   do { } while (0)
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
index 230b8d56d17fb04f6ebd0bdfaa6376e79036128f..12309b181d29b5780dd84138b0712d6050387d85 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _M68KNOMMU_SCATTERLIST_H
 #define _M68KNOMMU_SCATTERLIST_H
 
+#include <linux/mm.h>
+
 struct scatterlist {
        struct page     *page;
        unsigned int    offset;
@@ -8,6 +10,10 @@ struct scatterlist {
        unsigned int    length;
 };
 
+#define sg_address(sg) (page_address((sg)->page) + (sg)->offset
+#define sg_dma_address(sg)      ((sg)->dma_address)
+#define sg_dma_len(sg)          ((sg)->length)
+
 #define ISA_DMA_THRESHOLD      (0xffffffff)
 
 #endif /* !(_M68KNOMMU_SCATTERLIST_H) */
index c341b66c147b605bd7ea078bbdd770401a0fcd34..53cbbad0f13019d2bf23df3b33a45d9ae7b3a99a 100644 (file)
@@ -57,9 +57,18 @@ asmlinkage void resume(void);
         : "cc", "%d0", "memory")
 #define local_irq_disable() __asm__ __volatile__ (             \
        "move %/sr,%%d0\n\t"                                    \
-       "ori.l  #0x0700,%%d0\n\t"                               \
+       "ori.l #0x0700,%%d0\n\t"                                \
        "move %%d0,%/sr\n"                                      \
-       : /* no inputs */                                       \
+       : /* no outputs */                                      \
+       :                                                       \
+       : "cc", "%d0", "memory")
+/* For spinlocks etc */
+#define local_irq_save(x) __asm__ __volatile__ (               \
+       "movew %%sr,%0\n\t"                                     \
+       "movew #0x0700,%%d0\n\t"                                \
+       "or.l  %0,%%d0\n\t"                                     \
+       "movew %%d0,%/sr"                                       \
+       : "=d" (x)                                              \
        :                                                       \
        : "cc", "%d0", "memory")
 #else
@@ -75,7 +84,9 @@ asmlinkage void resume(void);
 #define local_irq_restore(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory")
 
 /* For spinlocks etc */
+#ifndef local_irq_save
 #define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } while (0)
+#endif
 
 #define        irqs_disabled()                 \
 ({                                     \
@@ -234,9 +245,9 @@ cmpxchg(volatile int *p, int old, int new)
 #ifdef CONFIG_COLDFIRE
 #if defined(CONFIG_M5272) && defined(CONFIG_NETtel)
 /*
- *     Need to account for broken early mask of 5272 silicon. So don't
- *     jump through the original start address. Jump strait into the
- *     known start of the FLASH code.
+ * Need to account for broken early mask of 5272 silicon. So don't
+ * jump through the original start address. Jump strait into the
+ * known start of the FLASH code.
  */
 #define HARD_RESET_NOW() ({            \
         asm("                          \
@@ -244,7 +255,9 @@ cmpxchg(volatile int *p, int old, int new)
         jmp 0xf0000400;                        \
         ");                            \
 })
-#elif defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
+#elif defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \
+      defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \
+      defined(CONFIG_CLEOPATRA)
 #define HARD_RESET_NOW() ({            \
         asm("                          \
        movew #0x2700, %sr;             \
@@ -257,6 +270,26 @@ cmpxchg(volatile int *p, int old, int new)
         jmp (%a0);                     \
         ");                            \
 })
+#elif defined(CONFIG_M5272)
+/*
+ * Retrieve the boot address in flash using CSBR0 and CSOR0
+ * find the reset vector at flash_address + 4 (e.g. 0x400)
+ * remap it in the flash's current location (e.g. 0xf0000400)
+ * and jump there.
+ */ 
+#define HARD_RESET_NOW() ({            \
+       asm("                           \
+       movew #0x2700, %%sr;            \
+       move.l  %0+0x40,%%d0;           \
+       and.l   %0+0x44,%%d0;           \
+       andi.l  #0xfffff000,%%d0;       \
+       mov.l   %%d0,%%a0;              \
+       or.l    4(%%a0),%%d0;           \
+       mov.l   %%d0,%%a0;              \
+       jmp (%%a0);"                    \
+       : /* No output */               \
+       : "o" (*(char *)MCF_MBAR) );    \
+})
 #elif defined(CONFIG_M528x)
 /*
  * The MCF528x has a bit (SOFTRST) in memory (Reset Control Register RCR),
@@ -270,6 +303,15 @@ cmpxchg(volatile int *p, int old, int new)
        while(1)                                \
        *reset |= (0x01 << 7);\
 })
+#elif defined(CONFIG_M523x)
+#define HARD_RESET_NOW() ({            \
+       asm("                           \
+       movew #0x2700, %sr;             \
+       movel #0x01000000, %sp;         \
+       moveal #0x40110000, %a0;        \
+       moveb #0x80, (%a0);             \
+       ");                             \
+})
 #else
 #define HARD_RESET_NOW() ({            \
         asm("                          \
index dbe13da0bdadbe55affd38c3999ed4e0eb04593b..cbd1672c94cb366db294898d470704c2707ac49d 100644 (file)
@@ -358,16 +358,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
 extern phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size);
 extern int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot);
 
-static inline int io_remap_page_range(struct vm_area_struct *vma,
-               unsigned long vaddr,
-               unsigned long paddr,
-               unsigned long size,
-               pgprot_t prot)
-{
-       phys_t phys_addr_high = fixup_bigphys_addr(paddr, size);
-       return remap_pfn_range(vma, vaddr, phys_addr_high >> PAGE_SHIFT, size, prot);
-}
-
 static inline int io_remap_pfn_range(struct vm_area_struct *vma,
                unsigned long vaddr,
                unsigned long pfn,
@@ -378,8 +368,6 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
        return remap_pfn_range(vma, vaddr, pfn, size, prot);
 }
 #else
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
index f001bb01e38f277a3210a7a19ee08d4bf1aabfca..820c6e712cd7b863a0f30460cdc349da2b77072f 100644 (file)
@@ -498,9 +498,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 
 #endif /* !__ASSEMBLY__ */
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index 538ea8ef509b99f4d2ec3350d64e12bd27450332..12f1bce037be7f57c422b26246b692838b4fbc9d 100644 (file)
 
 #include <asm-generic/siginfo.h>
 
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRANCH    (__SI_FAULT|3)  /* process taken branch trap */
+#define TRAP_HWBKPT    (__SI_FAULT|4)  /* hardware breakpoint or watchpoint */
+#undef NSIGTRAP
+#define NSIGTRAP       4
+
 #endif /* _ASM_POWERPC_SIGINFO_H */
index 835930d6faa1bf54c2a4c71d5138a03730610183..75c2ffa26b26d5b22a1dffcc78a1731361001b7a 100644 (file)
@@ -119,6 +119,14 @@ extern spinlock_t mv64x60_lock;
 
 #define        MV64x60_64BIT_WIN_COUNT                 24
 
+/* Watchdog Platform Device, Driver Data */
+#define        MV64x60_WDT_NAME                        "wdt"
+
+struct mv64x60_wdt_pdata {
+       int     timeout;        /* watchdog expiry in seconds, default 10 */
+       int     bus_clk;        /* bus clock in MHz, default 133 */
+};
+
 /*
  * Define a structure that's used to pass in config information to the
  * core routines.
index 92f30b28b252e1ab38c78d3727d99e2317dcefd5..eee601bb9ada6fbcedcb954a9715bc9b8a681a29 100644 (file)
@@ -812,15 +812,6 @@ extern void kernel_set_cachemode (unsigned long address, unsigned long size,
 #ifdef CONFIG_PHYS_64BIT
 extern int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
                        unsigned long paddr, unsigned long size, pgprot_t prot);
-static inline int io_remap_page_range(struct vm_area_struct *vma,
-                                       unsigned long vaddr,
-                                       unsigned long paddr,
-                                       unsigned long size,
-                                       pgprot_t prot)
-{
-       phys_addr_t paddr64 = fixup_bigphys_addr(paddr, size);
-       return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot);
-}
 
 static inline int io_remap_pfn_range(struct vm_area_struct *vma,
                                        unsigned long vaddr,
@@ -832,8 +823,6 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
        return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot);
 }
 #else
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
index 9d4e4ea530c3a7c2c5dd34b0d01d6824914a08f3..7043c164b5375d98a9ae8794b1b77db89653b3ab 100644 (file)
@@ -142,4 +142,11 @@ do {                                                                             \
 #define PTRACE_GETEVRREGS      20
 #define PTRACE_SETEVRREGS      21
 
+/*
+ * Get or set a debug register. The first 16 are DABR registers and the
+ * second 16 are IABR registers.
+ */
+#define PTRACE_GET_DEBUGREG    25
+#define PTRACE_SET_DEBUGREG    26
+
 #endif
diff --git a/include/asm-ppc/segment.h b/include/asm-ppc/segment.h
deleted file mode 100644 (file)
index 0f2f742..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm/uaccess.h>
index 4f668a4baff01b13427e59be038280075c7e835c..ab7c3cf24888cd6c6fb2f3663cd835f95d088f7b 100644 (file)
 #define H_PP1                  (1UL<<(63-62))
 #define H_PP2                  (1UL<<(63-63))
 
+/* DABRX flags */
+#define H_DABRX_HYPERVISOR     (1UL<<(63-61))
+#define H_DABRX_KERNEL         (1UL<<(63-62))
+#define H_DABRX_USER           (1UL<<(63-63))
+
 /* pSeries hypervisor opcodes */
 #define H_REMOVE               0x04
 #define H_ENTER                        0x08
 #define H_VIO_SIGNAL           0x104
 #define H_SEND_CRQ             0x108
 #define H_COPY_RDMA             0x110
+#define H_SET_XDABR            0x134
 #define H_STUFF_TCE            0x138
 #define H_PUT_TCE_INDIRECT     0x13C
 #define H_VTERM_PARTNER_INFO   0x150
index 9a1ef4427ed2dfa0b2923f99ef2f8c4098cf4011..8027160ec96d005966b3afd54edac45fecfa5512 100644 (file)
@@ -88,6 +88,7 @@ struct machdep_calls {
 
        /* PCI stuff */
        void            (*pcibios_fixup)(void);
+       int             (*pci_probe_mode)(struct pci_bus *);
 
        void            (*restart)(char *cmd);
        void            (*power_off)(void);
@@ -173,10 +174,6 @@ extern sys_ctrler_t sys_ctrler;
 void ppc64_boot_msg(unsigned int src, const char *msg);
 /* Print a termination message (print only -- does not stop the kernel) */
 void ppc64_terminate_msg(unsigned int src, const char *msg);
-/* Print something that needs attention (device error, etc) */
-void ppc64_attention_msg(unsigned int src, const char *msg);
-/* Print a dump progress message. */
-void ppc64_dump_msg(unsigned int src, const char *msg);
 
 static inline void log_error(char *buf, unsigned int err_type, int fatal)
 {
index 6b4a5b1f695e916cf72b38f29ec44f8ed1e132ec..d8991389ab3960c598fbd030c7dc6e0385f40b90 100644 (file)
@@ -119,5 +119,10 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
        return PCI_DN(busdn)->phb;
 }
 
+/* Return values for ppc_md.pci_probe_mode function */
+#define PCI_PROBE_NONE         -1      /* Don't look at this bus at all */
+#define PCI_PROBE_NORMAL       0       /* Do normal PCI probing */
+#define PCI_PROBE_DEVTREE      1       /* Instantiate from device tree */
+
 #endif
 #endif /* __KERNEL__ */
index f4a5fb7d67c7ccd24a0aa82c06672e8f54461565..72dd2449ee76224f6f9f1748e5ef69c81b4843bd 100644 (file)
@@ -107,5 +107,14 @@ static inline long plpar_put_term_char(unsigned long termno,
                                  lbuf[1]);
 }
 
+static inline long plpar_set_xdabr(unsigned long address, unsigned long flags)
+{
+       return plpar_hcall_norets(H_SET_XDABR, address, flags);
+}
+
+static inline long plpar_set_dabr(unsigned long val)
+{
+       return plpar_hcall_norets(H_SET_DABR, val);
+}
 
 #endif /* _PPC64_PLPAR_WRAPPERS_H */
index 8bd7aa959385d01d33c530526609e7302cf97921..4146189006e32cac1d8d11d618e8f02498bfe1ce 100644 (file)
@@ -433,6 +433,7 @@ struct thread_struct {
        unsigned long   start_tb;       /* Start purr when proc switched in */
        unsigned long   accum_tb;       /* Total accumilated purr for process */
        unsigned long   vdso_base;      /* base of the vDSO library */
+       unsigned long   dabr;           /* Data address breakpoint register */
 #ifdef CONFIG_ALTIVEC
        /* Complete AltiVec register set */
        vector128       vr[32] __attribute((aligned(16)));
index af03547f9c7edf4151afbbb3f29d5bbd89fddba6..b1babb7296733632baeaa2ea60a21e0399bc60e0 100644 (file)
 
 #ifndef _PPC64_PTRACE_COMMON_H
 #define _PPC64_PTRACE_COMMON_H
+
+#include <linux/config.h>
+#include <asm/system.h>
+
 /*
  * Set of msr bits that gdb can change on behalf of a process.
  */
@@ -69,4 +73,92 @@ static inline void clear_single_step(struct task_struct *task)
        clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP);
 }
 
+#ifdef CONFIG_ALTIVEC
+/*
+ * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
+ * The transfer totals 34 quadword.  Quadwords 0-31 contain the
+ * corresponding vector registers.  Quadword 32 contains the vscr as the
+ * last word (offset 12) within that quadword.  Quadword 33 contains the
+ * vrsave as the first word (offset 0) within the quadword.
+ *
+ * This definition of the VMX state is compatible with the current PPC32
+ * ptrace interface.  This allows signal handling and ptrace to use the
+ * same structures.  This also simplifies the implementation of a bi-arch
+ * (combined (32- and 64-bit) gdb.
+ */
+
+/*
+ * Get contents of AltiVec register state in task TASK
+ */
+static inline int get_vrregs(unsigned long __user *data,
+                            struct task_struct *task)
+{
+       unsigned long regsize;
+
+       /* copy AltiVec registers VR[0] .. VR[31] */
+       regsize = 32 * sizeof(vector128);
+       if (copy_to_user(data, task->thread.vr, regsize))
+               return -EFAULT;
+       data += (regsize / sizeof(unsigned long));
+
+       /* copy VSCR */
+       regsize = 1 * sizeof(vector128);
+       if (copy_to_user(data, &task->thread.vscr, regsize))
+               return -EFAULT;
+       data += (regsize / sizeof(unsigned long));
+
+       /* copy VRSAVE */
+       if (put_user(task->thread.vrsave, (u32 __user *)data))
+               return -EFAULT;
+
+       return 0;
+}
+
+/*
+ * Write contents of AltiVec register state into task TASK.
+ */
+static inline int set_vrregs(struct task_struct *task,
+                            unsigned long __user *data)
+{
+       unsigned long regsize;
+
+       /* copy AltiVec registers VR[0] .. VR[31] */
+       regsize = 32 * sizeof(vector128);
+       if (copy_from_user(task->thread.vr, data, regsize))
+               return -EFAULT;
+       data += (regsize / sizeof(unsigned long));
+
+       /* copy VSCR */
+       regsize = 1 * sizeof(vector128);
+       if (copy_from_user(&task->thread.vscr, data, regsize))
+               return -EFAULT;
+       data += (regsize / sizeof(unsigned long));
+
+       /* copy VRSAVE */
+       if (get_user(task->thread.vrsave, (u32 __user *)data))
+               return -EFAULT;
+
+       return 0;
+}
+#endif
+
+static inline int ptrace_set_debugreg(struct task_struct *task,
+                                     unsigned long addr, unsigned long data)
+{
+       /* We only support one DABR and no IABRS at the moment */
+       if (addr > 0)
+               return -EINVAL;
+
+       /* The bottom 3 bits are flags */
+       if ((data & ~0x7UL) >= TASK_SIZE)
+               return -EIO;
+
+       /* Ensure translation is on */
+       if (data && !(data & DABR_TRANSLATION))
+               return -EIO;
+
+       task->thread.dabr = data;
+       return 0;
+}
+
 #endif /* _PPC64_PTRACE_COMMON_H */
index c96aad28fc081fc721d8c66fbca460864f1ea7b5..3a55377f1fd30fe2781c7cd817f2ca283f832265 100644 (file)
  */
 
 #ifndef __ASSEMBLY__
-#define PPC_REG unsigned long
+
 struct pt_regs {
-       PPC_REG gpr[32];
-       PPC_REG nip;
-       PPC_REG msr;
-       PPC_REG orig_gpr3;      /* Used for restarting system calls */
-       PPC_REG ctr;
-       PPC_REG link;
-       PPC_REG xer;
-       PPC_REG ccr;
-       PPC_REG softe;          /* Soft enabled/disabled */
-       PPC_REG trap;           /* Reason for being here */
-       PPC_REG dar;            /* Fault registers */
-       PPC_REG dsisr;
-       PPC_REG result;         /* Result of a system call */
+       unsigned long gpr[32];
+       unsigned long nip;
+       unsigned long msr;
+       unsigned long orig_gpr3; /* Used for restarting system calls */
+       unsigned long ctr;
+       unsigned long link;
+       unsigned long xer;
+       unsigned long ccr;
+       unsigned long softe;    /* Soft enabled/disabled */
+       unsigned long trap;     /* Reason for being here */
+       unsigned long dar;      /* Fault registers */
+       unsigned long dsisr;
+       unsigned long result;   /* Result of a system call */
 };
 
-#define PPC_REG_32 unsigned int
 struct pt_regs32 {
-       PPC_REG_32 gpr[32];
-       PPC_REG_32 nip;
-       PPC_REG_32 msr;
-       PPC_REG_32 orig_gpr3;   /* Used for restarting system calls */
-       PPC_REG_32 ctr;
-       PPC_REG_32 link;
-       PPC_REG_32 xer;
-       PPC_REG_32 ccr;
-       PPC_REG_32 mq;          /* 601 only (not used at present) */
-                               /* Used on APUS to hold IPL value. */
-       PPC_REG_32 trap;                /* Reason for being here */
-       PPC_REG_32 dar;         /* Fault registers */
-       PPC_REG_32 dsisr;
-       PPC_REG_32 result;      /* Result of a system call */
+       unsigned int gpr[32];
+       unsigned int nip;
+       unsigned int msr;
+       unsigned int orig_gpr3; /* Used for restarting system calls */
+       unsigned int ctr;
+       unsigned int link;
+       unsigned int xer;
+       unsigned int ccr;
+       unsigned int mq;        /* 601 only (not used at present) */
+       unsigned int trap;      /* Reason for being here */
+       unsigned int dar;       /* Fault registers */
+       unsigned int dsisr;
+       unsigned int result;    /* Result of a system call */
 };
 
+#ifdef __KERNEL__
+
 #define instruction_pointer(regs) ((regs)->nip)
+
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
 #else
 #define profile_pc(regs) instruction_pointer(regs)
 #endif
 
-#endif /* __ASSEMBLY__ */
-
-#define STACK_FRAME_OVERHEAD   112     /* size of minimum stack frame */
-
-/* Size of dummy stack frame allocated when calling signal handler. */
-#define __SIGNAL_FRAMESIZE     128
-#define __SIGNAL_FRAMESIZE32   64
-
 #define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
 
 #define force_successful_syscall_return()   \
@@ -89,6 +82,16 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 #define TRAP(regs)             ((regs)->trap & ~0xF)
 #define CHECK_FULL_REGS(regs)  BUG_ON(regs->trap & 1)
 
+#endif /* __KERNEL__ */
+
+#endif /* __ASSEMBLY__ */
+
+#define STACK_FRAME_OVERHEAD   112     /* size of minimum stack frame */
+
+/* Size of dummy stack frame allocated when calling signal handler. */
+#define __SIGNAL_FRAMESIZE     128
+#define __SIGNAL_FRAMESIZE32   64
+
 /*
  * Offsets used by 'ptrace' system call interface.
  */
@@ -135,17 +138,21 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 #define PT_XER 37
 #define PT_CCR 38
 #define PT_SOFTE 39
+#define PT_TRAP        40
+#define PT_DAR 41
+#define PT_DSISR 42
 #define PT_RESULT 43
 
 #define PT_FPR0        48
 
-/* Kernel and userspace will both use this PT_FPSCR value.  32-bit apps will have
- * visibility to the asm-ppc/ptrace.h header instead of this one.
+/*
+ * Kernel and userspace will both use this PT_FPSCR value.  32-bit apps will
+ * have visibility to the asm-ppc/ptrace.h header instead of this one.
  */
-#define PT_FPSCR (PT_FPR0 + 32)          /* each FP reg occupies 1 slot in 64-bit space */
+#define PT_FPSCR (PT_FPR0 + 32)        /* each FP reg occupies 1 slot in 64-bit space */
 
 #ifdef __KERNEL__
-#define PT_FPSCR32 (PT_FPR0 + 2*32 + 1)          /* each FP reg occupies 2 32-bit userspace slots */
+#define PT_FPSCR32 (PT_FPR0 + 2*32 + 1)        /* each FP reg occupies 2 32-bit userspace slots */
 #endif
 
 #define PT_VR0 82      /* each Vector reg occupies 2 slots in 64-bit */
@@ -173,17 +180,34 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 #define PTRACE_GETVRREGS       18
 #define PTRACE_SETVRREGS       19
 
-/* Additional PTRACE requests implemented on PowerPC. */
-#define PPC_PTRACE_GETREGS           0x99  /* Get GPRs 0 - 31 */
-#define PPC_PTRACE_SETREGS           0x98  /* Set GPRs 0 - 31 */
-#define PPC_PTRACE_GETFPREGS       0x97  /* Get FPRs 0 - 31 */
-#define PPC_PTRACE_SETFPREGS       0x96  /* Set FPRs 0 - 31 */
-#define PPC_PTRACE_PEEKTEXT_3264  0x95  /* Read word at location ADDR on a 64-bit process from a 32-bit process. */
-#define PPC_PTRACE_PEEKDATA_3264  0x94  /* Read word at location ADDR on a 64-bit process from a 32-bit process. */
-#define PPC_PTRACE_POKETEXT_3264  0x93  /* Write word at location ADDR on a 64-bit process from a 32-bit process. */
-#define PPC_PTRACE_POKEDATA_3264  0x92  /* Write word at location ADDR on a 64-bit process from a 32-bit process. */
-#define PPC_PTRACE_PEEKUSR_3264   0x91  /* Read a register (specified by ADDR) out of the "user area" on a 64-bit process from a 32-bit process. */
-#define PPC_PTRACE_POKEUSR_3264   0x90  /* Write DATA into location ADDR within the "user area" on a 64-bit process from a 32-bit process. */
+/*
+ * While we dont have 64bit book E processors, we need to reserve the
+ * relevant ptrace calls for 32bit compatibility.
+ */
+#if 0
+#define PTRACE_GETEVRREGS       20
+#define PTRACE_SETEVRREGS       21
+#endif
 
+/*
+ * Get or set a debug register. The first 16 are DABR registers and the
+ * second 16 are IABR registers.
+ */
+#define PTRACE_GET_DEBUGREG    25
+#define PTRACE_SET_DEBUGREG    26
+
+/* Additional PTRACE requests implemented on PowerPC. */
+#define PPC_PTRACE_GETREGS     0x99    /* Get GPRs 0 - 31 */
+#define PPC_PTRACE_SETREGS     0x98    /* Set GPRs 0 - 31 */
+#define PPC_PTRACE_GETFPREGS   0x97    /* Get FPRs 0 - 31 */
+#define PPC_PTRACE_SETFPREGS   0x96    /* Set FPRs 0 - 31 */
+
+/* Calls to trace a 64bit program from a 32bit program */
+#define PPC_PTRACE_PEEKTEXT_3264 0x95
+#define PPC_PTRACE_PEEKDATA_3264 0x94
+#define PPC_PTRACE_POKETEXT_3264 0x93
+#define PPC_PTRACE_POKEDATA_3264 0x92
+#define PPC_PTRACE_PEEKUSR_3264  0x91
+#define PPC_PTRACE_POKEUSR_3264  0x90
 
 #endif /* _PPC64_PTRACE_H */
index c0396428cc3c0c908bb723c111adff2a1d44ebac..375015c62f2071083b0114040404719fccc58818 100644 (file)
@@ -101,6 +101,9 @@ static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; }
 static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
 #endif
 
+extern int set_dabr(unsigned long dabr);
+extern void _exception(int signr, struct pt_regs *regs, int code,
+                      unsigned long addr);
 extern int fix_alignment(struct pt_regs *regs);
 extern void bad_page_fault(struct pt_regs *regs, unsigned long address,
                           int sig);
index ecb909572d3fc955efba94c6bb1035f28e203ab0..0f4bcaae61bd74265361e381356c51bc20fe2c70 100644 (file)
@@ -277,9 +277,6 @@ typedef pte_t *pte_addr_t;
 
 #define kern_addr_valid(addr)  (1)
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index 78ac6be2d9ef0ebe6de29d7e4f8a5a7be3e91e34..51db4307bfaf9fd2be6733490d39be673df2fe17 100644 (file)
@@ -482,9 +482,6 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
 #define PageSkip(page)         (0)
 #define kern_addr_valid(addr)  (1)
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index 16ec82e16b21aa18e400e269f386b3d52b3d9ee0..6c5d5ca8383a2abf4e2bd437bdb4ea865a6ec1e5 100644 (file)
@@ -109,9 +109,10 @@ extern unsigned int nmi_watchdog;
 #define NMI_LOCAL_APIC 2
 #define NMI_INVALID    3
 
+extern int disable_timer_pin_1;
+
 #endif /* CONFIG_X86_LOCAL_APIC */
 
-#define esr_disable 0
 extern unsigned boot_cpu_id;
 
 #endif /* __ASM_APIC_H */
index 9388062c4f6e52fd409ef099395ca55be862c21d..fb1c99ac669fda16727616a5172aac3c44de2c51 100644 (file)
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
 
 #define MAX_IO_APICS 128
+#define MAX_LOCAL_APIC 256
 
 /*
  * All x86-64 systems are xAPIC compatible.
index eed785667289fa34b0e287ba7240db98ab9866d3..80ac1fe966ac13ec3be908b2ec94bfaccefb40cc 100644 (file)
@@ -9,10 +9,8 @@
  */
 struct bug_frame {
        unsigned char ud2[2];
-       unsigned char mov;
-       /* should use 32bit offset instead, but the assembler doesn't 
-          like it */
-       char *filename;
+       unsigned char push;
+       signed int filename;
        unsigned char ret;
        unsigned short line;
 } __attribute__((packed));
@@ -25,8 +23,8 @@ struct bug_frame {
    The magic numbers generate mov $64bitimm,%eax ; ret $offset. */
 #define BUG()                                                          \
        asm volatile(                                                   \
-       "ud2 ; .byte 0xa3 ; .quad %c1 ; .byte 0xc2 ; .short %c0" ::     \
-                    "i"(__LINE__), "i" (__stringify(__FILE__)))
+       "ud2 ; pushq $%c1 ; ret $%c0" ::                                \
+                    "i"(__LINE__), "i" (__FILE__))
 void out_of_line_bug(void);
 #else
 static inline void out_of_line_bug(void) { }
index 0bc12655fa5be49e1feada576d01ba3a297b881c..fc2c5a6c262a20356c1fc1dc5e475fa84d97189c 100644 (file)
        .if \skipr11
        .else
        movq (%rsp),%r11
+       CFI_RESTORE r11
        .endif
        .if \skipr8910
        .else
        movq 1*8(%rsp),%r10
+       CFI_RESTORE r10
        movq 2*8(%rsp),%r9
+       CFI_RESTORE r9
        movq 3*8(%rsp),%r8
+       CFI_RESTORE r8
        .endif
        .if \skiprax
        .else
        movq 4*8(%rsp),%rax
+       CFI_RESTORE rax
        .endif
        .if \skiprcx
        .else
        movq 5*8(%rsp),%rcx
+       CFI_RESTORE rcx
        .endif
        .if \skiprdx
        .else
        movq 6*8(%rsp),%rdx
+       CFI_RESTORE rdx
        .endif
        movq 7*8(%rsp),%rsi
+       CFI_RESTORE rsi
        movq 8*8(%rsp),%rdi
+       CFI_RESTORE rdi
        .if ARG_SKIP+\addskip > 0
        addq $ARG_SKIP+\addskip,%rsp
        CFI_ADJUST_CFA_OFFSET   -(ARG_SKIP+\addskip)
 
        .macro RESTORE_REST
        movq (%rsp),%r15
+       CFI_RESTORE r15
        movq 1*8(%rsp),%r14
+       CFI_RESTORE r14
        movq 2*8(%rsp),%r13
+       CFI_RESTORE r13
        movq 3*8(%rsp),%r12
+       CFI_RESTORE r12
        movq 4*8(%rsp),%rbp
+       CFI_RESTORE rbp
        movq 5*8(%rsp),%rbx
+       CFI_RESTORE rbx
        addq $REST_SKIP,%rsp
        CFI_ADJUST_CFA_OFFSET   -(REST_SKIP)
        .endm
        .macro icebp
        .byte 0xf1
        .endm
-
-#ifdef CONFIG_FRAME_POINTER
-#define ENTER enter
-#define LEAVE leave
-#else
-#define ENTER
-#define LEAVE
-#endif
index c89b58bebee24619f9ae2b5ad903b752f5e1ec12..594e610f4a1e7d66aff1a12aa3666e7af8e9dd0a 100644 (file)
@@ -191,7 +191,7 @@ static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
 /*
  * load one particular LDT into the current CPU
  */
-extern inline void load_LDT_nolock (mm_context_t *pc, int cpu)
+static inline void load_LDT_nolock (mm_context_t *pc, int cpu)
 {
        int count = pc->size;
 
index a416dc31634a207fa4ff3330810ef20dce2829c9..e784fdc524f1ac7be2dce7930995cccab58dc0f6 100644 (file)
@@ -85,6 +85,11 @@ static inline void dma_sync_single_for_device(struct device *hwdev,
        flush_write_buffers();
 }
 
+#define dma_sync_single_range_for_cpu(dev, dma_handle, offset, size, dir)       \
+        dma_sync_single_for_cpu(dev, dma_handle, size, dir)
+#define dma_sync_single_range_for_device(dev, dma_handle, offset, size, dir)    \
+        dma_sync_single_for_device(dev, dma_handle, size, dir)
+
 static inline void dma_sync_sg_for_cpu(struct device *hwdev,
                                       struct scatterlist *sg,
                                       int nelems, int direction)
index afd4212e860bd4e93409c16d38f0184c47c292f4..582757fc03655423d12d96b7baf43d986e6fe031 100644 (file)
 #define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
 #define CFI_OFFSET .cfi_offset
 #define CFI_REL_OFFSET .cfi_rel_offset
+#define CFI_REGISTER .cfi_register
+#define CFI_RESTORE .cfi_restore
+#define CFI_REMEMBER_STATE .cfi_remember_state
+#define CFI_RESTORE_STATE .cfi_restore_state
 
 #else
 
 #define CFI_ADJUST_CFA_OFFSET  #
 #define CFI_OFFSET     #
 #define CFI_REL_OFFSET #
+#define CFI_REGISTER   #
+#define CFI_RESTORE    #
+#define CFI_REMEMBER_STATE     #
+#define CFI_RESTORE_STATE      #
 
 #endif
 
index cf8b16cbe8db65e40ce5a84e6e18c8decdcba931..a582cfcf2231a631564bac9aeda0a4422d8f0ca6 100644 (file)
@@ -76,7 +76,7 @@ extern void __this_fixmap_does_not_exist(void);
  * directly without translation, we catch the bug with a NULL-deference
  * kernel oops. Illegal ranges of incoming indices are caught too.
  */
-extern inline unsigned long fix_to_virt(const unsigned int idx)
+static inline unsigned long fix_to_virt(const unsigned int idx)
 {
        /*
         * this branch gets completely eliminated after inlining,
index 27c381fa1c9d0e15eb0ff5e60c901a24336bd714..8661b476fb404f74e14d4ed7342e92575c37c50d 100644 (file)
@@ -9,11 +9,12 @@
 
 #define __ARCH_IRQ_STAT 1
 
-/* Generate a lvalue for a pda member. Should fix softirq.c instead to use
-   special access macros. This would generate better code. */ 
-#define __IRQ_STAT(cpu,member) (read_pda(me)->member)
+#define local_softirq_pending() read_pda(__softirq_pending)
 
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+#define __ARCH_SET_SOFTIRQ_PENDING 1
+
+#define set_softirq_pending(x) write_pda(__softirq_pending, (x))
+#define or_softirq_pending(x)  or_pda(__softirq_pending, (x))
 
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
index 2b5cb2865d21de2b835da29788c5b5456e5f2670..dc97668ea0f9d3bc76ffa960fdfc50e596745847 100644 (file)
@@ -26,6 +26,7 @@
 struct hw_interrupt_type;
 #endif
 
+#define NMI_VECTOR             0x02
 /*
  * IDT vectors usable for external interrupt sources start
  * at 0x20:
@@ -50,14 +51,15 @@ struct hw_interrupt_type;
  */
 #define SPURIOUS_APIC_VECTOR   0xff
 #define ERROR_APIC_VECTOR      0xfe
-#define INVALIDATE_TLB_VECTOR  0xfd
-#define RESCHEDULE_VECTOR      0xfc
-#define TASK_MIGRATION_VECTOR  0xfb
-#define CALL_FUNCTION_VECTOR   0xfa
-#define KDB_VECTOR     0xf9
-
-#define THERMAL_APIC_VECTOR    0xf0
-
+#define RESCHEDULE_VECTOR      0xfd
+#define CALL_FUNCTION_VECTOR   0xfc
+#define KDB_VECTOR             0xfb    /* reserved for KDB */
+#define THERMAL_APIC_VECTOR    0xfa
+/* 0xf9 free */
+#define INVALIDATE_TLB_VECTOR_END      0xf8
+#define INVALIDATE_TLB_VECTOR_START    0xf0    /* f0-f8 used for TLB flush */
+
+#define NUM_INVALIDATE_TLB_VECTORS     8
 
 /*
  * Local APIC timer IRQ vector is on a different priority level,
index 37fc3f149a5a6a2cf54cf194303d3975d32e85b9..52ff269fe05473ff255d8ced8c87f80a274e57b9 100644 (file)
@@ -48,7 +48,7 @@
  * Talk about misusing macros..
  */
 #define __OUT1(s,x) \
-extern inline void out##s(unsigned x value, unsigned short port) {
+static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
 __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
@@ -58,7 +58,7 @@ __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
 __OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
 
 #define __IN1(s) \
-extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
 __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
@@ -68,12 +68,12 @@ __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 __IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 
 #define __INS(s) \
-extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
 { __asm__ __volatile__ ("rep ; ins" #s \
 : "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
 
 #define __OUTS(s) \
-extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
 { __asm__ __volatile__ ("rep ; outs" #s \
 : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
 
@@ -110,12 +110,12 @@ __OUTS(l)
  * Change virtual addresses to physical addresses and vv.
  * These are pretty trivial
  */
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
        return __pa(address);
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
        return __va(address);
 }
@@ -130,7 +130,7 @@ extern inline void * phys_to_virt(unsigned long address)
 
 extern void __iomem *__ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
-extern inline void __iomem * ioremap (unsigned long offset, unsigned long size)
+static inline void __iomem * ioremap (unsigned long offset, unsigned long size)
 {
        return __ioremap(offset, size, 0);
 }
index 5e166b9d3bdeb766cb406eaeea764ef9402fb47d..022e9d340ad759cbc763458ed5df2cc186f2eafe 100644 (file)
 
 static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector, unsigned int dest)
 {
-       unsigned int icr =  APIC_DM_FIXED | shortcut | vector | dest;
-       if (vector == KDB_VECTOR)
-               icr = (icr & (~APIC_VECTOR_MASK)) | APIC_DM_NMI;
+       unsigned int icr = shortcut | dest;
+
+       switch (vector) {
+       default:
+               icr |= APIC_DM_FIXED | vector;
+               break;
+       case NMI_VECTOR:
+               /*
+                * Setup KDB IPI to be delivered as an NMI
+                */
+       case KDB_VECTOR:
+               icr |= APIC_DM_NMI;
+               break;
+       }
        return icr;
 }
 
@@ -66,7 +77,7 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, unsign
        /*
         * Send the IPI. The write to APIC_ICR fires this off.
         */
-       apic_write_around(APIC_ICR, cfg);
+       apic_write(APIC_ICR, cfg);
 }
 
 
@@ -92,7 +103,7 @@ static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
                 * prepare target chip field
                 */
                cfg = __prepare_ICR2(x86_cpu_to_apicid[query_cpu]);
-               apic_write_around(APIC_ICR2, cfg);
+               apic_write(APIC_ICR2, cfg);
 
                /*
                 * program the ICR
@@ -102,7 +113,7 @@ static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
                /*
                 * Send the IPI. The write to APIC_ICR fires this off.
                 */
-               apic_write_around(APIC_ICR, cfg);
+               apic_write(APIC_ICR, cfg);
        }
        local_irq_restore(flags);
 }
index b90341994d80f6e78d18f685cca99e15baea8e37..f604e84c53039e784e10605b3b3e428af9d91deb 100644 (file)
@@ -46,7 +46,7 @@ extern void die(const char *,struct pt_regs *,long);
 extern void __die(const char *,struct pt_regs *,long);
 extern void show_registers(struct pt_regs *regs);
 extern void dump_pagetable(unsigned long);
-extern void oops_begin(void);
-extern void oops_end(void);
+extern unsigned long oops_begin(void);
+extern void oops_end(unsigned long);
 
 #endif
index c954f15c1a755f850c60b7e0f0c05a17b1feb2b8..3e72c41727c53af2f7ea75666aab6da56be79a5f 100644 (file)
@@ -29,7 +29,7 @@ static __inline__ void local_dec(local_t *v)
                :"m" (v->counter));
 }
 
-static __inline__ void local_add(unsigned long i, local_t *v)
+static __inline__ void local_add(unsigned int i, local_t *v)
 {
        __asm__ __volatile__(
                "addl %1,%0"
@@ -37,7 +37,7 @@ static __inline__ void local_add(unsigned long i, local_t *v)
                :"ir" (i), "m" (v->counter));
 }
 
-static __inline__ void local_sub(unsigned long i, local_t *v)
+static __inline__ void local_sub(unsigned int i, local_t *v)
 {
        __asm__ __volatile__(
                "subl %1,%0"
index 768413751b34288c0eb6b1ae5b56f4c5eecb3d13..b40c661f111e32b58f2c07bdd081a89fa4aa4b40 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <asm/smp.h>
 
-#define NODEMAPSIZE 0xff
+#define NODEMAPSIZE 0xfff
 
 /* Simple perfect hash to map physical addresses to node numbers */
 extern int memnode_shift; 
@@ -54,7 +54,7 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
 
 #define pfn_valid(pfn) ((pfn) >= num_physpages ? 0 : \
                        ({ u8 nid__ = pfn_to_nid(pfn); \
-                          nid__ != 0xff && (pfn) >= node_start_pfn(nid__) && (pfn) <= node_end_pfn(nid__); }))
+                          nid__ != 0xff && (pfn) >= node_start_pfn(nid__) && (pfn) < node_end_pfn(nid__); }))
 #endif
 
 #define local_mapnr(kvaddr) \
index ba15279a79d02f826e2c8d79f58d14d50671bfdf..4d727f3f5550bb2eadba0a20829bbf96ff970050 100644 (file)
 #define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32) 
 
 /* wrmsr with exception handling */
-#define wrmsr_safe(msr,a,b) ({ int ret__;                                              \
-       asm volatile("2: wrmsr ; xorl %0,%0\n"                                          \
-                    "1:\n\t"                                                           \
-                    ".section .fixup,\"ax\"\n\t"                                       \
-                    "3:  movl %4,%0 ; jmp 1b\n\t"                                      \
-                    ".previous\n\t"                                                    \
-                    ".section __ex_table,\"a\"\n"                                      \
-                    "   .align 8\n\t"                                                  \
-                    "   .quad  2b,3b\n\t"                                              \
-                    ".previous"                                                        \
-                    : "=a" (ret__)                                                     \
-                    : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
+#define wrmsr_safe(msr,a,b) ({ int ret__;                      \
+       asm volatile("2: wrmsr ; xorl %0,%0\n"                  \
+                    "1:\n\t"                                   \
+                    ".section .fixup,\"ax\"\n\t"               \
+                    "3:  movl %4,%0 ; jmp 1b\n\t"              \
+                    ".previous\n\t"                            \
+                    ".section __ex_table,\"a\"\n"              \
+                    "   .align 8\n\t"                          \
+                    "   .quad  2b,3b\n\t"                      \
+                    ".previous"                                \
+                    : "=a" (ret__)                             \
+                    : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT)); \
        ret__; })
 
 #define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32))
 
+#define rdmsr_safe(msr,a,b) \
+       ({ int ret__;                                           \
+         asm volatile ("1:       rdmsr\n"                      \
+                      "2:\n"                                   \
+                      ".section .fixup,\"ax\"\n"               \
+                      "3:       movl %4,%0\n"                  \
+                      " jmp 2b\n"                              \
+                      ".previous\n"                            \
+                      ".section __ex_table,\"a\"\n"            \
+                      " .align 8\n"                            \
+                      " .quad 1b,3b\n"                         \
+                      ".previous":"=&bDS" (ret__), "=a"(a), "=d"(b)\
+                      :"c"(msr), "i"(-EIO), "0"(0));           \
+         ret__; })             
+
 #define rdtsc(low,high) \
      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
 
@@ -64,7 +79,7 @@
                          : "=a" (low), "=d" (high) \
                          : "c" (counter))
 
-extern inline void cpuid(int op, unsigned int *eax, unsigned int *ebx,
+static inline void cpuid(int op, unsigned int *eax, unsigned int *ebx,
                         unsigned int *ecx, unsigned int *edx)
 {
        __asm__("cpuid"
@@ -90,7 +105,7 @@ static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
 /*
  * CPUID functions returning a single datum
  */
-extern inline unsigned int cpuid_eax(unsigned int op)
+static inline unsigned int cpuid_eax(unsigned int op)
 {
        unsigned int eax;
 
@@ -100,7 +115,7 @@ extern inline unsigned int cpuid_eax(unsigned int op)
                : "bx", "cx", "dx");
        return eax;
 }
-extern inline unsigned int cpuid_ebx(unsigned int op)
+static inline unsigned int cpuid_ebx(unsigned int op)
 {
        unsigned int eax, ebx;
 
@@ -110,7 +125,7 @@ extern inline unsigned int cpuid_ebx(unsigned int op)
                : "cx", "dx" );
        return ebx;
 }
-extern inline unsigned int cpuid_ecx(unsigned int op)
+static inline unsigned int cpuid_ecx(unsigned int op)
 {
        unsigned int eax, ecx;
 
@@ -120,7 +135,7 @@ extern inline unsigned int cpuid_ecx(unsigned int op)
                : "bx", "dx" );
        return ecx;
 }
-extern inline unsigned int cpuid_edx(unsigned int op)
+static inline unsigned int cpuid_edx(unsigned int op)
 {
        unsigned int eax, edx;
 
index 5c363a1482e43ecada598942d124b87d64a0041a..bcf55c3f7f7f35e0f162c504c5f6030578a857f8 100644 (file)
@@ -9,6 +9,7 @@ struct node {
 };
 
 extern int compute_hash_shift(struct node *nodes, int numnodes);
+extern int pxm_to_node(int nid);
 
 #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
 
@@ -16,6 +17,8 @@ extern void numa_add_cpu(int cpu);
 extern void numa_init_array(void);
 extern int numa_off;
 
+extern unsigned char apicid_to_node[256];
+
 #define NUMA_NO_NODE 0xff
 
 #endif
index 135ffaa0393b4d8aa5559241d0f512fb61251742..e5ab4d231f2ce2d837dea8476e7a024f5436060a 100644 (file)
@@ -32,6 +32,8 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
+extern unsigned long end_pfn;
+
 void clear_page(void *);
 void copy_page(void *, void *);
 
@@ -111,7 +113,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #ifdef CONFIG_FLATMEM
 #define pfn_to_page(pfn)       (mem_map + (pfn))
 #define page_to_pfn(page)      ((unsigned long)((page) - mem_map))
-#define pfn_valid(pfn)         ((pfn) < max_mapnr)
+#define pfn_valid(pfn)         ((pfn) < end_pfn)
 #endif
 
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
index eeb3088a1c9e3d2fbbff1140b94fad85c69777f9..5a82a6762c2183411c5af255c8c32f2140a0e8c0 100644 (file)
@@ -50,10 +50,10 @@ extern int iommu_setup(char *opt);
  * address space.  The networking and block device layers use
  * this boolean for bounce buffer decisions
  *
- * On AMD64 it mostly equals, but we set it to zero to tell some subsystems
- * that an IOMMU is available.
+ * On x86-64 it mostly equals, but we set it to zero to tell some subsystems
+ * that an hard or soft IOMMU is available.
  */
-#define PCI_DMA_BUS_IS_PHYS    (no_iommu ? 1 : 0)
+#define PCI_DMA_BUS_IS_PHYS 0
 
 /*
  * x86-64 always supports DAC, but sometimes it is useful to force
index 36b766cfc4d5630992c14e374d3a550fab7a54eb..bbf89aa8a1afe67a7178b5ada67c3e7368e71484 100644 (file)
 struct x8664_pda {
        struct task_struct *pcurrent;   /* Current process */
        unsigned long data_offset;      /* Per cpu data offset from linker address */
-       struct x8664_pda *me;       /* Pointer to itself */  
        unsigned long kernelstack;  /* top of kernel stack for current */ 
        unsigned long oldrsp;       /* user rsp for system call */
-       unsigned long irqrsp;       /* Old rsp for interrupts. */ 
         int irqcount;              /* Irq nesting counter. Starts with -1 */   
        int cpunumber;              /* Logical CPU number */
        char *irqstackptr;      /* top of irqstack */
@@ -22,7 +20,7 @@ struct x8664_pda {
        struct mm_struct *active_mm;
        int mmu_state;     
        unsigned apic_timer_irqs;
-} ____cacheline_aligned;
+} ____cacheline_aligned_in_smp;
 
 
 #define IRQSTACK_ORDER 2
@@ -42,13 +40,14 @@ extern void __bad_pda_field(void);
 #define pda_offset(field) offsetof(struct x8664_pda, field)
 
 #define pda_to_op(op,field,val) do { \
+       typedef typeof_field(struct x8664_pda, field) T__; \
        switch (sizeof_field(struct x8664_pda, field)) {                \
 case 2: \
-asm volatile(op "w %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \
+asm volatile(op "w %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
 case 4: \
-asm volatile(op "l %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \
+asm volatile(op "l %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
 case 8: \
-asm volatile(op "q %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \
+asm volatile(op "q %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \
        default: __bad_pda_field();                                     \
        } \
        } while (0)
@@ -58,7 +57,7 @@ asm volatile(op "q %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); bre
  * Unfortunately removing them causes all hell to break lose currently.
  */
 #define pda_from_op(op,field) ({ \
-       typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \
+       typeof_field(struct x8664_pda, field) ret__; \
        switch (sizeof_field(struct x8664_pda, field)) {                \
 case 2: \
 asm volatile(op "w %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\
@@ -75,6 +74,7 @@ asm volatile(op "q %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); b
 #define write_pda(field,val) pda_to_op("mov",field,val)
 #define add_pda(field,val) pda_to_op("add",field,val)
 #define sub_pda(field,val) pda_to_op("sub",field,val)
+#define or_pda(field,val) pda_to_op("or",field,val)
 
 #endif
 
index deadd146978b189c002b81feaa305cdd5da3b8da..08cad2482bcbc56e88ac82cbfb82b0f1ff3f97bb 100644 (file)
@@ -18,12 +18,12 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p
        set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)));
 }
 
-extern __inline__ pmd_t *get_pmd(void)
+static inline pmd_t *get_pmd(void)
 {
        return (pmd_t *)get_zeroed_page(GFP_KERNEL);
 }
 
-extern __inline__ void pmd_free(pmd_t *pmd)
+static inline void pmd_free(pmd_t *pmd)
 {
        BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
        free_page((unsigned long)pmd);
@@ -86,13 +86,13 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long add
 /* Should really implement gc for free page table pages. This could be
    done with a reference count in struct page. */
 
-extern __inline__ void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(pte_t *pte)
 {
        BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
        free_page((unsigned long)pte); 
 }
 
-extern inline void pte_free(struct page *pte)
+static inline void pte_free(struct page *pte)
 {
        __free_page(pte);
 } 
index 5e0f2fdab0d35885f75f1177d54d18b4117808ec..2cb483516459dd3efb48fa48269b66c3beb8d072 100644 (file)
@@ -85,7 +85,7 @@ static inline void set_pud(pud_t *dst, pud_t val)
        pud_val(*dst) = pud_val(val);
 }
 
-extern inline void pud_clear (pud_t *pud)
+static inline void pud_clear (pud_t *pud)
 {
        set_pud(pud, __pud(0));
 }
@@ -95,7 +95,7 @@ static inline void set_pgd(pgd_t *dst, pgd_t val)
        pgd_val(*dst) = pgd_val(val); 
 } 
 
-extern inline void pgd_clear (pgd_t * pgd)
+static inline void pgd_clear (pgd_t * pgd)
 {
        set_pgd(pgd, __pgd(0));
 }
@@ -375,7 +375,7 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 }
  
 /* Change flags of a PTE */
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { 
        pte_val(pte) &= _PAGE_CHG_MASK;
        pte_val(pte) |= pgprot_val(newprot);
@@ -421,9 +421,6 @@ extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 extern int kern_addr_valid(unsigned long addr); 
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
                remap_pfn_range(vma, vaddr, pfn, size, prot)
 
index a8321999448f840e256d142a3cf2a62cd62db120..03837d34fba0ccdb4caab752902f1bc943755876 100644 (file)
@@ -254,7 +254,13 @@ struct thread_struct {
        u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
 } __attribute__((aligned(16)));
 
-#define INIT_THREAD  {}
+#define INIT_THREAD  { \
+       .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \
+}
+
+#define INIT_TSS  { \
+       .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \
+}
 
 #define INIT_MMAP \
 { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
@@ -375,13 +381,13 @@ struct extended_sigtable {
 #define ASM_NOP_MAX 8
 
 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-extern inline void rep_nop(void)
+static inline void rep_nop(void)
 {
        __asm__ __volatile__("rep;nop": : :"memory");
 }
 
 /* Stop speculative execution */
-extern inline void sync_core(void)
+static inline void sync_core(void)
 { 
        int tmp;
        asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory");
index f7574196424e1c4e266b1b0d7e9bbd4f5a48f2a3..dbb37b0adb43df3f2ea20d62bc4e398c9bd469be 100644 (file)
@@ -74,9 +74,6 @@ extern void acpi_reserve_bootmem(void);
 
 extern void swap_low_mappings(void);
 
-extern void oops_begin(void);
-extern void die(const char *,struct pt_regs *,long);
-extern void __die(const char * str, struct pt_regs * regs, long err);
 extern void __show_regs(struct pt_regs * regs);
 extern void show_regs(struct pt_regs * regs);
 
@@ -93,8 +90,6 @@ extern int unhandled_signal(struct task_struct *tsk, int sig);
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
 extern void swiotlb_init(void);
 
-extern unsigned long max_mapnr;
-extern unsigned long end_pfn; 
 extern unsigned long table_start, table_end;
 
 extern int exception_trace;
index fe9b96d94815f688091d6c1318e1905d8c995ac8..f8d55798535ac4ccf06e1fc46cbc624a6b68cd76 100644 (file)
@@ -143,23 +143,23 @@ typedef struct sigaltstack {
 #undef __HAVE_ARCH_SIG_BITOPS
 #if 0
 
-extern __inline__ void sigaddset(sigset_t *set, int _sig)
+static inline void sigaddset(sigset_t *set, int _sig)
 {
        __asm__("btsq %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
 }
 
-extern __inline__ void sigdelset(sigset_t *set, int _sig)
+static inline void sigdelset(sigset_t *set, int _sig)
 {
        __asm__("btrq %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
 }
 
-extern __inline__ int __const_sigismember(sigset_t *set, int _sig)
+static inline int __const_sigismember(sigset_t *set, int _sig)
 {
        unsigned long sig = _sig - 1;
        return 1 & (set->sig[sig / _NSIG_BPW] >> (sig & ~(_NSIG_BPW-1)));
 }
 
-extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
+static inline int __gen_sigismember(sigset_t *set, int _sig)
 {
        int ret;
        __asm__("btq %2,%1\n\tsbbq %0,%0"
@@ -172,7 +172,7 @@ extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
         __const_sigismember((set),(sig)) :     \
         __gen_sigismember((set),(sig)))
 
-extern __inline__ int sigfindinword(unsigned long word)
+static inline int sigfindinword(unsigned long word)
 {
        __asm__("bsfq %1,%0" : "=r"(word) : "rm"(word) : "cc");
        return word;
index de8b57b2b62b934c8bfe6cf3b0fa6fd87b8204f8..24e32611f0bf3d93bc0a41f15fa3678d3006f598 100644 (file)
@@ -72,7 +72,7 @@ static inline int num_booting_cpus(void)
 
 #define raw_smp_processor_id() read_pda(cpunumber)
 
-extern __inline int hard_smp_processor_id(void)
+static inline int hard_smp_processor_id(void)
 {
        /* we don't want to mark this access volatile - bad code generation */
        return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
index 8606e170a7dc825c40d10d4101a2c721ff20f536..85348e02ad2e1f847580d21e7e8acd878f83fc4f 100644 (file)
@@ -188,7 +188,7 @@ static inline void write_cr4(unsigned long val)
 
 #define __xg(x) ((volatile long *)(x))
 
-extern inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
+static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
 {
        *ptr = val;
 }
@@ -253,19 +253,19 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
        case 2:
                __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
                                     : "=a"(prev)
-                                    : "q"(new), "m"(*__xg(ptr)), "0"(old)
+                                    : "r"(new), "m"(*__xg(ptr)), "0"(old)
                                     : "memory");
                return prev;
        case 4:
                __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
                                     : "=a"(prev)
-                                    : "q"(new), "m"(*__xg(ptr)), "0"(old)
+                                    : "r"(new), "m"(*__xg(ptr)), "0"(old)
                                     : "memory");
                return prev;
        case 8:
                __asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
                                     : "=a"(prev)
-                                    : "q"(new), "m"(*__xg(ptr)), "0"(old)
+                                    : "r"(new), "m"(*__xg(ptr)), "0"(old)
                                     : "memory");
                return prev;
        }
index 24ecf6a637cb47ce9a5097ad1d7f9fecf1f2b26e..f971f45d6d78b63479fa7cf48e9fb4b9efd11833 100644 (file)
@@ -6,7 +6,6 @@
 #ifndef _ASMx8664_TIMEX_H
 #define _ASMx8664_TIMEX_H
 
-#include <linux/config.h>
 #include <asm/8253pit.h>
 #include <asm/msr.h>
 #include <asm/vsyscall.h>
index 505b0cf906ded2658ff91da72b9d51e54e80adcc..4a9c20ea9b105d9523bb712e0b9a30d93aa30047 100644 (file)
@@ -109,6 +109,10 @@ static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long st
 #define TLBSTATE_OK    1
 #define TLBSTATE_LAZY  2
 
+/* Roughly an IPI every 20MB with 4k pages for freeing page table
+   ranges. Cost is about 42k of memory for each CPU. */
+#define ARCH_FREE_PTE_NR 5350  
+
 #endif
 
 #define flush_tlb_kernel_range(start, end) flush_tlb_all()
index c1bc3fad482ed4a4388412ff300a0395f86178a1..1c603cd7e4d096389d7cf92f11b79afcc338b288 100644 (file)
@@ -13,7 +13,6 @@
 extern cpumask_t cpu_online_map;
 
 extern unsigned char cpu_to_node[];
-extern unsigned char pci_bus_to_node[];
 extern cpumask_t     node_to_cpumask[];
 
 #ifdef CONFIG_ACPI_NUMA
@@ -26,7 +25,7 @@ extern int __node_distance(int, int);
 #define parent_node(node)              (node)
 #define node_to_first_cpu(node)        (__ffs(node_to_cpumask[node]))
 #define node_to_cpumask(node)          (node_to_cpumask[node])
-#define pcibus_to_node(bus)            pci_bus_to_node[(bus)->number]
+#define pcibus_to_node(bus)            ((long)(bus->sysdata))  
 #define pcibus_to_cpumask(bus)         node_to_cpumask(pcibus_to_node(bus));
 
 /* sched_domains SD_NODE_INIT for x86_64 machines */
index 2872da23fc7ea5990feb03c110278e012aea7d15..438a3f52f839fa8161fc5c1ac8f2ec7b8f00ec89 100644 (file)
@@ -29,7 +29,6 @@ enum vsyscall_num {
 
 struct vxtime_data {
        long hpet_address;      /* HPET base address */
-       unsigned long hz;       /* HPET clocks / sec */
        int last;
        unsigned long last_tsc;
        long quot;
index 883ebc2d75d69090f0c044e2556b7df9b324d965..987e3b802313561d837b7f43f1e53133db0d0656 100644 (file)
@@ -441,11 +441,11 @@ extern  void update_mmu_cache(struct vm_area_struct * vma,
                              unsigned long address, pte_t pte);
 
 /*
- * remap a physical address `phys' of size `size' with page protection `prot'
+ * remap a physical page `pfn' of size `size' with page protection `prot'
  * into virtual address `from'
  */
-#define io_remap_page_range(vma,from,phys,size,prot) \
-                remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
+#define io_remap_pfn_range(vma,from,pfn,size,prot) \
+                remap_pfn_range(vma, from, pfn, size, prot)
 
 
 /* No page table caches to init */
diff --git a/include/linux/connector.h b/include/linux/connector.h
new file mode 100644 (file)
index 0000000..96de263
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *     connector.h
+ * 
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 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.  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
+ */
+
+#ifndef __CONNECTOR_H
+#define __CONNECTOR_H
+
+#include <asm/types.h>
+
+#define CN_IDX_CONNECTOR               0xffffffff
+#define CN_VAL_CONNECTOR               0xffffffff
+
+#define CN_NETLINK_USERS               1
+
+/*
+ * Maximum connector's message size.
+ */
+#define CONNECTOR_MAX_MSG_SIZE         1024
+
+/*
+ * idx and val are unique identifiers which 
+ * are used for message routing and 
+ * must be registered in connector.h for in-kernel usage.
+ */
+
+struct cb_id {
+       __u32 idx;
+       __u32 val;
+};
+
+struct cn_msg {
+       struct cb_id id;
+
+       __u32 seq;
+       __u32 ack;
+
+       __u16 len;              /* Length of the following data */
+       __u16 flags;
+       __u8 data[0];
+};
+
+/*
+ * Notify structure - requests notification about
+ * registering/unregistering idx/val in range [first, first+range].
+ */
+struct cn_notify_req {
+       __u32 first;
+       __u32 range;
+};
+
+/*
+ * Main notification control message
+ * *_notify_num        - number of appropriate cn_notify_req structures after 
+ *                             this struct.
+ * group               - notification receiver's idx.
+ * len                         - total length of the attached data.
+ */
+struct cn_ctl_msg {
+       __u32 idx_notify_num;
+       __u32 val_notify_num;
+       __u32 group;
+       __u32 len;
+       __u8 data[0];
+};
+
+#ifdef __KERNEL__
+
+#include <asm/atomic.h>
+
+#include <linux/list.h>
+#include <linux/workqueue.h>
+
+#include <net/sock.h>
+
+#define CN_CBQ_NAMELEN         32
+
+struct cn_queue_dev {
+       atomic_t refcnt;
+       unsigned char name[CN_CBQ_NAMELEN];
+
+       struct workqueue_struct *cn_queue;
+
+       struct list_head queue_list;
+       spinlock_t queue_lock;
+
+       int netlink_groups;
+       struct sock *nls;
+};
+
+struct cn_callback {
+       unsigned char name[CN_CBQ_NAMELEN];
+
+       struct cb_id id;
+       void (*callback) (void *);
+       void *priv;
+};
+
+struct cn_callback_entry {
+       struct list_head callback_entry;
+       struct cn_callback *cb;
+       struct work_struct work;
+       struct cn_queue_dev *pdev;
+
+       void (*destruct_data) (void *);
+       void *ddata;
+
+       int seq, group;
+       struct sock *nls;
+};
+
+struct cn_ctl_entry {
+       struct list_head notify_entry;
+       struct cn_ctl_msg *msg;
+};
+
+struct cn_dev {
+       struct cb_id id;
+
+       u32 seq, groups;
+       struct sock *nls;
+       void (*input) (struct sock * sk, int len);
+
+       struct cn_queue_dev *cbdev;
+};
+
+int cn_add_callback(struct cb_id *, char *, void (*callback) (void *));
+void cn_del_callback(struct cb_id *);
+int cn_netlink_send(struct cn_msg *, u32, int);
+
+int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb);
+void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);
+
+struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *);
+void cn_queue_free_dev(struct cn_queue_dev *dev);
+
+int cn_cb_equal(struct cb_id *, struct cb_id *);
+
+extern int cn_already_initialized;
+
+#endif                         /* __KERNEL__ */
+#endif                         /* __CONNECTOR_H */
index bdedf825b04a5b7dc824b2dc8f7982a4f9bd704b..9443c084f8811d79bbd7904ff14f95fe2ecee42c 100644 (file)
@@ -1,22 +1,11 @@
 /*
  *     crc16.h - CRC-16 routine
  *
- * Implements the standard CRC-16, as used with 1-wire devices:
+ * Implements the standard CRC-16:
  *   Width 16
  *   Poly  0x8005 (x^16 + x^15 + x^2 + 1)
  *   Init  0
  *
- * For 1-wire devices, the CRC is stored inverted, LSB-first
- *
- * Example buffer with the CRC attached:
- *   31 32 33 34 35 36 37 38 39 C2 44
- *
- * The CRC over a buffer with the CRC attached is 0xB001.
- * So, if (crc16(0, buf, size) == 0xB001) then the buffer is valid.
- *
- * Refer to "Application Note 937: Book of iButton Standards" for details.
- * http://www.maxim-ic.com/appnotes.cfm/appnote_number/937
- *
  * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
  *
  * This source code is licensed under the GNU General Public License,
@@ -28,9 +17,6 @@
 
 #include <linux/types.h>
 
-#define CRC16_INIT             0
-#define CRC16_VALID            0xb001
-
 extern u16 const crc16_table[256];
 
 extern u16 crc16(u16 crc, const u8 *buffer, size_t len);
index c30175e8dec67fa39f7a7fb1bf753f4fa40d0dda..a415f1d93e9a4f6c6c647dd851bc19be7ef3035b 100644 (file)
@@ -70,7 +70,7 @@ extern struct dmi_device * dmi_find_device(int type, const char *name,
 
 static inline int dmi_check_system(struct dmi_system_id *list) { return 0; }
 static inline char * dmi_get_system_info(int field) { return NULL; }
-static struct dmi_device * dmi_find_device(int type, const char *name,
+static inline struct dmi_device * dmi_find_device(int type, const char *name,
        struct dmi_device *from) { return NULL; }
 
 #endif
index 82e39cd0c4fbaf5da68d79cdf6affea9da47ec20..c698055266d062b09fa7e19b447144c67fd82c22 100644 (file)
@@ -619,7 +619,7 @@ struct fb_tilemap {
        __u32 height;               /* height of each tile in scanlines */
        __u32 depth;                /* color depth of each tile */
        __u32 length;               /* number of tiles in the map */
-       __u8  *data;                /* actual tile map: a bitmap array, packed
+       const __u8 *data;           /* actual tile map: a bitmap array, packed
                                       to the nearest byte */
 };
 
index 8fc80a7d78ac2e131ce8b7dea5095499a4aa94e5..53b129f07f6f294a896ce4bcc62133641f79d9ef 100644 (file)
@@ -15,9 +15,9 @@
 
 struct font_desc {
     int idx;
-    char *name;
+    const char *name;
     int width, height;
-    void *data;
+    const void *data;
     int pref;
 };
 
@@ -32,7 +32,7 @@ struct font_desc {
 #define ACORN8x8_IDX   8
 #define        MINI4x6_IDX     9
 
-extern struct font_desc        font_vga_8x8,
+extern const struct font_desc  font_vga_8x8,
                        font_vga_8x16,
                        font_pearl_8x8,
                        font_vga_6x11,
@@ -45,11 +45,11 @@ extern struct font_desc     font_vga_8x8,
 
 /* Find a font with a specific name */
 
-extern struct font_desc *find_font(char *name);
+extern const struct font_desc *find_font(const char *name);
 
 /* Get the default font for a specific screen size */
 
-extern struct font_desc *get_default_font(int xres, int yres);
+extern const struct font_desc *get_default_font(int xres, int yres);
 
 /* Max. length for the name of a predefined font */
 #define MAX_FONT_NAME  32
index d99e7aeb7d338a9fde859840ab4aff555f20e488..0a90205184b0b4511776604fd0b37a6fc0cf6bc1 100644 (file)
@@ -57,6 +57,11 @@ extern void disable_irq(unsigned int irq);
 extern void enable_irq(unsigned int irq);
 #endif
 
+#ifndef __ARCH_SET_SOFTIRQ_PENDING
+#define set_softirq_pending(x) (local_softirq_pending() = (x))
+#define or_softirq_pending(x)  (local_softirq_pending() |= (x))
+#endif
+
 /*
  * Temporary defines for UP kernels, until all code gets fixed.
  */
@@ -123,7 +128,7 @@ struct softirq_action
 asmlinkage void do_softirq(void);
 extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data);
 extern void softirq_init(void);
-#define __raise_softirq_irqoff(nr) do { local_softirq_pending() |= 1UL << (nr); } while (0)
+#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0)
 extern void FASTCALL(raise_softirq_irqoff(unsigned int nr));
 extern void FASTCALL(raise_softirq(unsigned int nr));
 
index 687ba8c9973de2d30d97e234817a52e6b2d2f993..4367ce4db52a1a427ba3cdc73d6100371c9f67e4 100644 (file)
@@ -307,8 +307,8 @@ struct sysinfo {
        char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
 };
 
-extern void BUILD_BUG(void);
-#define BUILD_BUG_ON(condition) do { if (condition) BUILD_BUG(); } while(0)
+/* Force a compilation error if condition is false */
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
 
 #ifdef CONFIG_SYSCTL
 extern int randomize_va_space;
index 1675186689361370861897bd7b12a1003c9e5af3..7bbd25970c9ebfb4a5a73ef1b555082e748e6752 100644 (file)
@@ -15,6 +15,7 @@
 #define NETLINK_ISCSI          8       /* Open-iSCSI */
 #define NETLINK_AUDIT          9       /* auditing */
 #define NETLINK_FIB_LOOKUP     10      
+#define NETLINK_CONNECTOR      11
 #define NETLINK_NETFILTER      12      /* netfilter subsystem */
 #define NETLINK_IP6_FW         13
 #define NETLINK_DNRTMSG                14      /* DECnet routing messages */
index 4d24d65c0e88ae44abd098ee1b6aa25fc75f8a40..8903688890cea97f94659c63e453bfb127b393e5 100644 (file)
@@ -438,17 +438,22 @@ extern int nfsd4_process_open1(struct nfsd4_open *open);
 extern int nfsd4_process_open2(struct svc_rqst *rqstp, 
                struct svc_fh *current_fh, struct nfsd4_open *open);
 extern int nfsd4_open_confirm(struct svc_rqst *rqstp, 
-               struct svc_fh *current_fh, struct nfsd4_open_confirm *oc);
+               struct svc_fh *current_fh, struct nfsd4_open_confirm *oc,
+               struct nfs4_stateowner **);
 extern  int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
-               struct nfsd4_close *close);
+               struct nfsd4_close *close,
+               struct nfs4_stateowner **replay_owner);
 extern int nfsd4_open_downgrade(struct svc_rqst *rqstp, 
-               struct svc_fh *current_fh, struct nfsd4_open_downgrade *od);
+               struct svc_fh *current_fh, struct nfsd4_open_downgrade *od,
+               struct nfs4_stateowner **replay_owner);
 extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
-               struct nfsd4_lock *lock);
+               struct nfsd4_lock *lock,
+               struct nfs4_stateowner **replay_owner);
 extern int nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
                struct nfsd4_lockt *lockt);
 extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
-               struct nfsd4_locku *locku);
+               struct nfsd4_locku *locku,
+               struct nfs4_stateowner **replay_owner);
 extern int
 nfsd4_release_lockowner(struct svc_rqst *rqstp,
                struct nfsd4_release_lockowner *rlockowner);
index 31da85f4ab6e1e4451bc0e71da064024fca2f99b..f6c1a142286ada86dedd2acf509dfc429b594186 100644 (file)
 #define PCI_DEVICE_ID_HP_DIVA_EVEREST  0x1282
 #define PCI_DEVICE_ID_HP_DIVA_AUX      0x1290
 #define PCI_DEVICE_ID_HP_DIVA_RMP3     0x1301
+#define PCI_DEVICE_ID_HP_CISS          0x3210
 #define PCI_DEVICE_ID_HP_CISSA         0x3220
 #define PCI_DEVICE_ID_HP_CISSB         0x3222
-#define PCI_DEVICE_ID_HP_ZX2_IOC       0x4031
 #define PCI_DEVICE_ID_HP_CISSC         0x3230
+#define PCI_DEVICE_ID_HP_CISSD         0x3238
+#define PCI_DEVICE_ID_HP_ZX2_IOC       0x4031
 
 #define PCI_VENDOR_ID_PCTECH           0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000    0x1000
index 4b32bce9a2893527195c46321adcf860fe5feed3..2c177e4c8f226d50803162dcb421beb629d4cbd3 100644 (file)
@@ -166,6 +166,9 @@ struct packet_iosched
 /*
  * 32 buffers of 2048 bytes
  */
+#if (PAGE_SIZE % CD_FRAMESIZE) != 0
+#error "PAGE_SIZE must be a multiple of CD_FRAMESIZE"
+#endif
 #define PACKET_MAX_SIZE                32
 #define PAGES_PER_PACKET       (PACKET_MAX_SIZE * CD_FRAMESIZE / PAGE_SIZE)
 #define PACKET_MAX_SECTORS     (PACKET_MAX_SIZE * CD_FRAMESIZE >> 9)
index ed3bb19d13372c56aeac9ddac804162844378812..49e617fa0f662a10a04980ed0f2b3997a1adc0d0 100644 (file)
@@ -121,6 +121,17 @@ extern unsigned long nr_iowait(void);
 #define set_task_state(tsk, state_value)               \
        set_mb((tsk)->state, (state_value))
 
+/*
+ * set_current_state() includes a barrier so that the write of current->state
+ * is correctly serialised wrt the caller's subsequent test of whether to
+ * actually sleep:
+ *
+ *     set_current_state(TASK_UNINTERRUPTIBLE);
+ *     if (do_i_need_to_sleep())
+ *             schedule();
+ *
+ * If the caller does not need such serialisation then use __set_current_state()
+ */
 #define __set_current_state(state_value)                       \
        do { current->state = (state_value); } while (0)
 #define set_current_state(state_value)         \
@@ -785,7 +796,6 @@ struct task_struct {
        short il_next;
 #endif
 #ifdef CONFIG_CPUSETS
-       short cpuset_sem_nest_depth;
        struct cpuset *cpuset;
        nodemask_t mems_allowed;
        int cpuset_mems_generation;
index 532a6c5c24e9cc105b30accf34f4a6e792967988..3a29a9f9b451d7f3b0e6135ff7d4fcc0fa886027 100644 (file)
@@ -544,7 +544,8 @@ enum {
        NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE=8,
        NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT=9,
        NET_NETROM_ROUTING_CONTROL=10,
-       NET_NETROM_LINK_FAILS_COUNT=11
+       NET_NETROM_LINK_FAILS_COUNT=11,
+       NET_NETROM_RESET=12
 };
 
 /* /proc/sys/net/ax25 */
index fb57c221746827a06a1f7153ad794728771b1c89..9facf733800ccb99a7fb59e2be87b9a7846ada57 100644 (file)
@@ -32,7 +32,6 @@
 #define _LINUX_USBDEVICE_FS_H
 
 #include <linux/types.h>
-#include <linux/compat.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -125,6 +124,7 @@ struct usbdevfs_hub_portinfo {
 };
 
 #ifdef CONFIG_COMPAT
+#include <linux/compat.h>
 struct usbdevfs_urb32 {
        unsigned char type;
        unsigned char endpoint;
index f623a33b9abe856ea37a01be04ac515727498ae2..89a055761bed8e877ce1f7af782ae3f0e33371cf 100644 (file)
@@ -60,12 +60,17 @@ enum v4l2_field {
         (field) == V4L2_FIELD_SEQ_BT)
 
 enum v4l2_buf_type {
-       V4L2_BUF_TYPE_VIDEO_CAPTURE  = 1,
-       V4L2_BUF_TYPE_VIDEO_OUTPUT   = 2,
-       V4L2_BUF_TYPE_VIDEO_OVERLAY  = 3,
-       V4L2_BUF_TYPE_VBI_CAPTURE    = 4,
-       V4L2_BUF_TYPE_VBI_OUTPUT     = 5,
-       V4L2_BUF_TYPE_PRIVATE        = 0x80,
+       V4L2_BUF_TYPE_VIDEO_CAPTURE      = 1,
+       V4L2_BUF_TYPE_VIDEO_OUTPUT       = 2,
+       V4L2_BUF_TYPE_VIDEO_OVERLAY      = 3,
+       V4L2_BUF_TYPE_VBI_CAPTURE        = 4,
+       V4L2_BUF_TYPE_VBI_OUTPUT         = 5,
+#if 1
+       /* Experimental Sliced VBI */
+       V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
+       V4L2_BUF_TYPE_SLICED_VBI_OUTPUT  = 7,
+#endif
+       V4L2_BUF_TYPE_PRIVATE            = 0x80,
 };
 
 enum v4l2_ctrl_type {
@@ -149,20 +154,24 @@ struct v4l2_capability
 };
 
 /* Values for 'capabilities' field */
-#define V4L2_CAP_VIDEO_CAPTURE 0x00000001  /* Is a video capture device */
-#define V4L2_CAP_VIDEO_OUTPUT  0x00000002  /* Is a video output device */
-#define V4L2_CAP_VIDEO_OVERLAY 0x00000004  /* Can do video overlay */
-#define V4L2_CAP_VBI_CAPTURE   0x00000010  /* Is a VBI capture device */
-#define V4L2_CAP_VBI_OUTPUT    0x00000020  /* Is a VBI output device */
-#define V4L2_CAP_RDS_CAPTURE   0x00000100  /* RDS data capture */
+#define V4L2_CAP_VIDEO_CAPTURE         0x00000001  /* Is a video capture device */
+#define V4L2_CAP_VIDEO_OUTPUT          0x00000002  /* Is a video output device */
+#define V4L2_CAP_VIDEO_OVERLAY         0x00000004  /* Can do video overlay */
+#define V4L2_CAP_VBI_CAPTURE           0x00000010  /* Is a raw VBI capture device */
+#define V4L2_CAP_VBI_OUTPUT            0x00000020  /* Is a raw VBI output device */
+#if 1
+#define V4L2_CAP_SLICED_VBI_CAPTURE    0x00000040  /* Is a sliced VBI capture device */
+#define V4L2_CAP_SLICED_VBI_OUTPUT     0x00000080  /* Is a sliced VBI output device */
+#endif
+#define V4L2_CAP_RDS_CAPTURE           0x00000100  /* RDS data capture */
 
-#define V4L2_CAP_TUNER         0x00010000  /* has a tuner */
-#define V4L2_CAP_AUDIO         0x00020000  /* has audio support */
-#define V4L2_CAP_RADIO         0x00040000  /* is a radio device */
+#define V4L2_CAP_TUNER                 0x00010000  /* has a tuner */
+#define V4L2_CAP_AUDIO                 0x00020000  /* has audio support */
+#define V4L2_CAP_RADIO                 0x00040000  /* is a radio device */
 
-#define V4L2_CAP_READWRITE      0x01000000  /* read/write systemcalls */
-#define V4L2_CAP_ASYNCIO        0x02000000  /* async I/O */
-#define V4L2_CAP_STREAMING      0x04000000  /* streaming I/O ioctls */
+#define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
+#define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
+#define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
 
 /*
  *     V I D E O   I M A G E   F O R M A T
@@ -809,6 +818,8 @@ struct v4l2_audioout
  *     Data services API by Michael Schimek
  */
 
+/* Raw VBI */
+
 struct v4l2_vbi_format
 {
        __u32   sampling_rate;          /* in 1 Hz */
@@ -825,6 +836,54 @@ struct v4l2_vbi_format
 #define V4L2_VBI_UNSYNC                (1<< 0)
 #define V4L2_VBI_INTERLACED    (1<< 1)
 
+#if 1
+/* Sliced VBI
+ *
+ *    This implements is a proposal V4L2 API to allow SLICED VBI
+ * required for some hardware encoders. It should change without
+ * notice in the definitive implementation.
+ */
+
+struct v4l2_sliced_vbi_format
+{
+        __u16   service_set;
+        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+                                 (equals frame lines 313-336 for 625 line video
+                                  standards, 263-286 for 525 line standards) */
+        __u16   service_lines[2][24];
+        __u32   io_size;
+        __u32   reserved[2];            /* must be zero */
+};
+
+#define V4L2_SLICED_TELETEXT_B          (0x0001)
+#define V4L2_SLICED_VPS                 (0x0400)
+#define V4L2_SLICED_CAPTION_525         (0x1000)
+#define V4L2_SLICED_WSS_625             (0x4000)
+
+#define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
+#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
+
+struct v4l2_sliced_vbi_cap
+{
+        __u16   service_set;
+        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+                                 (equals frame lines 313-336 for 625 line video
+                                  standards, 263-286 for 525 line standards) */
+        __u16   service_lines[2][24];
+        __u32   reserved[4];    /* must be 0 */
+};
+
+struct v4l2_sliced_vbi_data
+{
+        __u32   id;
+        __u32   field;          /* 0: first field, 1: second field */
+        __u32   line;           /* 1-23 */
+        __u32   reserved;       /* must be 0 */
+        __u8    data[48];
+};
+#endif
 
 /*
  *     A G G R E G A T E   S T R U C T U R E S
@@ -837,10 +896,13 @@ struct v4l2_format
        enum v4l2_buf_type type;
        union
        {
-               struct v4l2_pix_format  pix;  // V4L2_BUF_TYPE_VIDEO_CAPTURE
-               struct v4l2_window      win;  // V4L2_BUF_TYPE_VIDEO_OVERLAY
-               struct v4l2_vbi_format  vbi;  // V4L2_BUF_TYPE_VBI_CAPTURE
-               __u8    raw_data[200];        // user-defined
+               struct v4l2_pix_format          pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE
+               struct v4l2_window              win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY
+               struct v4l2_vbi_format          vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE
+#if 1
+               struct v4l2_sliced_vbi_format   sliced;  // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
+#endif
+               __u8    raw_data[200];                   // user-defined
        } fmt;
 };
 
@@ -916,6 +978,9 @@ struct v4l2_streamparm
 #define VIDIOC_ENUMAUDOUT      _IOWR ('V', 66, struct v4l2_audioout)
 #define VIDIOC_G_PRIORITY       _IOR  ('V', 67, enum v4l2_priority)
 #define VIDIOC_S_PRIORITY       _IOW  ('V', 68, enum v4l2_priority)
+#if 1
+#define VIDIOC_G_SLICED_VBI_CAP _IOR  ('V', 69, struct v4l2_sliced_vbi_cap)
+#endif
 
 /* for compatibility, will go away some day */
 #define VIDIOC_OVERLAY_OLD             _IOWR ('V', 14, int)
index 227d3378decd8cf86d8467652f6e9ebc9e3daec5..9dbcd9e51c00a33d1502824929468ce6a9e594c2 100644 (file)
 
 /* AX.25 Protocol IDs */
 #define AX25_P_ROSE                    0x01
-#define AX25_P_IP                      0xCC
-#define AX25_P_ARP                     0xCD
-#define AX25_P_TEXT                    0xF0
-#define AX25_P_NETROM                  0xCF
-#define        AX25_P_SEGMENT                  0x08
+#define AX25_P_VJCOMP                  0x06    /* Compressed TCP/IP packet   */
+                                               /* Van Jacobsen (RFC 1144)    */
+#define AX25_P_VJUNCOMP                        0x07    /* Uncompressed TCP/IP packet */
+                                               /* Van Jacobsen (RFC 1144)    */
+#define        AX25_P_SEGMENT                  0x08    /* Segmentation fragment      */
+#define AX25_P_TEXNET                  0xc3    /* TEXTNET datagram protocol  */
+#define AX25_P_LQ                      0xc4    /* Link Quality Protocol      */
+#define AX25_P_ATALK                   0xca    /* Appletalk                  */
+#define AX25_P_ATALK_ARP               0xcb    /* Appletalk ARP              */
+#define AX25_P_IP                      0xcc    /* ARPA Internet Protocol     */
+#define AX25_P_ARP                     0xcd    /* ARPA Adress Resolution     */
+#define AX25_P_FLEXNET                 0xce    /* FlexNet                    */
+#define AX25_P_NETROM                  0xcf    /* NET/ROM                    */
+#define AX25_P_TEXT                    0xF0    /* No layer 3 protocol impl.  */
 
 /* AX.25 Segment control values */
 #define        AX25_SEG_REM                    0x7F
 /* Define Link State constants. */
 
 enum { 
-       AX25_STATE_0,
-       AX25_STATE_1,
-       AX25_STATE_2,
-       AX25_STATE_3,
-       AX25_STATE_4
+       AX25_STATE_0,                   /* Listening */
+       AX25_STATE_1,                   /* SABM sent */
+       AX25_STATE_2,                   /* DISC sent */
+       AX25_STATE_3,                   /* Established */
+       AX25_STATE_4                    /* Recovery */
 };
 
 #define AX25_MODULUS           8       /*  Standard AX.25 modulus */
@@ -319,7 +328,7 @@ extern int  ax25_rx_iframe(ax25_cb *, struct sk_buff *);
 extern int  ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 
 /* ax25_ip.c */
-extern int  ax25_encapsulate(struct sk_buff *, struct net_device *, unsigned short, void *, void *, unsigned int);
+extern int  ax25_hard_header(struct sk_buff *, struct net_device *, unsigned short, void *, void *, unsigned int);
 extern int  ax25_rebuild_header(struct sk_buff *);
 
 /* ax25_out.c */
index 45f2c7616d8b8566e690aedbdecb66db9ccea9d3..a6bf6e0f606aed23ac8a8b4a2583bc5d7d6a8d19 100644 (file)
@@ -6,6 +6,7 @@
 
 #ifndef _NETROM_H
 #define _NETROM_H 
+
 #include <linux/netrom.h>
 #include <linux/list.h>
 #include <net/sock.h>
@@ -22,6 +23,7 @@
 #define        NR_DISCACK                      0x04
 #define        NR_INFO                         0x05
 #define        NR_INFOACK                      0x06
+#define        NR_RESET                        0x07
 
 #define        NR_CHOKE_FLAG                   0x80
 #define        NR_NAK_FLAG                     0x40
@@ -51,11 +53,16 @@ enum {
 #define        NR_DEFAULT_TTL                  16              /* Default Time To Live - 16 */
 #define        NR_DEFAULT_ROUTING              1               /* Is routing enabled ? */
 #define        NR_DEFAULT_FAILS                2               /* Link fails until route fails */
+#define        NR_DEFAULT_RESET                0               /* Sent / accept reset cmds? */
 
 #define NR_MODULUS                     256
 #define NR_MAX_WINDOW_SIZE             127                     /* Maximum Window Allowable - 127 */
 #define        NR_MAX_PACKET_SIZE              236                     /* Maximum Packet Length - 236 */
 
+struct nr_private {
+       struct net_device_stats stats;
+};
+
 struct nr_sock {
        struct sock             sock;
        ax25_address            user_addr, source_addr, dest_addr;
@@ -176,6 +183,8 @@ extern int  sysctl_netrom_transport_requested_window_size;
 extern int  sysctl_netrom_transport_no_activity_timeout;
 extern int  sysctl_netrom_routing_control;
 extern int  sysctl_netrom_link_fails_count;
+extern int  sysctl_netrom_reset_circuit;
+
 extern int  nr_rx_frame(struct sk_buff *, struct net_device *);
 extern void nr_destroy_socket(struct sock *);
 
@@ -218,7 +227,28 @@ extern void nr_requeue_frames(struct sock *);
 extern int  nr_validate_nr(struct sock *, unsigned short);
 extern int  nr_in_rx_window(struct sock *, unsigned short);
 extern void nr_write_internal(struct sock *, int);
-extern void nr_transmit_refusal(struct sk_buff *, int);
+
+extern void __nr_transmit_reply(struct sk_buff *skb, int mine,
+       unsigned char cmdflags);
+
+/*
+ * This routine is called when a Connect Acknowledge with the Choke Flag
+ * set is needed to refuse a connection.
+ */
+#define nr_transmit_refusal(skb, mine)                                 \
+do {                                                                   \
+       __nr_transmit_reply((skb), (mine), NR_CONNACK | NR_CHOKE_FLAG); \
+} while (0)
+
+/*
+ * This routine is called when we don't have a circuit matching an incoming
+ * NET/ROM packet.  This is an G8PZT Xrouter extension.
+ */
+#define nr_transmit_reset(skb, mine)                                   \
+do {                                                                   \
+       __nr_transmit_reply((skb), (mine), NR_RESET);                   \
+} while (0)
+
 extern void nr_disconnect(struct sock *, int);
 
 /* nr_timer.c */
index da63722c0123b8e77feadd5cd6ee118c757c153e..c0e4c67d836fa66e4f72f520e33e50f7526e597d 100644 (file)
@@ -178,8 +178,8 @@ static inline struct scsi_target *scsi_target(struct scsi_device *sdev)
 
 extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
                uint, uint, uint, void *hostdata);
-#define scsi_add_device(host, channel, target, lun) \
-       __scsi_add_device(host, channel, target, lun, NULL)
+extern int scsi_add_device(struct Scsi_Host *host, uint channel,
+                          uint target, uint lun);
 extern void scsi_remove_device(struct scsi_device *);
 extern int scsi_device_cancel(struct scsi_device *, int);
 
index 70ad16315a16f2718d74c6030e799f8c948e2e6e..115db056dc6bdc8ec31eaacda793d4849521a300 100644 (file)
@@ -439,4 +439,12 @@ int fc_remote_port_block(struct fc_rport *rport);
 void fc_remote_port_unblock(struct fc_rport *rport);
 int scsi_is_fc_rport(const struct device *);
 
+static inline u64 wwn_to_u64(u8 *wwn)
+{
+       return (u64)wwn[0] << 56 | (u64)wwn[1] << 48 |
+           (u64)wwn[2] << 40 | (u64)wwn[3] << 32 |
+           (u64)wwn[4] << 24 | (u64)wwn[5] << 16 |
+           (u64)wwn[6] <<  8 | (u64)wwn[7];
+}
+
 #endif /* SCSI_TRANSPORT_FC_H */
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
new file mode 100644 (file)
index 0000000..bc4aeb6
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef SCSI_TRANSPORT_SAS_H
+#define SCSI_TRANSPORT_SAS_H
+
+#include <linux/transport_class.h>
+#include <linux/types.h>
+
+struct scsi_transport_template;
+struct sas_rphy;
+
+
+enum sas_device_type {
+       SAS_PHY_UNUSED,
+       SAS_END_DEVICE,
+       SAS_EDGE_EXPANDER_DEVICE,
+       SAS_FANOUT_EXPANDER_DEVICE,
+};
+
+enum sas_protocol {
+       SAS_PROTOCOL_SATA               = 0x01,
+       SAS_PROTOCOL_SMP                = 0x02,
+       SAS_PROTOCOL_STP                = 0x04,
+       SAS_PROTOCOL_SSP                = 0x08,
+};
+
+enum sas_linkrate {
+       SAS_LINK_RATE_UNKNOWN,
+       SAS_PHY_DISABLED,
+       SAS_LINK_RATE_FAILED,
+       SAS_SATA_SPINUP_HOLD,
+       SAS_SATA_PORT_SELECTOR,
+       SAS_LINK_RATE_1_5_GBPS,
+       SAS_LINK_RATE_3_0_GBPS,
+       SAS_LINK_VIRTUAL,
+};
+
+struct sas_identify {
+       enum sas_device_type    device_type;
+       enum sas_protocol       initiator_port_protocols;
+       enum sas_protocol       target_port_protocols;
+       u64                     sas_address;
+       u8                      phy_identifier;
+};
+
+/* The functions by which the transport class and the driver communicate */
+struct sas_function_template {
+};
+
+struct sas_phy {
+       struct device           dev;
+       int                     number;
+       struct sas_identify     identify;
+       enum sas_linkrate       negotiated_linkrate;
+       enum sas_linkrate       minimum_linkrate_hw;
+       enum sas_linkrate       minimum_linkrate;
+       enum sas_linkrate       maximum_linkrate_hw;
+       enum sas_linkrate       maximum_linkrate;
+       u8                      port_identifier;
+       struct sas_rphy         *rphy;
+};
+
+#define dev_to_phy(d) \
+       container_of((d), struct sas_phy, dev)
+#define transport_class_to_phy(cdev) \
+       dev_to_phy((cdev)->dev)
+#define phy_to_shost(phy) \
+       dev_to_shost((phy)->dev.parent)
+
+struct sas_rphy {
+       struct device           dev;
+       struct sas_identify     identify;
+       struct list_head        list;
+       u32                     scsi_target_id;
+};
+
+#define dev_to_rphy(d) \
+       container_of((d), struct sas_rphy, dev)
+#define transport_class_to_rphy(cdev) \
+       dev_to_rphy((cdev)->dev)
+#define rphy_to_shost(rphy) \
+       dev_to_shost((rphy)->dev.parent)
+
+extern void sas_remove_host(struct Scsi_Host *);
+
+extern struct sas_phy *sas_phy_alloc(struct device *, int);
+extern void sas_phy_free(struct sas_phy *);
+extern int sas_phy_add(struct sas_phy *);
+extern void sas_phy_delete(struct sas_phy *);
+extern int scsi_is_sas_phy(const struct device *);
+
+extern struct sas_rphy *sas_rphy_alloc(struct sas_phy *);
+void sas_rphy_free(struct sas_rphy *);
+extern int sas_rphy_add(struct sas_rphy *);
+extern void sas_rphy_delete(struct sas_rphy *);
+extern int scsi_is_sas_rphy(const struct device *);
+
+extern struct scsi_transport_template *
+sas_attach_transport(struct sas_function_template *);
+extern void sas_release_transport(struct scsi_transport_template *);
+
+#endif /* SCSI_TRANSPORT_SAS_H */
index 8d3cef5d87a20264af07948e6c1df10d2f04f8bc..6f4ea808cf74b4ae9e2e47f19da0231e5b07a51a 100644 (file)
 /* do we want accelerated console  */
 #define PM3FB_USE_ACCEL 1
 
-/* useful ? */
-#define CHAR_IS_NUM(a)  ((((a) >= '0') && ((a) <= '9')) ? 1 : 0)
-
 /* for driver debugging ONLY */
 /* 0 = assert only, 1 = error, 2 = info, 3+ = verbose */
 /* define PM3FB_MASTER_DEBUG 1 */
index e6da2d7ded8cfa7a0a5c1d16ae1e732b98af996a..677d403267967ed361488666198594db8cde9ba9 100644 (file)
@@ -19,6 +19,7 @@ struct w100fb_par;
 
 unsigned long w100fb_gpio_read(int port);
 void w100fb_gpio_write(int port, unsigned long value);
+unsigned long w100fb_get_hsynclen(struct device *dev);
 
 /* LCD Specific Routines and Config */
 struct w100_tg_info {
index 02c5ce64990d4abdd162eeee1e9a8410156d41bd..0c5d9a3f951baea7efa88f37683641e7efc3a978 100644 (file)
@@ -466,6 +466,14 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
 extern char __initramfs_start[], __initramfs_end[];
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/initrd.h>
+
+static void __init free_initrd(void)
+{
+       free_initrd_mem(initrd_start, initrd_end);
+       initrd_start = 0;
+       initrd_end = 0;
+}
+
 #endif
 
 void __init populate_rootfs(void)
@@ -484,7 +492,7 @@ void __init populate_rootfs(void)
                        printk(" it is\n");
                        unpack_to_rootfs((char *)initrd_start,
                                initrd_end - initrd_start, 0);
-                       free_initrd_mem(initrd_start, initrd_end);
+                       free_initrd();
                        return;
                }
                printk("it isn't (%s); looks like an initrd\n", err);
@@ -493,7 +501,7 @@ void __init populate_rootfs(void)
                        sys_write(fd, (char *)initrd_start,
                                        initrd_end - initrd_start);
                        sys_close(fd);
-                       free_initrd_mem(initrd_start, initrd_end);
+                       free_initrd();
                }
        }
 #endif
index 407b5f0a8c8eeed2aea648b08748771dd284b3d7..79866bc6b3a154d06c4b42daa3daec60aa96ebd9 100644 (file)
@@ -180,6 +180,8 @@ static struct super_block *cpuset_sb = NULL;
  */
 
 static DECLARE_MUTEX(cpuset_sem);
+static struct task_struct *cpuset_sem_owner;
+static int cpuset_sem_depth;
 
 /*
  * The global cpuset semaphore cpuset_sem can be needed by the
@@ -200,16 +202,19 @@ static DECLARE_MUTEX(cpuset_sem);
 
 static inline void cpuset_down(struct semaphore *psem)
 {
-       if (current->cpuset_sem_nest_depth == 0)
+       if (cpuset_sem_owner != current) {
                down(psem);
-       current->cpuset_sem_nest_depth++;
+               cpuset_sem_owner = current;
+       }
+       cpuset_sem_depth++;
 }
 
 static inline void cpuset_up(struct semaphore *psem)
 {
-       current->cpuset_sem_nest_depth--;
-       if (current->cpuset_sem_nest_depth == 0)
+       if (--cpuset_sem_depth == 0) {
+               cpuset_sem_owner = NULL;
                up(psem);
+       }
 }
 
 /*
index 4b39d3793c720673452b6d8be18ade674360131a..ff5c500ab625202ef8401998bc0a71cac53424aa 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/moduleloader.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/elf.h>
@@ -498,7 +499,7 @@ static inline int try_force(unsigned int flags)
 {
        int ret = (flags & O_TRUNC);
        if (ret)
-               tainted |= TAINT_FORCED_MODULE;
+               add_taint(TAINT_FORCED_MODULE);
        return ret;
 }
 #else
@@ -897,7 +898,7 @@ static int check_version(Elf_Shdr *sechdrs,
        if (!(tainted & TAINT_FORCED_MODULE)) {
                printk("%s: no version for \"%s\" found: kernel tainted.\n",
                       mod->name, symname);
-               tainted |= TAINT_FORCED_MODULE;
+               add_taint(TAINT_FORCED_MODULE);
        }
        return 1;
 }
@@ -1352,7 +1353,7 @@ static void set_license(struct module *mod, const char *license)
        if (!mod->license_gplok && !(tainted & TAINT_PROPRIETARY_MODULE)) {
                printk(KERN_WARNING "%s: module license '%s' taints kernel.\n",
                       mod->name, license);
-               tainted |= TAINT_PROPRIETARY_MODULE;
+               add_taint(TAINT_PROPRIETARY_MODULE);
        }
 }
 
@@ -1610,7 +1611,7 @@ static struct module *load_module(void __user *umod,
        modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
        /* This is allowed: modprobe --force will invalidate it. */
        if (!modmagic) {
-               tainted |= TAINT_FORCED_MODULE;
+               add_taint(TAINT_FORCED_MODULE);
                printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",
                       mod->name);
        } else if (!same_magic(modmagic, vermagic)) {
@@ -1739,7 +1740,7 @@ static struct module *load_module(void __user *umod,
            (mod->num_gpl_syms && !gplcrcindex)) {
                printk(KERN_WARNING "%s: No versions for exported symbols."
                       " Tainting kernel.\n", mod->name);
-               tainted |= TAINT_FORCED_MODULE;
+               add_taint(TAINT_FORCED_MODULE);
        }
 #endif
 
index e9ff04a9b56df3e424dff87eec851196f72c0d4c..81b3a96ed2d09a79f7937503a88c3ced4c959953 100644 (file)
@@ -3576,32 +3576,6 @@ task_t *idle_task(int cpu)
        return cpu_rq(cpu)->idle;
 }
 
-/**
- * curr_task - return the current task for a given cpu.
- * @cpu: the processor in question.
- */
-task_t *curr_task(int cpu)
-{
-       return cpu_curr(cpu);
-}
-
-/**
- * set_curr_task - set the current task for a given cpu.
- * @cpu: the processor in question.
- * @p: the task pointer to set.
- *
- * Description: This function must only be used when non-maskable interrupts
- * are serviced on a separate stack.  It allows the architecture to switch the
- * notion of the current task on a cpu in a non-blocking manner.  This function
- * must be called with interrupts disabled, the caller must save the original
- * value of the current task (see curr_task() above) and restore that value
- * before reenabling interrupts.
- */
-void set_curr_task(int cpu, task_t *p)
-{
-       cpu_curr(cpu) = p;
-}
-
 /**
  * find_process_by_pid - find a process with a matching PID value.
  * @pid: the pid in question.
@@ -5628,3 +5602,47 @@ void normalize_rt_tasks(void)
 }
 
 #endif /* CONFIG_MAGIC_SYSRQ */
+
+#ifdef CONFIG_IA64
+/*
+ * These functions are only useful for the IA64 MCA handling.
+ *
+ * They can only be called when the whole system has been
+ * stopped - every CPU needs to be quiescent, and no scheduling
+ * activity can take place. Using them for anything else would
+ * be a serious bug, and as a result, they aren't even visible
+ * under any other configuration.
+ */
+
+/**
+ * curr_task - return the current task for a given cpu.
+ * @cpu: the processor in question.
+ *
+ * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
+ */
+task_t *curr_task(int cpu)
+{
+       return cpu_curr(cpu);
+}
+
+/**
+ * set_curr_task - set the current task for a given cpu.
+ * @cpu: the processor in question.
+ * @p: the task pointer to set.
+ *
+ * Description: This function must only be used when non-maskable interrupts
+ * are serviced on a separate stack.  It allows the architecture to switch the
+ * notion of the current task on a cpu in a non-blocking manner.  This function
+ * must be called with all CPU's synchronized, and interrupts disabled, the
+ * and caller must save the original value of the current task (see
+ * curr_task() above) and restore that value before reenabling interrupts and
+ * re-starting the system.
+ *
+ * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
+ */
+void set_curr_task(int cpu, task_t *p)
+{
+       cpu_curr(cpu) = p;
+}
+
+#endif
index b4ab6af1dea8513147c19694a8eff8a4353c69e0..f766b2fc48be8cd54cc254c91660ec414603a2c5 100644 (file)
@@ -84,7 +84,7 @@ asmlinkage void __do_softirq(void)
        cpu = smp_processor_id();
 restart:
        /* Reset the pending bitmask before enabling irqs */
-       local_softirq_pending() = 0;
+       set_softirq_pending(0);
 
        local_irq_enable();
 
index f4152fcd9f8effecb04229c6e3a239576e7e09af..3ba10fa35b607fd8a3c6d0db86f104c767df6604 100644 (file)
@@ -1151,19 +1151,22 @@ fastcall signed long __sched schedule_timeout(signed long timeout)
  out:
        return timeout < 0 ? 0 : timeout;
 }
-
 EXPORT_SYMBOL(schedule_timeout);
 
+/*
+ * We can use __set_current_state() here because schedule_timeout() calls
+ * schedule() unconditionally.
+ */
 signed long __sched schedule_timeout_interruptible(signed long timeout)
 {
-       set_current_state(TASK_INTERRUPTIBLE);
+       __set_current_state(TASK_INTERRUPTIBLE);
        return schedule_timeout(timeout);
 }
 EXPORT_SYMBOL(schedule_timeout_interruptible);
 
 signed long __sched schedule_timeout_uninterruptible(signed long timeout)
 {
-       set_current_state(TASK_UNINTERRUPTIBLE);
+       __set_current_state(TASK_UNINTERRUPTIBLE);
        return schedule_timeout(timeout);
 }
 EXPORT_SYMBOL(schedule_timeout_uninterruptible);
index 3754c9a8f5c8e1e3fccebf2d0f282fd5eda6bcb4..016e89a44ac8defe6c753bd73d6bc74aa4e48e0f 100644 (file)
@@ -170,11 +170,11 @@ config DEBUG_FS
 
 config FRAME_POINTER
        bool "Compile the kernel with frame pointers"
-       depends on DEBUG_KERNEL && ((X86 && !X86_64) || CRIS || M68K || M68KNOMMU || FRV || UML)
+       depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML)
        default y if DEBUG_INFO && UML
        help
          If you say Y here the resulting kernel image will be slightly larger
-         and slower, but it will give very useful debugging information.
-         If you don't debug the kernel, you can say N, but we may not be able
-         to solve problems without frame pointers.
+         and slower, but it might give very useful debugging information
+         on some architectures or you use external debuggers.
+         If you don't debug the kernel, you can say N.
 
index c1330cc197835ae66bffaa2baacc032ace0020b4..8ec4e4c2a179f5fc1a8d7ddb648dad0d9f69cdbb 100644 (file)
@@ -61,9 +61,17 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat,
 {
        bootmem_data_t *bdata = pgdat->bdata;
        unsigned long mapsize = ((end - start)+7)/8;
-
-       pgdat->pgdat_next = pgdat_list;
-       pgdat_list = pgdat;
+       static struct pglist_data *pgdat_last;
+
+       pgdat->pgdat_next = NULL;
+       /* Add new nodes last so that bootmem always starts
+          searching in the first nodes, not the last ones */
+       if (pgdat_last)
+               pgdat_last->pgdat_next = pgdat;
+       else {
+               pgdat_list = pgdat;     
+               pgdat_last = pgdat;
+       }
 
        mapsize = ALIGN(mapsize, sizeof(long));
        bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
index afa06e184d88a93311708bdfb1e15077859e29c4..9033f0859aa8c2f17bc66a55c7eb129092cc4a4d 100644 (file)
@@ -333,8 +333,13 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
                if (prev && prev->vm_end < vma->vm_start)
                        return ERR_PTR(-EFAULT);
                if ((flags & MPOL_MF_STRICT) && !is_vm_hugetlb_page(vma)) {
+                       unsigned long endvma = vma->vm_end;
+                       if (endvma > end)
+                               endvma = end;
+                       if (vma->vm_start > start)
+                               start = vma->vm_start;
                        err = check_pgd_range(vma->vm_mm,
-                                          vma->vm_start, vma->vm_end, nodes);
+                                          start, endvma, nodes);
                        if (err) {
                                first = ERR_PTR(err);
                                break;
index fd4e8df0f02df979bb2a2de5a891e35f82754a7d..064d70442895a05f9dbba0db0ecdcf72cf044e60 100644 (file)
@@ -57,6 +57,11 @@ DECLARE_RWSEM(nommu_vma_sem);
 struct vm_operations_struct generic_file_vm_ops = {
 };
 
+EXPORT_SYMBOL(vmalloc);
+EXPORT_SYMBOL(vfree);
+EXPORT_SYMBOL(vmalloc_to_page);
+EXPORT_SYMBOL(vmalloc_32);
+
 /*
  * Handle all mappings that got truncated by a "truncate()"
  * system call.
@@ -142,6 +147,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        return(i);
 }
 
+EXPORT_SYMBOL(get_user_pages);
+
 DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
@@ -852,7 +859,7 @@ unsigned long do_mmap_pgoff(struct file *file,
  error_getting_vma:
        up_write(&nommu_vma_sem);
        kfree(vml);
-       printk("Allocation of vml for %lu byte allocation from process %d failed\n",
+       printk("Allocation of vma for %lu byte allocation from process %d failed\n",
               len, current->pid);
        show_free_areas();
        return -ENOMEM;
@@ -909,7 +916,7 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
 
        for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next)
                if ((*parent)->vma->vm_start == addr &&
-                   (*parent)->vma->vm_end == end)
+                   ((len == 0) || ((*parent)->vma->vm_end == end)))
                        goto found;
 
        printk("munmap of non-mmaped memory by process %d (%s): %p\n",
@@ -1054,7 +1061,8 @@ struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr)
 int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
                unsigned long to, unsigned long size, pgprot_t prot)
 {
-       return -EPERM;
+       vma->vm_start = vma->vm_pgoff << PAGE_SHIFT;
+       return 0;
 }
 
 void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
@@ -1073,9 +1081,10 @@ void arch_unmap_area(struct mm_struct *mm, unsigned long addr)
 
 void update_mem_hiwater(struct task_struct *tsk)
 {
-       unsigned long rss = get_mm_counter(tsk->mm, rss);
+       unsigned long rss;
 
        if (likely(tsk->mm)) {
+               rss = get_mm_counter(tsk->mm, rss);
                if (tsk->mm->hiwater_rss < rss)
                        tsk->mm->hiwater_rss = rss;
                if (tsk->mm->hiwater_vm < tsk->mm->total_vm)
index c5823c395f7145f2a66ef3ffd11af836c294845f..ae2903339e71cf92a0e429f6a9423341a432dfc1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/compiler.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/suspend.h>
 #include <linux/pagevec.h>
@@ -117,7 +118,7 @@ static void bad_page(const char *function, struct page *page)
        set_page_count(page, 0);
        reset_page_mapcount(page);
        page->mapping = NULL;
-       tainted |= TAINT_BAD_PAGE;
+       add_taint(TAINT_BAD_PAGE);
 }
 
 #ifndef CONFIG_HUGETLB_PAGE
index a740778f688da277d35eb0d15a60168257dbe42e..0ea71e887bb6e3fdf51d9b18ad56fe993423249d 100644 (file)
@@ -1258,9 +1258,9 @@ void wakeup_kswapd(struct zone *zone, int order)
                pgdat->kswapd_max_order = order;
        if (!cpuset_zone_allowed(zone, __GFP_HARDWALL))
                return;
-       if (!waitqueue_active(&zone->zone_pgdat->kswapd_wait))
+       if (!waitqueue_active(&pgdat->kswapd_wait))
                return;
-       wake_up_interruptible(&zone->zone_pgdat->kswapd_wait);
+       wake_up_interruptible(&pgdat->kswapd_wait);
 }
 
 #ifdef CONFIG_PM
index ed705ddad56be0e9bb6b69580b681b1e5c91f6d0..8e37e71e34ff1929aef5a8b8efb2ef362dec6b54 100644 (file)
@@ -1695,16 +1695,12 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                /* These two are safe on a single CPU system as only user tasks fiddle here */
                if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
                        amount = skb->len;
-               res = put_user(amount, (int __user *)argp);
+               res = put_user(amount, (int __user *) argp);
                break;
        }
 
        case SIOCGSTAMP:
-               if (sk != NULL) {
-                       res = sock_get_timestamp(sk, argp);
-                       break;
-               }
-               res = -EINVAL;
+               res = sock_get_timestamp(sk, argp);
                break;
 
        case SIOCAX25ADDUID:    /* Add a uid to the uid/call map table */
@@ -1951,24 +1947,24 @@ static struct net_proto_family ax25_family_ops = {
 };
 
 static struct proto_ops ax25_proto_ops = {
-       .family =       PF_AX25,
-       .owner =        THIS_MODULE,
-       .release =      ax25_release,
-       .bind =         ax25_bind,
-       .connect =      ax25_connect,
-       .socketpair =   sock_no_socketpair,
-       .accept =       ax25_accept,
-       .getname =      ax25_getname,
-       .poll =         datagram_poll,
-       .ioctl =        ax25_ioctl,
-       .listen =       ax25_listen,
-       .shutdown =     ax25_shutdown,
-       .setsockopt =   ax25_setsockopt,
-       .getsockopt =   ax25_getsockopt,
-       .sendmsg =      ax25_sendmsg,
-       .recvmsg =      ax25_recvmsg,
-       .mmap =         sock_no_mmap,
-       .sendpage =     sock_no_sendpage,
+       .family         = PF_AX25,
+       .owner          = THIS_MODULE,
+       .release        = ax25_release,
+       .bind           = ax25_bind,
+       .connect        = ax25_connect,
+       .socketpair     = sock_no_socketpair,
+       .accept         = ax25_accept,
+       .getname        = ax25_getname,
+       .poll           = datagram_poll,
+       .ioctl          = ax25_ioctl,
+       .listen         = ax25_listen,
+       .shutdown       = ax25_shutdown,
+       .setsockopt     = ax25_setsockopt,
+       .getsockopt     = ax25_getsockopt,
+       .sendmsg        = ax25_sendmsg,
+       .recvmsg        = ax25_recvmsg,
+       .mmap           = sock_no_mmap,
+       .sendpage       = sock_no_sendpage,
 };
 
 /*
@@ -1984,7 +1980,7 @@ static struct notifier_block ax25_dev_notifier = {
        .notifier_call =ax25_device_event,
 };
 
-EXPORT_SYMBOL(ax25_encapsulate);
+EXPORT_SYMBOL(ax25_hard_header);
 EXPORT_SYMBOL(ax25_rebuild_header);
 EXPORT_SYMBOL(ax25_findbyuid);
 EXPORT_SYMBOL(ax25_find_cb);
index bba0173e2d6500a44954871389fc5e35396dffa2..d643dac3eccc6981b8d56b1a9c1ba20fa3b5bcf4 100644 (file)
@@ -47,7 +47,7 @@
 
 #ifdef CONFIG_INET
 
-int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
 {
        unsigned char *buff;
 
@@ -88,7 +88,7 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short
                *buff++ = AX25_P_ARP;
                break;
        default:
-               printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
+               printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type);
                *buff++ = 0;
                break;
        }
@@ -209,7 +209,7 @@ put:
 
 #else  /* INET */
 
-int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
 {
        return -AX25_HEADER_LEN;
 }
index b3ad49fa7d787ad7d8a01feb7a1a62f3faaa0bd9..ef430b1e8e42acc87af3d12fb4c95544c8996570 100644 (file)
@@ -1452,8 +1452,7 @@ static int proc_thread_write(struct file *file, const char __user *user_buffer,
                thread_lock();
                t->control |= T_REMDEV;
                thread_unlock();
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(HZ/8);  /* Propagate thread->control  */
+               schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
                ret = count;
                 sprintf(pg_result, "OK: rem_device_all");
                goto out;
@@ -1716,10 +1715,9 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
        printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now));
        while (now < spin_until_us) {
                /* TODO: optimise sleeping behavior */
-               if (spin_until_us - now > (1000000/HZ)+1) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(1);
-               } else if (spin_until_us - now > 100) {
+               if (spin_until_us - now > jiffies_to_usecs(1)+1)
+                       schedule_timeout_interruptible(1);
+               else if (spin_until_us - now > 100) {
                        do_softirq();
                        if (!pkt_dev->running)
                                return;
@@ -2449,8 +2447,7 @@ static void pktgen_run_all_threads(void)
        }
        thread_unlock();
 
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(HZ/8);  /* Propagate thread->control  */
+       schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
                        
        pktgen_wait_all_threads_run();
 }
index e05f4f955eeee8d0bd68eae5ccfab3bc674bec8b..38aa84986118564379043c462b19e832f8342933 100644 (file)
@@ -1095,6 +1095,10 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
 {
        const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
 
+       /* Listen socks doesn't have a private CCID block */
+       if (sk->sk_state == DCCP_LISTEN)
+               return;
+
        BUG_ON(hcrx == NULL);
 
        info->tcpi_ca_state     = hcrx->ccid3hcrx_state;
@@ -1106,6 +1110,10 @@ static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
 {
        const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
+       /* Listen socks doesn't have a private CCID block */
+       if (sk->sk_state == DCCP_LISTEN)
+               return;
+
        BUG_ON(hctx == NULL);
 
        info->tcpi_rto = hctx->ccid3hctx_t_rto;
index 953129d392d21cc97f551f93c519b491cb0190cc..e8674baaa8d99034ee0d56a7fdbdfc66d205abf6 100644 (file)
@@ -1103,10 +1103,8 @@ static int __init ic_dynamic(void)
 #endif
 
                jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout);
-               while (time_before(jiffies, jiff) && !ic_got_reply) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(1);
-               }
+               while (time_before(jiffies, jiff) && !ic_got_reply)
+                       schedule_timeout_uninterruptible(1);
 #ifdef IPCONFIG_DHCP
                /* DHCP isn't done until we get a DHCPACK. */
                if ((ic_got_reply & IC_BOOTP)
index 5d1e61168eb72d77c18f9fa278fa8a92516577f0..6f20b4206e08a56bc3b79902b9fededeac826cd9 100644 (file)
@@ -567,10 +567,8 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
        self->tty = NULL;
 
        if (self->blocked_open) {
-               if (self->close_delay) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(self->close_delay);
-               }
+               if (self->close_delay)
+                       schedule_timeout_interruptible(self->close_delay);
                wake_up_interruptible(&self->open_wait);
        }
 
@@ -863,8 +861,7 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
        spin_lock_irqsave(&self->spinlock, flags);
        while (self->tx_skb && self->tx_skb->len) {
                spin_unlock_irqrestore(&self->spinlock, flags);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(poll_time);
+               schedule_timeout_interruptible(poll_time);
                spin_lock_irqsave(&self->spinlock, flags);
                if (signal_pending(current))
                        break;
index f4578c759ffcc3350ebbd708c7f0a2ffef52c587..e5d82d711cae2ea36e1e36e652fdeebd0b5db591 100644 (file)
@@ -56,6 +56,7 @@ int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW;
 int sysctl_netrom_transport_no_activity_timeout   = NR_DEFAULT_IDLE;
 int sysctl_netrom_routing_control                 = NR_DEFAULT_ROUTING;
 int sysctl_netrom_link_fails_count                = NR_DEFAULT_FAILS;
+int sysctl_netrom_reset_circuit                   = NR_DEFAULT_RESET;
 
 static unsigned short circuit = 0x101;
 
@@ -908,17 +909,17 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
        if (frametype != NR_CONNREQ) {
                /*
                 * Here it would be nice to be able to send a reset but
-                * NET/ROM doesn't have one. The following hack would
-                * have been a way to extend the protocol but apparently
-                * it kills BPQ boxes... :-(
+                * NET/ROM doesn't have one.  We've tried to extend the protocol
+                * by sending NR_CONNACK | NR_CHOKE_FLAGS replies but that
+                * apparently kills BPQ boxes... :-(
+                * So now we try to follow the established behaviour of
+                * G8PZT's Xrouter which is sending packets with command type 7
+                * as an extension of the protocol.
                 */
-#if 0
-               /*
-                * Never reply to a CONNACK/CHOKE.
-                */
-               if (frametype != NR_CONNACK || flags != NR_CHOKE_FLAG)
-                       nr_transmit_refusal(skb, 1);
-#endif
+               if (sysctl_netrom_reset_circuit &&
+                   (frametype != NR_RESET || flags != 0))
+                       nr_transmit_reset(skb, 1);
+
                return 0;
        }
 
@@ -1187,9 +1188,7 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        }
 
        case SIOCGSTAMP:
-               ret = -EINVAL;
-               if (sk != NULL)
-                       ret = sock_get_timestamp(sk, argp);
+               ret = sock_get_timestamp(sk, argp);
                release_sock(sk);
                return ret;
 
@@ -1393,8 +1392,7 @@ static int __init nr_proto_init(void)
                struct net_device *dev;
 
                sprintf(name, "nr%d", i);
-               dev = alloc_netdev(sizeof(struct net_device_stats), name,
-                                         nr_setup);
+               dev = alloc_netdev(sizeof(struct nr_private), name, nr_setup);
                if (!dev) {
                        printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n");
                        goto fail;
index 263da4c26494cb2cf875d22b75ca773be770c8b8..4e66eef9a03479f0ead803fabdfb3d1f73e0b18f 100644 (file)
@@ -47,7 +47,7 @@ int nr_rx_ip(struct sk_buff *skb, struct net_device *dev)
        struct net_device_stats *stats = netdev_priv(dev);
 
        if (!netif_running(dev)) {
-               stats->rx_errors++;
+               stats->rx_dropped++;
                return 0;
        }
 
@@ -71,15 +71,10 @@ int nr_rx_ip(struct sk_buff *skb, struct net_device *dev)
 
 static int nr_rebuild_header(struct sk_buff *skb)
 {
-       struct net_device *dev = skb->dev;
-       struct net_device_stats *stats = netdev_priv(dev);
-       struct sk_buff *skbn;
        unsigned char *bp = skb->data;
-       int len;
 
-       if (arp_find(bp + 7, skb)) {
+       if (arp_find(bp + 7, skb))
                return 1;
-       }
 
        bp[6] &= ~AX25_CBIT;
        bp[6] &= ~AX25_EBIT;
@@ -90,27 +85,7 @@ static int nr_rebuild_header(struct sk_buff *skb)
        bp[6] |= AX25_EBIT;
        bp[6] |= AX25_SSSID_SPARE;
 
-       if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-               kfree_skb(skb);
-               return 1;
-       }
-
-       if (skb->sk != NULL)
-               skb_set_owner_w(skbn, skb->sk);
-
-       kfree_skb(skb);
-
-       len = skbn->len;
-
-       if (!nr_route_frame(skbn, NULL)) {
-               kfree_skb(skbn);
-               stats->tx_errors++;
-       }
-
-       stats->tx_packets++;
-       stats->tx_bytes += len;
-
-       return 1;
+       return 0;
 }
 
 #else
@@ -185,15 +160,27 @@ static int nr_close(struct net_device *dev)
 
 static int nr_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct net_device_stats *stats = netdev_priv(dev);
-       dev_kfree_skb(skb);
-       stats->tx_errors++;
+       struct nr_private *nr = netdev_priv(dev);
+       struct net_device_stats *stats = &nr->stats;
+       unsigned int len = skb->len;
+
+       if (!nr_route_frame(skb, NULL)) {
+               kfree_skb(skb);
+               stats->tx_errors++;
+               return 0;
+       }
+
+       stats->tx_packets++;
+       stats->tx_bytes += len;
+
        return 0;
 }
 
 static struct net_device_stats *nr_get_stats(struct net_device *dev)
 {
-       return netdev_priv(dev);
+       struct nr_private *nr = netdev_priv(dev);
+
+       return &nr->stats;
 }
 
 void nr_setup(struct net_device *dev)
@@ -208,12 +195,11 @@ void nr_setup(struct net_device *dev)
        dev->hard_header_len    = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
        dev->addr_len           = AX25_ADDR_LEN;
        dev->type               = ARPHRD_NETROM;
-       dev->tx_queue_len       = 40;
        dev->rebuild_header     = nr_rebuild_header;
        dev->set_mac_address    = nr_set_mac_address;
 
        /* New-style flags. */
-       dev->flags              = 0;
+       dev->flags              = IFF_NOARP;
 
        dev->get_stats          = nr_get_stats;
 }
index 64b81a7969077c706353e76309a67698380f2095..004e8599b8fe595f5b72c92b0b51bb203b99a44d 100644 (file)
@@ -98,6 +98,11 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
                nr_disconnect(sk, ECONNREFUSED);
                break;
 
+       case NR_RESET:
+               if (sysctl_netrom_reset_circuit);
+                       nr_disconnect(sk, ECONNRESET);
+               break;
+
        default:
                break;
        }
@@ -124,6 +129,11 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
                nr_disconnect(sk, 0);
                break;
 
+       case NR_RESET:
+               if (sysctl_netrom_reset_circuit);
+                       nr_disconnect(sk, ECONNRESET);
+               break;
+
        default:
                break;
        }
@@ -254,6 +264,11 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
                }
                break;
 
+       case NR_RESET:
+               if (sysctl_netrom_reset_circuit);
+                       nr_disconnect(sk, ECONNRESET);
+               break;
+
        default:
                break;
        }
index 587bed2674bfb4dcb09e40f13ae0d33b8342e053..bcb9946b4f5628f59276cfed1082c33135d95119 100644 (file)
@@ -210,10 +210,9 @@ void nr_write_internal(struct sock *sk, int frametype)
 }
 
 /*
- * This routine is called when a Connect Acknowledge with the Choke Flag
- * set is needed to refuse a connection.
+ * This routine is called to send an error reply.
  */
-void nr_transmit_refusal(struct sk_buff *skb, int mine)
+void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags)
 {
        struct sk_buff *skbn;
        unsigned char *dptr;
@@ -254,7 +253,7 @@ void nr_transmit_refusal(struct sk_buff *skb, int mine)
                *dptr++ = 0;
        }
 
-       *dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
+       *dptr++ = cmdflags;
        *dptr++ = 0;
 
        if (!nr_route_frame(skbn, NULL))
index c9ed50382ea7bb067766173207bafbade894f984..6bb8dda849dc71d1de1bd13ca8942eb6d607316f 100644 (file)
@@ -30,6 +30,7 @@ static int min_idle[]    = {0 * HZ};
 static int max_idle[]    = {65535 * HZ};
 static int min_route[]   = {0}, max_route[]   = {1};
 static int min_fails[]   = {1}, max_fails[]   = {10};
+static int min_reset[]   = {0}, max_reset[]   = {1};
 
 static struct ctl_table_header *nr_table_header;
 
@@ -155,6 +156,17 @@ static ctl_table nr_table[] = {
                .extra1         = &min_fails,
                .extra2         = &max_fails
        },
+        {
+               .ctl_name       = NET_NETROM_RESET,
+               .procname       = "reset",
+               .data           = &sysctl_netrom_reset_circuit,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_reset,
+               .extra2         = &max_reset
+       },
        { .ctl_name = 0 }
 };
 
index 3077878ed4f09fdc1a9a1bcf0b1303084f098641..5acb1680524ab5a3ae381b2a741fabd0219f8bc1 100644 (file)
@@ -1243,7 +1243,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
                if (amount < 0)
                        amount = 0;
-               return put_user(amount, (unsigned int __user *)argp);
+               return put_user(amount, (unsigned int __user *) argp);
        }
 
        case TIOCINQ: {
@@ -1252,13 +1252,11 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                /* These two are safe on a single CPU system as only user tasks fiddle here */
                if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
                        amount = skb->len;
-               return put_user(amount, (unsigned int __user *)argp);
+               return put_user(amount, (unsigned int __user *) argp);
        }
 
        case SIOCGSTAMP:
-               if (sk != NULL) 
-                       return sock_get_timestamp(sk, (struct timeval __user *)argp);
-               return -EINVAL;
+               return sock_get_timestamp(sk, (struct timeval __user *) argp);
 
        case SIOCGIFADDR:
        case SIOCSIFADDR:
index a8ed9a1d09f9efe2dee89d08893bad4d892bd836..d297af737d1023a41c88f028a8628d91e52bc3eb 100644 (file)
@@ -149,6 +149,6 @@ void rose_setup(struct net_device *dev)
        dev->set_mac_address    = rose_set_mac_address;
 
        /* New-style flags. */
-       dev->flags              = 0;
+       dev->flags              = IFF_NOARP;
        dev->get_stats = rose_get_stats;
 }
index 05fe2e735538e15999a5b018f19b5c8474573dc7..30ec3efc48a654fe16e7f7f096b42e4e44727b72 100644 (file)
@@ -512,15 +512,14 @@ svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
 static void
 svc_udp_data_ready(struct sock *sk, int count)
 {
-       struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data);
+       struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
 
-       if (!svsk)
-               goto out;
-       dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
-               svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));
-       set_bit(SK_DATA, &svsk->sk_flags);
-       svc_sock_enqueue(svsk);
- out:
+       if (svsk) {
+               dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
+                       svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));
+               set_bit(SK_DATA, &svsk->sk_flags);
+               svc_sock_enqueue(svsk);
+       }
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
                wake_up_interruptible(sk->sk_sleep);
 }
@@ -540,7 +539,7 @@ svc_write_space(struct sock *sk)
        }
 
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) {
-               printk(KERN_WARNING "RPC svc_write_space: some sleeping on %p\n",
+               dprintk("RPC svc_write_space: someone sleeping on %p\n",
                       svsk);
                wake_up_interruptible(sk->sk_sleep);
        }
@@ -692,31 +691,29 @@ svc_udp_init(struct svc_sock *svsk)
 static void
 svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
 {
-       struct svc_sock *svsk;
+       struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
 
        dprintk("svc: socket %p TCP (listen) state change %d\n",
-                       sk, sk->sk_state);
+               sk, sk->sk_state);
 
-       if  (sk->sk_state != TCP_LISTEN) {
-               /*
-                * This callback may called twice when a new connection
-                * is established as a child socket inherits everything
-                * from a parent LISTEN socket.
-                * 1) data_ready method of the parent socket will be called
-                *    when one of child sockets become ESTABLISHED.
-                * 2) data_ready method of the child socket may be called
-                *    when it receives data before the socket is accepted.
-                * In case of 2, we should ignore it silently.
-                */
-               goto out;
-       }
-       if (!(svsk = (struct svc_sock *) sk->sk_user_data)) {
-               printk("svc: socket %p: no user data\n", sk);
-               goto out;
+       /*
+        * This callback may called twice when a new connection
+        * is established as a child socket inherits everything
+        * from a parent LISTEN socket.
+        * 1) data_ready method of the parent socket will be called
+        *    when one of child sockets become ESTABLISHED.
+        * 2) data_ready method of the child socket may be called
+        *    when it receives data before the socket is accepted.
+        * In case of 2, we should ignore it silently.
+        */
+       if (sk->sk_state == TCP_LISTEN) {
+               if (svsk) {
+                       set_bit(SK_CONN, &svsk->sk_flags);
+                       svc_sock_enqueue(svsk);
+               } else
+                       printk("svc: socket %p: no user data\n", sk);
        }
-       set_bit(SK_CONN, &svsk->sk_flags);
-       svc_sock_enqueue(svsk);
- out:
+
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
                wake_up_interruptible_all(sk->sk_sleep);
 }
@@ -727,18 +724,17 @@ svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
 static void
 svc_tcp_state_change(struct sock *sk)
 {
-       struct svc_sock *svsk;
+       struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
 
        dprintk("svc: socket %p TCP (connected) state change %d (svsk %p)\n",
-                       sk, sk->sk_state, sk->sk_user_data);
+               sk, sk->sk_state, sk->sk_user_data);
 
-       if (!(svsk = (struct svc_sock *) sk->sk_user_data)) {
+       if (!svsk)
                printk("svc: socket %p: no user data\n", sk);
-               goto out;
+       else {
+               set_bit(SK_CLOSE, &svsk->sk_flags);
+               svc_sock_enqueue(svsk);
        }
-       set_bit(SK_CLOSE, &svsk->sk_flags);
-       svc_sock_enqueue(svsk);
- out:
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
                wake_up_interruptible_all(sk->sk_sleep);
 }
@@ -746,15 +742,14 @@ svc_tcp_state_change(struct sock *sk)
 static void
 svc_tcp_data_ready(struct sock *sk, int count)
 {
-       struct svc_sock *       svsk;
+       struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
 
        dprintk("svc: socket %p TCP data ready (svsk %p)\n",
-                       sk, sk->sk_user_data);
-       if (!(svsk = (struct svc_sock *)(sk->sk_user_data)))
-               goto out;
-       set_bit(SK_DATA, &svsk->sk_flags);
-       svc_sock_enqueue(svsk);
- out:
+               sk, sk->sk_user_data);
+       if (svsk) {
+               set_bit(SK_DATA, &svsk->sk_flags);
+               svc_sock_enqueue(svsk);
+       }
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
                wake_up_interruptible(sk->sk_sleep);
 }
@@ -1170,8 +1165,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
        while (rqstp->rq_arghi < pages) {
                struct page *p = alloc_page(GFP_KERNEL);
                if (!p) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ/2);
+                       schedule_timeout_uninterruptible(msecs_to_jiffies(500));
                        continue;
                }
                rqstp->rq_argpages[rqstp->rq_arghi++] = p;
index 09ffca54b3734136aa46afcfcbaeb279e80960d9..3bed09e625c0b52c8d52f762af6ee6dfd7c86cba 100644 (file)
@@ -370,6 +370,12 @@ handle_modversions(struct module *mod, struct elf_info *info,
                        /* Ignore register directives. */
                        if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
                                break;
+                       if (symname[0] == '.') {
+                               char *munged = strdup(symname);
+                               munged[0] = '_';
+                               munged[1] = toupper(munged[1]);
+                               symname = munged;
+                       }
                }
 #endif